Solving equations
Run Symbolica in your browser
Python examples with a Run button can be edited and run here. The first run loads Python, Symbolica, hover documentation, and code completion.
Expression.solve finds exact solutions to supported linear and nonlinear equations. Give it expressions that should equal zero, or equations constructed with .eq(), and specify the unknowns. Other symbols are parameters. Python == tests equality immediately; it does not construct an equation.
Domains and solution branches
The default domain is Complexes. Choose Reals, Rationals, or Integers to restrict the solutions:
from symbolica import *
x = S('x')
result = Expression.solve(x**2-2, [x], domain=Reals)
assert len(result) == 2
resultThe result is a SolutionSet. Each branch is a Solution, with assignments accessible as branch[x], dict(branch), or branch.as_dict(). Branch order is not guaranteed. Inspect all branches instead of assuming [0] is the only solution.
from symbolica import *
x, y = S('x', 'y')
result = Expression.solve([x+y-3, x-y-1], [x, y])
branch = result[0]
assert dict(branch) == {x: 2, y: 1}
branchFamilies with free variables
One branch can describe infinitely many points. len(result) counts branches, not points. A variable without an assignment is free; inspect it with free_variables():
from symbolica import *
x, y = S('x', 'y')
family = Expression.solve(x+y-1, [x, y])[0]
print('Free variables:', family.free_variables())
print('Dimension:', family.dimension())
familyUse branch.get(variable) if the variable might be free: it returns None when no assignment is present. Indexing a free variable raises KeyError. An empty assignment dictionary can represent a family in which every requested variable is free.
Parameters, conditions, and coverage
A parameter-dependent result may only apply under a condition. Read coverage, coverage_guard, and each branch’s conditions() before using its assignments:
from symbolica import *
a, x = S('a', 'x')
result = Expression.solve(a*x-1, [x])
print('Coverage:', result.coverage)
print('Coverage guard:', result.coverage_guard)
resultcoverage == 'complete' means the result covers the problem completely. For 'generic' coverage, the result applies where coverage_guard holds; excluded parameter values require a separate solve. Branch conditions can also constrain parameter values or domain membership, and are included in the displayed result.
For the example above, substituting a = 0 into the original equation gives a problem with no solutions:
from symbolica import *
a, x = S('a', 'x')
equation = a*x-1
exceptional = Expression.solve(equation.replace(a, 0), [x])
assert exceptional.is_empty()
exceptionalresult.is_empty() and bool(result) require an established answer: they can raise IncompleteCoverage when coverage or unresolved conditions prevent deciding emptiness. Use len(result) only to count the represented branches. A condition’s .eval() can return None when it cannot be decided.
Exact algebraic roots
Some exact solutions are represented by root(...) expressions rather than radicals. These remain exact and can be used in subsequent symbolic calculations or as generators of algebraic coefficient fields. Use .evaluate({}, decimal_digit_precision=30) for a numerical approximation.
The solver does not support every equation. UnsupportedProblem reports an unsupported problem; it must not be interpreted as an empty solution set. See the solver API for the full interface.