Symbolic Math (sympy_module)¶
The sympy_module standard library module provides symbolic mathematics predicates backed by SymPy. It accepts native Clausal terms directly — logic variables and arithmetic operators are converted to SymPy expressions automatically.
-import_from(sympy_module, [Diff, Solve, Simplify, sin, cos, inf])
Test("diff sin") <- (
Diff(sin(X), X, R),
R == cos(X)
)
Test("solve quadratic") <- (
Solve(X**2 - 4, X, S),
S == 2
)
The implementation lives in clausal/modules/sympy_module.py.
Import¶
-import_from(sympy_module, [Simplify, Expand, Factor, Solve, Diff, Integrate,
sin, cos, exp, log, sqrt, inf, pi])
Or via module import:
How it works¶
Term conversion¶
Clausal arithmetic terms (X**2 + 3*X + 1) are trees of Add, Mult, Pow nodes containing logic variables (Var). The module converts these to SymPy expression trees automatically:
| Clausal | SymPy |
|---|---|
X (unbound Var) |
Symbol('x') |
X**2 + 1 |
Symbol('x')**2 + 1 |
sin(X) |
sympy.sin(Symbol('x')) |
3 (int) |
Integer(3) |
Variables are auto-named alphabetically in discovery order: first Var → x, second → y, third → z, then a, b, c, ...
When the same Var appears in multiple arguments to a predicate, it maps to the same Symbol.
Symbolic equality via ==¶
Predicate results are wrapped in SymExpr, which overrides __eq__ to do symbolic comparison. This means Clausal's native == works for comparing symbolic results:
This handles term reordering (SymPy may internally reorder x + 1 to 1 + x) and alpha-equivalence (different variable names between the result and the expected value).
Numeric results (integers, floats) are collapsed to plain Python values, so Simplify(X - X, R), R == 0 works with ordinary equality.
Chaining¶
Results from one predicate can be fed directly into another:
The := operator also preserves symbolic equality through chains:
Predicates¶
Core calculus¶
Simplify/2¶
Simplify(Expr, Result) — simplify an expression:
Expand/2¶
Expand(Expr, Result) — algebraic expansion:
Factor/2¶
Factor(Expr, Result) — factorization:
# skip
Factor(X**2 - 1, R), R == (X - 1) * (X + 1)
Factor(X**2 + 5*X + 6, R), R == (X + 2) * (X + 3)
Solve/3¶
Solve(Equation, Var, Solution) — solve equation = 0 for Var. Nondeterministic — yields one solution per answer on backtracking:
# skip
Solve(2*X - 6, X, S), S == 3
Solve(X**2 - 4, X, S), S == 2 # first solution
Solve(X**2 - 4, X, S), S == -2 # second solution (on backtracking)
SolveAll/3¶
SolveAll(Equation, Var, Solutions) — deterministic, unifies Solutions with a list:
Diff/2, Diff/3¶
Diff(Expr, Result) — differentiate w.r.t. the single free variable.
Diff(Expr, Var, Result) — differentiate w.r.t. specified variable:
# skip
Diff(X**3, X, R), R == 3*X**2
Diff(sin(X), X, R), R == cos(X)
Diff(X*Y + X**2, X, R), R == Y + 2*X # partial derivative
Integrate/2, Integrate/3¶
Integrate(Expr, Result) — indefinite integral w.r.t. the single free variable.
Integrate(Expr, Var, Result) — w.r.t. specified variable:
Limit/4¶
Limit(Expr, Var, Point, Result) — limit as Var approaches Point:
Series/4, Series/5¶
Series(Expr, Var, N, Result) — Taylor series around Var=0 to N terms.
Series(Expr, Var, Point, N, Result) — around a specified point:
Algebra extras¶
Collect/3¶
Collect(Expr, Var, Result) — collect terms by powers of Var:
Cancel/2¶
Cancel(Expr, Result) — cancel common factors in a rational expression:
Apart/2, Apart/3¶
Apart(Expr, Result) — partial fraction decomposition:
Together/2¶
Together(Expr, Result) — combine fractions over a common denominator:
Degree/2, Degree/3¶
Degree(Expr, Result) / Degree(Expr, Var, Result) — polynomial degree:
Coeffs/3¶
Coeffs(Expr, Var, Result) — polynomial coefficients (highest degree first):
Roots/3¶
Roots(Equation, Var, Pair) — nondeterministic, yields (root, multiplicity) tuples:
Trigonometry¶
TrigSimp/2¶
TrigSimp(Expr, Result) — simplify trigonometric expressions:
ExpandTrig/2¶
ExpandTrig(Expr, Result) — expand trig identities:
Number theory¶
IsPrime/1¶
IsPrime(N) — succeeds if N is prime:
NextPrime/2¶
NextPrime(N, Result) — smallest prime greater than N:
FactorInt/2¶
FactorInt(N, Result) — prime factorization as {prime: exponent} dict:
Divisors/2¶
Divisors(N, Result) — sorted list of positive divisors:
Gcd/3, Lcm/3¶
Gcd(A, B, Result) / Lcm(A, B, Result) — symbolic GCD/LCM (works on both integers and polynomials):
Special functions¶
Sum/5¶
Sum(Expr, Var, Low, High, Result) — symbolic summation:
Product/5¶
Product(Expr, Var, Low, High, Result) — symbolic product:
Binomial/3¶
Binomial(N, K, Result) — binomial coefficient:
Printing¶
Latex/2¶
Latex(Expr, String) — convert expression to LaTeX:
Pretty/2¶
Pretty(Expr, String) — Unicode pretty-print:
MathML/2¶
MathML(Expr, String) — convert to MathML.
Substitution and inspection¶
Subs/3¶
Subs(Expr, Bindings, Result) — substitute values. Bindings is a dict or list of pairs:
Note: binding dicts with logic variable keys must be wrapped in ++() so the Vars are dereferenced.
FreeVars/2¶
FreeVars(Expr, Names) — sorted list of free symbol name strings:
Display and comparison¶
SymStr/2¶
SymStr(Expr, String) — convert expression to a readable string via SymPy:
SymEqual/2¶
SymEqual(A, B) — explicit symbolic equality (usually == suffices, but SymEqual is available for cases where both sides are raw Clausal terms):
Conversion¶
Sym/2¶
Sym(Name, Symbol) — create a named SymPy Symbol. Rarely needed since predicates auto-convert Vars, but useful when you want a specific display name:
ToSympy/2, FromSympy/2¶
Explicit conversion between Clausal terms and SymPy expressions. Rarely needed.
Math functions¶
Importable callables that produce Compound terms. These are converted to SymPy functions by the predicates:
| Function | SymPy equivalent |
|---|---|
sin, cos, tan |
sympy.sin, sympy.cos, sympy.tan |
asin, acos, atan |
sympy.asin, sympy.acos, sympy.atan |
exp, log, ln |
sympy.exp, sympy.log, sympy.log |
sqrt |
sympy.sqrt |
factorial |
sympy.factorial |
Abs |
sympy.Abs |
Usage:
# skip
-import_from(sympy_module, [Diff, sin, cos, exp, log, sqrt])
Diff(sin(X), X, R), R == cos(X)
Simplify(exp(log(X)), R), R == X
Constants¶
| Constant | Value | Note |
|---|---|---|
inf |
sympy.oo (infinity) |
SymPy uses oo; inf is more readable |
pi |
sympy.pi |
|
e |
sympy.E (Euler's number) |
Lowercase to avoid ALLCAPS logic variable conflict |
Usage:
Naming conventions¶
Function and constant names follow SymPy's conventions where possible:
- Math functions: lowercase (
sin,cos,exp,log,sqrt,factorial) — matches SymPy exactly Abs: capitalized — matches SymPy (they capitalized it becauseabsis a Python builtin)inf: instead of SymPy'soo— readabilitye: instead of SymPy'sE—Eis ALLCAPS so Clausal treats it as a logic variable- Predicates: capitalized (
Simplify,Diff,Solve) — Clausal convention
Test coverage
tests/test_sympy_module.py— 50 Python tests (conversion layer, predicates via API)tests/fixtures/sympy_basic.clausal— 32 tests (core calculus, solve, series, chaining, multivariate)tests/fixtures/sympy_algebra.clausal— 14 tests (collect, cancel, apart, together, degree, coeffs, roots)tests/fixtures/sympy_trig.clausal— 5 tests (trigsimp, expand_trig, exp/log)tests/fixtures/sympy_printing.clausal— 5 tests (latex, pretty)tests/fixtures/sympy_numtheory.clausal— 18 tests (isprime, nextprime, factorint, divisors, gcd, lcm)tests/fixtures/sympy_special.clausal— 8 tests (summation, product, binomial)
Total: 132 tests.