# Solver

The main symbolic solver for Symbolics.jl is `symbolic_solve`

. Symbolic solving means that it only uses symbolic (algebraic) methods and outputs exact solutions.

`Symbolics.symbolic_solve`

— Function`symbolic_solve(expr, x; dropmultiplicity=true, warns=true)`

`symbolic_solve`

is a function which attempts to solve input equations/expressions symbolically using various methods.

**Arguments**

expr: Could be a single univar expression in the form of a poly or multiple univar expressions or multiple multivar polys or a transcendental nonlinear function.

x: Could be a single variable or an array of variables which should be solved

dropmultiplicity (optional): Should the output be printed

`n`

times where`n`

is the number of occurrence of the root? Say we have`(x+1)^2`

, we then have 2 roots`x = -1`

, by default the output is`[-1]`

, If dropmultiplicity is inputted as false, then the output is`[-1, -1]`

.warns (optional): When invalid expressions or cases are inputted, should the solver warn you of such cases before returning nothing? if this is set to false, the solver returns nothing. By default, warns are set to true.

**Supported input**

The base solver (`symbolic_solve`

) has multiple solvers which chooses from depending on the the type of input (multiple/uni var and multiple/single expression) only after ensuring that the input is valid.

The expressions inputted can contain parameters, which are assumed to be transcendental. A parameter "a" is transcendental if there exists no polynomial P with rational coefficients such that P(a) = 0. Check the examples section.

Currently, `symbolic_solve`

supports

- Linear and polynomial equations (with parameters)
- Systems of linear and polynomials equations (without extra parameters, for now)
- Equations with transcendental functions (with parameters)

**Examples**

`solve_univar`

(uses factoring and analytic solutions up to degree 4)

The package `Nemo`

is needed in order to use `solve_univar`

as well as `solve_multipoly`

, so executing `using Nemo`

as you will see in the following examples is necessary; otherwise, the function will throw an error.

```
julia> using Symbolics, Nemo;
julia> @variables x a b;
julia> expr = expand((x + b)*(x^2 + 2x + 1)*(x^2 - a))
-a*b - a*x - 2a*b*x - 2a*(x^2) + b*(x^2) + x^3 - a*b*(x^2) - a*(x^3) + 2b*(x^3) + 2(x^4) + b*(x^4) + x^5
julia> symbolic_solve(expr, x)
4-element Vector{Any}:
-1
-b
(1//2)*√(4a)
(-1//2)*√(4a)
julia> symbolic_solve(expr, x, dropmultiplicity=false)
5-element Vector{Any}:
-1
-1
-b
(1//2)*√(4a)
(-1//2)*√(4a)
```

```
julia> symbolic_solve(x^2 + a*x + 6, x)
2-element Vector{SymbolicUtils.BasicSymbolic{Real}}:
(1//2)*(-a + √(-24 + a^2))
(1//2)*(-a - √(-24 + a^2))
```

```
julia> symbolic_solve(x^7 - 1, x)
2-element Vector{Any}:
roots_of((1//1) + x + x^2 + x^3 + x^4 + x^5 + x^6, x)
1
```

`solve_multivar`

(uses Groebner basis and `solve_univar`

to find roots)

Similar to `solve_univar`

, `Groebner`

is needed for `solve_multivar`

or to be fully functional.

```
julia> using Groebner
julia> @variables x y z
3-element Vector{Num}:
x
y
z
julia> eqs = [x+y^2+z, z*x*y, z+3x+y]
3-element Vector{Num}:
x + z + y^2
x*y*z
3x + y + z
julia> symbolic_solve(eqs, [x,y,z])
3-element Vector{Any}:
Dict{Num, Any}(z => 0, y => 1//3, x => -1//9)
Dict{Num, Any}(z => 0, y => 0, x => 0)
Dict{Num, Any}(z => -1, y => 1, x => 0)
```

If `Nemo`

or `Groebner`

are not imported when needed, the solver throws an error.

```
julia> using Symbolics
julia> @variables x y z;
julia> symbolic_solve(x+1, x)
ERROR: "Nemo is required. Execute `using Nemo` to enable this functionality."
julia> symbolic_solve([x+1, y], [x, y])
ERROR: "Groebner bases engine is required. Execute `using Groebner` to enable this functionality."
```

`solve_multipoly`

(uses GCD between the input polys)

```
julia> symbolic_solve([x-1, x^3 - 1, x^2 - 1, (x-1)^20], x)
1-element Vector{BigInt}:
1
```

`ia_solve`

(solving by isolation and attraction)

```
julia> symbolic_solve(2^(x+1) + 5^(x+3), x)
1-element Vector{SymbolicUtils.BasicSymbolic{Real}}:
(-slog(2) - log(complex(-1)) + 3slog(5)) / (slog(2) - slog(5))
```

```
julia> symbolic_solve(log(x+1)+log(x-1), x)
2-element Vector{SymbolicUtils.BasicSymbolic{BigFloat}}:
(1//2)*√(8.0)
(-1//2)*√(8.0)
```

```
julia> symbolic_solve(a*x^b + c, x)
((-c)^(1 / b)) / (a^(1 / b))
```

**Evaluating output (converting to floats)**

If you want to evaluate the exact expressions found by `symbolic_solve`

, you can do the following:

```
julia> roots = symbolic_solve(2^(x+1) + 5^(x+3), x)
1-element Vector{SymbolicUtils.BasicSymbolic{Real}}:
(-slog(2) - log(complex(-1)) + 3slog(5)) / (slog(2) - slog(5))
julia> Symbolics.symbolic_to_float.(roots)
1-element Vector{Complex{BigFloat}}:
-4.512941594732059759689023145584186058252768936052415430071569066192919491762214 + 3.428598090438030380369414618548038962770087500755160535832807433942464545729382im
```

One other symbolic solver is `symbolic_linear_solve`

which is limited compared to `symbolic_solve`

as it only solves linear equations.

`Symbolics.symbolic_linear_solve`

— Function```
symbolic_linear_solve(eq, var; simplify, check) -> Any
```

Solve equation(s) `eqs`

for a set of variables `vars`

.

Assumes `length(eqs) == length(vars)`

Currently only works if all equations are linear. `check`

if the expr is linear w.r.t `vars`

.

**Examples**

```
julia> @variables x y
2-element Vector{Num}:
x
y
julia> Symbolics.symbolic_linear_solve(x + y ~ 0, x)
-y
julia> Symbolics.symbolic_linear_solve([x + y ~ 0, x - y ~ 2], [x, y])
2-element Vector{Float64}:
1.0
-1.0
```

`symbolic_solve`

only supports symbolic, i.e. non-floating point computations, and thus prefers equations where the coefficients are integer, rational, or symbolic. Floating point coefficients are transformed into rational values and BigInt values are used internally with a potential performance loss, and thus it is recommended that this functionality is only used with floating point values if necessary. In contrast, `symbolic_linear_solve`

directly handles floating point values using standard factorizations.

### More technical details and examples

#### Technical details

The `symbolic_solve`

function uses 4 hidden solvers in order to solve the user's input. Its base, `solve_univar`

, uses analytic solutions up to polynomials of degree 4 and factoring as its method for solving univariate polynomials. The function's `solve_multipoly`

uses GCD on the input polynomials then throws passes the result to `solve_univar`

. The function's `solve_multivar`

uses Groebner basis and a separating form in order to create linear equations in the input variables and a single high degree equation in the separating variable ^{[1]}. Each equation resulting from the basis is then passed to `solve_univar`

. We can see that essentially, `solve_univar`

is the building block of `symbolic_solve`

. If the input is not a valid polynomial and can not be solved by the algorithm above, `symbolic_solve`

passes it to `ia_solve`

, which attempts solving by attraction and isolation ^{[2]}. This only works when the input is a single expression and the user wants the answer in terms of a single variable. Say `log(x) - a == 0`

gives us `[e^a]`

.

#### Nice examples

```
using Symbolics, Nemo;
@variables x;
Symbolics.symbolic_solve(9^x + 3^x ~ 8, x)
```

```
2-element Vector{SymbolicUtils.BasicSymbolic{Real}}:
slog(-(1//2) + (1//2)*√(33)) / slog(3)
slog(-(1//2) - (1//2)*√(33)) / slog(3)
```

```
@variables x y z;
Symbolics.symbolic_linear_solve(2//1*x + y - 2//1*z ~ 9//1*x, 1//1*x)
```

\[ \begin{equation} \frac{1}{7} \left( y - 2 z \right) \end{equation} \]

```
using Groebner;
@variables x y z;
eqs = [x^2 + y + z - 1, x + y^2 + z - 1, x + y + z^2 - 1]
Symbolics.symbolic_solve(eqs, [x,y,z])
```

```
5-element Vector{Any}:
Dict{Num, Any}(z => 1, y => 0, x => 0)
Dict{Num, Any}(z => -1 + √(2), y => -1 + √(2), x => -1 + √(2))
Dict{Num, Any}(z => -1 - √(2), y => -1 - √(2), x => -1 - √(2))
Dict{Num, Any}(z => 0, y => 0, x => 1)
Dict{Num, Any}(z => 0, y => 1, x => 0)
```

### Feature completeness

- [x] Linear and polynomial equations
- [x] Systems of linear and polynomial equations
- [x] Some transcendental functions
- [x] Systems of linear equations with parameters (via
`symbolic_linear_solve`

) - [ ] Equations with radicals
- [x] Systems of polynomial equations with parameters and positive dimensional systems
- [ ] Inequalities

### Expressions we can not solve (but aim to)

```
# Mathematica
In[1]:= Reduce[x^2 - x - 6 > 0, x]
Out[1]= x < -2 || x > 3
In[2]:= Reduce[x+a > 0, x]
Out[2]= a \[Element] Reals && x > -a
In[3]:= Solve[x^(x) + 3 == 0, x]
Out[3]= {{x -> (I \[Pi] + Log[3])/ProductLog[I \[Pi] + Log[3]]}}
```