Up | Next | Prev | PrevTail | Tail |
solve
is an operator for solving one or more simultaneous algebraic equations. It is
used with the syntax:
solve
(\(\langle \)exprn:algebraic\(\rangle \)[, \(\langle \)var:kernel\(\rangle \)\(\ \mid \ \), \(\langle \)varlist:list of kernels\(\rangle \)]) : list.exprn
is of the form \(\langle \)expression\(\rangle \) or {
\(\langle \)expression1\(\rangle \),\(\langle \)expression2\(\rangle \), …}
. Each expression is an
algebraic equation, or is the difference of the two sides of the equation. The second
argument is either a kernel or a list of kernels representing the unknowns in the system.
This argument may be omitted if the number of distinct, non-constant, top-level kernels
equals the number of unknowns, in which case these kernels are presumed to be the
unknowns and a message is printed:
solve(x^2 - 1); -> Unknown: x {x=1,x=-1}
For one equation, solve
recursively uses factorization and decomposition,
together with the known inverses of log
, sin
, cos
, ^
, acos
, asin
, and
linear, quadratic, cubic, quartic, or binomial factors. Solutions of equations
built with exponentials or logarithms are often expressed in terms of Lambert’s
W function. This function is (partially) implemented in the special functions
package.
Linear equations are solved by the multi-step elimination method due to Bareiss, unless
the switch cramer
is on, in which case Cramer’s method is used. The Bareiss method is
usually more efficient unless the system is large and dense.
Non-linear equations are solved using the Groebner basis package (chapter 20.26). Users should note that this can be quite a time consuming process.
Examples:
solve(log(sin(x+3))^5 = 8,x); solve(a*log(sin(x+3))^5 - b, sin(x+3)); solve({a*x+y=3,y=-2},{x,y});
solve
returns a list of solutions. If there is one unknown, each solution is an equation
for the unknown. If a complete solution was found, the unknown will appear by itself on
the left-hand side of the equation. On the other hand, if the solve package could not find a
solution, the “solution” will be an equation for the unknown in terms of the operator
root_of
. If there are several unknowns, each solution will be a list of equations for the
unknowns. For example,
solve(x^2=1,x); -> {x=-1,x=1} solve(x^7-x^6+x^2=1,x) 6 -> {x=root_of(x_ + x_ + 1,x_,tag_1),x=1} solve({x+3y=7,y-x=1},{x,y}) -> {{x=1,y=2}}.
The TAG argument is used to uniquely identify those particular solutions. Solution
multiplicities are stored in the global variable root_multiplicities
rather than
the solution list. The value of this variable is a list of the multiplicities of the solutions for
the last call of solve
. For example,
solve(x^2=2x-1,x); root_multiplicities;
gives the results
{x=1} {2}
If you want the multiplicities explicitly displayed, the switch multiplicities
can
be turned on. For example
on multiplicities; solve(x^2=2x-1,x);
yields the result
{x=1,x=1}
When solve
cannot find a solution to an equation, it normally returns an equation for
the relevant indeterminates in terms of the operator ROOT_OF
. For example, the
expression
solve(cos(x) + log(x),x);
returns the result
{x=root_of(cos(x_) + log(x_),x_,tag_1)} .
An expression with a top-level root_of
operator is implicitly a list with an unknown
number of elements (since we don’t always know how many solutions an equation has).
If a substitution is made into such an expression, closed form solutions can emerge. If
this occurs, the root_of construct is replaced by an operator one_of
. At this point it
is of course possible to transform the result of the original solve
operator expression
into a standard solve
solution. To effect this, the operator expand_cases
can be
used.
The following example shows the use of these facilities:
solve(-a*x^3+a*x^2+x^4-x^3-4*x^2+4,x); 2 3 {x=root_of(a*x_ - x_ + 4*x_ + 4,x_,tag_2),x=1} sub(a=-1,ws); {x=one_of({2,-1,-2},tag_2),x=1} expand_cases ws; {x=2,x=-1,x=-2,x=1}
Since roots of cubics and quartics can often be very messy, a switch fullroots
is
available, that, when off (the default), will prevent the production of a result in closed
form. The root_of
construct will be used in this case instead.
In constructing the solutions of cubics and quartics, trigonometrical forms are used
where appropriate. This option is under the control of a switch trigform
, which is
normally on.
The following example illustrates the use of these facilities:
let xx = solve(x^3+x+1,x); xx; 3 {x=root_of(x_ + x_ + 1,x_)} on fullroots; xx; - sqrt(31)*i atan(---------------) 3*sqrt(3) {x=(i*(sqrt(3)*sin(-----------------------) 3 - sqrt(31)*i atan(---------------) 3*sqrt(3) - cos(-----------------------)))/sqrt(3), 3 - sqrt(31)*i atan(---------------) 3*sqrt(3) x=( - i*(sqrt(3)*sin(-----------------------) 3 - sqrt(31)*i atan(---------------) 3*sqrt(3) + cos(-----------------------)))/sqrt( 3 3), - sqrt(31)*i atan(---------------) 3*sqrt(3) 2*cos(-----------------------)*i 3 x=----------------------------------} sqrt(3) off trigform; xx; 2/3 {x=( - (sqrt(31) - 3*sqrt(3)) *sqrt(3)*i 2/3 2/3 - (sqrt(31) - 3*sqrt(3)) - 2 *sqrt(3)*i 2/3 1/3 1/3 + 2 )/(2*(sqrt(31) - 3*sqrt(3)) *6 1/6 *3 ), 2/3 x=((sqrt(31) - 3*sqrt(3)) *sqrt(3)*i 2/3 2/3 - (sqrt(31) - 3*sqrt(3)) + 2 *sqrt(3)*i 2/3 1/3 1/3 + 2 )/(2*(sqrt(31) - 3*sqrt(3)) *6 1/6 *3 ), 2/3 2/3 (sqrt(31) - 3*sqrt(3)) - 2 x=-------------------------------------} 1/3 1/3 1/6 (sqrt(31) - 3*sqrt(3)) *6 *3
If solvesingular
is on (the default setting), degenerate systems such as x+y=0
,
2x+2y=0
will be solved by introducing appropriate arbitrary constants. The consistent
singular equation 0=0 or equations involving functions with multiple inverses may
introduce unique new indeterminant kernels arbcomplex(j)
, or arbint(j)
,
(\(j\)=1,2,...), representing arbitrary complex or integer numbers respectively. To
automatically select the principal branches, do off allbranch
. To avoid the
introduction of new indeterminant kernels do off arbvars
– then no equations are
generated for the free variables and their original names are used to express the
solution forms. To suppress solutions of consistent singular equations do off
solvesingular
.
To incorporate additional inverse functions do, for example:
put(’sinh,’inverse,’asinh); put(’asinh,’inverse,’sinh);
together with any desired simplification rules such as
for all x let sinh(asinh(x))=x, asinh(sinh(x))=x;
For completeness, functions with non-unique inverses should be treated as ^
, sin
, and
cos
are in the solve
module source.
Arguments of asin
and acos
are not checked to ensure that the absolute value of the
real part does not exceed 1; and arguments of log
are not checked to ensure that the
absolute value of the imaginary part does not exceed \(\pi \); but checks (perhaps involving user
response for non-numerical arguments) could be introduced using let
statements for
these operators.
The proper design of a variable sequence supplied as a second argument to
solve
is important for the structure of the solution of an equation system.
Any unknown in the system not in this list is considered totally free. E.g. the
call
solve({x=2*z,z=2*y},{z});
produces an empty list as a result because there is no function \(z=z(x,y)\) which fulfills both
equations for arbitrary \(x\) and \(y\) values. In such a case the share variable requirements
displays a set of restrictions for the parameters of the system:
requirements; {x - 4*y}
The non-existence of a formal solution is caused by a contradiction which
disappears only if the parameters of the initial system are set such that all
members of the requirements list take the value zero. For a linear system the
set is complete: a solution of the requirements list makes the initial system
solvable. E.g. in the above case a substitution \(x=4y\) makes the equation set consistent.
For a non-linear system only one inconsistency is detected. If such a system
has more than one inconsistency, you must reduce them one after the other.
3 The
set shows you also the dependency among the parameters: here one of \(x\) and \(y\) is free and a
formal solution of the system can be computed by adding it to the variable
list of solve
. The requirement set is not unique – there may be other such
sets.
A system with parameters may have a formal solution, e.g.
solve({x=a*z+1,0=b*z-y},{z,x}); y a*y + b {{z=---,x=---------}} b b
which is not valid for all possible values of the parameters. The variable
assumptions
contains then a list of restrictions: the solutions are valid only as long
as none of these expressions vanishes. Any zero of one of them represents a
special case that is not covered by the formal solution. In the above case the value
is
assumptions; {b}
which excludes formally the case \(b=0\); obviously this special parameter value makes the system singular. The set of assumptions is complete for both, linear and non–linear systems.
solve
rearranges the variable sequence to reduce the (expected) computing time.
This behavior is controlled by the switch varopt
, which is on by default.
If it is turned off, the supplied variable sequence is used or the system kernel
ordering is taken if the variable list is omitted. The effect is demonstrated by an
example:
s:= {y^3+3x=0,x^2+y^2=1}; solve(s,{y,x}); 6 2 {{y=root_of(y_ + 9*y_ - 9,y_), 3 - y x=-------}} 3 off varopt; solve(s,{y,x}); 6 4 2 {{x=root_of(x_ - 3*x_ + 12*x_ - 1,x_), 4 2 x*( - x + 2*x - 10) y=-----------------------}} 3
In the first case, solve
forms the solution as a set of pairs \((y_i,x(y_i))\) because the degree of \(x\) is
higher – such a rearrangement makes the internal computation of the Gröbner basis
generally faster. For the second case the explicitly given variable sequence is used such
that the solution has now the form \((x_i,y(x_i))\). Controlling the variable sequence is especially
important if the system has one or more free variables. As an alternative to turning off
varopt
, a partial dependency among the variables can be declared using the depend
statement: solve
then rearranges the variable sequence but keeps any variable ahead of
those on which it depends.
on varopt; s:={a^3+b,b^2+c}$ solve(s,{a,b,c}); 3 6 {{a=arbcomplex(1),b= - a ,c= - a }} depend a,c; depend b,c; solve(s,{a,b,c}); {{c=arbcomplex(2), 6 a=root_of(a_ + c,a_), 3 b= - a }}
Here solve
is forced to put \(c\) after \(a\) and after \(b\), but there is no obstacle to interchanging \(a\)
and \(b\).
Up | Next | Prev | PrevTail | Front |