The Blackbox Solver¶
A blackbox solver runs with default settings and values of the tolerances, executing a selection of algorithms which has shown to work for a large collection of problems. As to what the solver computes, two different types of solvers are available
to approximate all isolated solutions, typically of systems with as many equations as unknows; and
to compute a numerical irreducible decomposition of the entire solution set, which includes the isolated solution points, but also all positive dimensional sets (curves and surfaces), factored into irreducible components.
Because the output of the two types is so vastly different and because the complexity of a numerical irreducible decomposition is much higher than computing only the isolated solutions, the user must decide in advance which solver function to call.
approximating all isolated solutions¶
The input to the solver is a list of strings,
with symbolic representations of the polynomials in the system.
The ;
at the end signifies the = 0
of the equations.
polynomials = ['x^3 + 2*x*y - x^2;', 'x + y - x^3;']
To call the blackbox solver, we import the solve
function
from the solver
module.
from phcpy.solver import solve
solutions = solve(polynomials)
The output of solve
is also a list of strings.
for (idx, sol) in enumerate(solutions):
print('Solution', idx+1, ':')
print(sol)
has as output
Solution 1 :
t : 0.00000000000000E+00 0.00000000000000E+00
m : 2
the solution for t :
x : 0.00000000000000E+00 0.00000000000000E+00
y : 0.00000000000000E+00 0.00000000000000E+00
== err : 7.124E-17 = rco : 0.000E+00 = res : 0.000E+00 =
Solution 2 :
t : 1.00000000000000E+00 0.00000000000000E+00
m : 1
the solution for t :
x : 1.00000000000000E+00 0.00000000000000E+00
y : 0.00000000000000E+00 0.00000000000000E+00
== err : 2.100E-74 = rco : 5.348E-01 = res : 0.000E+00 =
Solution 3 :
t : 1.00000000000000E+00 0.00000000000000E+00
m : 1
the solution for t :
x : -1.50000000000000E+00 0.00000000000000E+00
y : -1.87500000000000E+00 3.30053725596684E-238
== err : 6.747E-80 = rco : 1.220E-01 = res : 1.073E-237 =
How did this actually work?
We can ask to see more output of the solver,
giving a value to the verbose level parameter,
the vrblvl
as argument to the solver.
solutions = solve(polynomials, vrblvl=1)
shows the following
in solve, tasks : 0, mvfocus : 0, precision : d
the polynomials on input :
x^3 + 2*x*y - x^2;
x + y - x^3;
nbr : 4, roco :
total degree : 9
2-homogeneous Bezout number : 6
with with partition : { x }{ y }
general linear-product Bezout number : 5
based on the set structure :
{ x }{ x y }{ x }
{ x y }{ x }{ x }
mixed volume : 2
stable mixed volume : 4
The roco
is an abbreviation of root count.
A root count is an upper bound on the number of solutions.
In the example, the two input polynomials are cubics.
Therefore, the largest number of isolated solutions equals nine,
the product of the degrees of the polynomials.
However, not all monomials of degree three or less that could
appear with nonzero coefficient are present.
The numbers 6
and 5
are better bounds computed on the degrees.
Mixed volumes are generically sharp bounds for the number
of isolated solutions with all coordinates different from zero.
As in the example, there is one double root at (0, 0)
,
which is counted by the stable mixed volume.
If the coefficients of the polynomials are sufficiently independent from each other, then the number of isolated solutions counted with multiplicity will match one of the computed root counts.
options of the solve function¶
The blackbox solver runs with default values,
which can be changed when calling the solve
function.
In addition to the list of polynomials, there are six parameters with default values:
tasks
equals the number of the threads and is by default set to zero. The solutions can approximated independently to each other using p threads could in the best case speed up the solver by a factor of p.mvfocus
is a flag to apply only mixed volumes as root counts, if set to one. By default, this flag is set to zero and the solver will compute all bounds based on the degrees which may be too time consuming for sparse polynomial systems.precision
is by default double (d
). Other values aredd
for double double andqd
for quad double. While running in higher precision leads to more accurate results, the computational overhead can be significant. The overhead may be compensated (in part) by multithreading.checkin
is the option to run some basic checks on the input. By defaultTrue
, setting it toFalse
is okay if the input polynomials are automatically generated in the correct way.dictionary_output
is by defaultFalse
and a list of strings is returned. IfTrue
, then the output is a list of dictionaries, often convenient for processing.vrblvl
is the verbose level parameter to make the blackbox solver less black when set to higher values.
Of course, then there is always the help(solve)
:
help(solve)
which shows the documentation string of the function.
When changing the default values, consider the following.
The number of threads should never be set to a value higher than the number of available cores on the system. To find out the number of available cores, do the following:
from phcpy.dimension import get_core_count get_core_count()
So, use up to the value returned by
phcpy.dimension.get_core_count()
as the value to assign to the parametertasks
.The focus on mixed volumes (in the option
mvfocus
) is automatically applied when the polynomials have negative exponents.When computing in higher precision, keep in mind that also the coefficients of the polynomials then must also be evaluated in higher precision. Consider
1/3
in double precision:1/3
which evaluates to
0.3333333333333333
which is of course not equal to the rational number
1/3
.One of the checks done by default (
checkin=True
) is whether the number of polynomials in the list equals the number of unknowns. At this stage, if the syntax of the polynomial is incorrect, an error message will be printed as well.If
dictionary_output
is wanted after a run, then it can be computed afterwards, thesolve()
should not be called again, but can be computed with thestrsol2dict()
of thesolutions
module. For example:from phcpy.solutions import strsol2dict strsol2dict(solutions[0])
shows the output
{'t': 0j, 'm': 2, 'err': 1.17e-16, 'rco': 0.0, 'res': 0.0, 'x': 0j, 'y': 0j}
Higher values of the verbose level
vrblvl
are mainly meant for debugging purposes as it should procedures are executed. As the solving of a polynomial system could take a long time, the user can see which procedures are currently running if the solver appears to be stuck.