A high-performance C++ DLL exposable as a Python package that solves systems of equations defined using Excel-style formulas and DP-syntax variable declarations.
| Capability | Details |
|---|---|
| Variable syntax | DP(name) where name ≤ 20 chars |
| Variable types | NUMERIC, BOOLEAN, DATE, TEXT |
| Excel anchoring | Each variable maps to a cell/range e.g. Sheet1!B2 |
| Formula engine | 40+ Excel-compatible functions (IF, SUM, SQRT, ROUND, MAX, MIN, AND, OR, CONCATENATE, DATE, YEAR…) |
| Linear solver | Eigen FullPivLU / BDC SVD (exact + least-squares) |
| Non-linear solver | Levenberg-Marquardt with numerical Jacobian + random restarts |
| Fallback | Adaptive gradient descent |
| Propagation | Topological constraint propagation pins assigned variables before solving |
| LOOCV | Leave-One-Out Cross-Validation identifies conflicting constraints |
| Excel output | Results, Solver_Summary, Solver_Constraints, LOOCV_Diagnosis sheets |
| Python API | Full pybind11 bindings — import equationsolver as es |
sudo apt install g++ cmake libeigen3-dev
pip install pybind11 numpy openpyxlmkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)The Python extension equationsolver.cpython-*.so and shared library libequationsolver_dll.so are generated in build/.
pip install . --no-build-isolationOne variable per line. Comments start with #.
DP(name) TYPE ExcelRef [optional_bounds]
| Field | Description | Example |
|---|---|---|
DP(name) |
Variable name, ≤ 20 chars | DP(money_spent) |
TYPE |
NUMERIC / BOOLEAN / DATE / TEXT | NUMERIC |
ExcelRef |
Cell or range in workbook | Sheet1!B2 or Finance!A1:A100 |
[lo,hi] |
Optional numeric bounds | [0, 1000000] |
# Financial variables
DP(revenue) NUMERIC Finance!B2 [0, 10000000]
DP(cost_of_goods) NUMERIC Finance!B3 [0, 10000000]
DP(gross_profit) NUMERIC Finance!B4
DP(tax_rate) NUMERIC Finance!B7 [0.0, 0.50]
DP(net_income) NUMERIC Finance!B9
DP(is_profitable) BOOLEAN Finance!B10
DP(report_date) DATE Finance!B12
DP(currency) TEXT Finance!B11
One formula per line. Identical to Excel formula syntax.
| Operator | Meaning |
|---|---|
= |
Equality constraint |
<= , >= |
Inequality constraints |
< , > |
Strict inequality |
<> |
Not-equal (used as expression) |
ABS, SQRT, POW, EXP, LN, LOG, ROUND, ROUNDDOWN, ROUNDUP, FLOOR, CEILING, MOD, MAX, MIN, SUM, AVERAGE, COUNT, INT, TRUNC, SIGN, SIN, COS, TAN, ASIN, ACOS, ATAN, ATAN2, DEGREES, RADIANS, PI, RAND, RANDBETWEEN, IF, AND, OR, NOT, ISNUMBER, ISBLANK, ISERROR, CONCATENATE, CONCAT, LEFT, RIGHT, MID, LEN, TRIM, UPPER, LOWER, VALUE, TEXT, TODAY, DATE, YEAR, MONTH, DAY
# Accounting identities
DP(gross_profit) = DP(revenue) - DP(cost_of_goods)
DP(net_income) = DP(gross_profit) * (1 - DP(tax_rate))
DP(is_profitable) = IF(DP(net_income) > 0, TRUE, FALSE)
# Business rules
DP(cost_of_goods) = 0.45 * DP(revenue)
DP(tax_rate) = 0.28
DP(revenue) = 1000000
# Inequality constraints
DP(net_income) >= 0
DP(tax_rate) <= 0.5
import equationsolver as es
# Create solver
solver = es.Solver()
# Load inputs
solver.load_variables_from_file("variables.txt")
solver.load_constraints_from_file("constraints.txt")
# Or inline
solver.load_variables_from_text("""
DP(x) NUMERIC Sheet1!A1
DP(y) NUMERIC Sheet1!B1
""")
solver.load_constraints_from_text("""
DP(x)^2 + DP(y)^2 = 25
DP(x) + DP(y) = 7
""")
# Optionally seed initial guesses
solver.set_initial_value("x", 3.0)
solver.set_initial_value("y", 4.0)
# Tune solver (optional)
solver.max_iterations = 5000
solver.tolerance = 1e-9
solver.restarts = 15
solver.verbose = True
# Solve
message = solver.solve()
print(solver.get_status()) # "OPTIMAL" | "PARTIAL" | "INFEASIBLE" | "ERROR"
print(solver.get_residual_norm()) # float
print(solver.get_variable_values()) # dict {name: value}
# Constraint report
for c in solver.get_constraint_report():
print(c['id'], c['formula'], c['satisfied'], c['residual'])
# Write Excel output
solver.write_excel("output.xlsx")if solver.get_status() in ("PARTIAL", "INFEASIBLE"):
report = solver.get_loocv_report()
print("Conflicting constraint IDs:", report['conflicting'])
print("Diagnosis:", report['diagnosis'])
solver.write_excel("output.xlsx") # includes LOOCV_Diagnosis sheetInput: Variables V, Constraints C
Phase 0 — Topological Propagation
While any DP(x) = <fully-resolved-expr> exists:
Pin x = eval(expr), remove from free set
Phase 1 — Classify System
If all formulas are linear → Eigen SVD/LU
Else → Levenberg-Marquardt (nonlinear)
Phase 2 — Iterative Solve (with random restarts)
Newton-LM:
Compute numerical Jacobian J (O(n) perturbations)
Solve (JᵀJ + λI) Δx = -Jᵀr (Levenberg-Marquardt)
Update x, adapt λ based on gain ratio
If Newton-LM fails → gradient descent fallback
Phase 3 — Verification
Check all constraints: |lhs - rhs| < tolerance
Phase 4 — LOOCV (only if Phase 3 fails)
For each constraint i:
Solve system with constraint i removed
If solvable → constraint i is conflicting
Pairwise removal to find minimal conflict set
Write diagnosis to Excel LOOCV_Diagnosis sheet
| Sheet | Contents |
|---|---|
<original sheets> |
Solved values written to their anchored cells |
Solver_Summary |
Variable name / ref / type / solved value |
Solver_Constraints |
ID / formula / satisfied (green/red) / residual |
LOOCV_Diagnosis |
Conflicting vs satisfied constraints (only on failure) |
solverlib/
├── include/
│ ├── variable.hpp — Variable & Constraint type definitions
│ ├── expr_parser.hpp — Excel formula AST & evaluator
│ ├── input_parser.hpp — DP syntax & formula file parsers
│ ├── solver_engine.hpp — SolverEngine, LOOCV, SolveResult
│ └── excel_writer.hpp — openpyxl-backed Excel output
├── src/
│ ├── expr_parser.cpp — Recursive-descent parser + 40+ builtins
│ ├── input_parser.cpp — Variable and constraint parsers
│ ├── solver_engine.cpp — Newton-LM, linear, GD, LOOCV
│ └── excel_writer.cpp — xlsx generation via Python subprocess
├── python/
│ └── bindings.cpp — pybind11 module definition
├── tests/
│ └── demo.py — 8 test suites + simulated data generation
├── CMakeLists.txt
├── setup.py
└── README.md
MIT