โป๏ธ Evaluation of cyclic-\(n\) polynomialsยถ
Bertini is software for algebraic geometry. This means we work with systems of polynomials, a critical component of which is system and function evaluation.
Bertini2 allows us to set up many kinds of functions, and thus systems, by exploting operator overloading.
Make some symbolsยถ
Letโs start by making some variables, programmatically [1].
import bertini
import numpy
num_vars = 10
x = [None] * num_vars # preallocate the list
for ii in range(num_vars):
x[ii] = bertini.Variable('x' + str(ii))
Huzzah, we have num_vars variables! This was hard to do in Bertini 1โs classic style input files. Now we can do it directly! ๐ฏ
Write a function to produce the cyclic \(n\) polynomials [DKK03].
def cyclic(vars):
n = len(vars)
f = [None] * len(vars)
y = []
for ii in range(2):
for x in vars:
y.append(x)
for ii in range(n-1):
f[ii] = numpy.sum( [numpy.prod(y[jj:jj+ii+1]) for jj in range(n)] )
# the last one is minus one
f[-1] = numpy.prod(vars)-1
return f
Now we will make a System, and put the cyclic polynomials into it.
sys = bertini.System()
for f in cyclic(x):
sys.add_function(f)
print(sys) # long screen output, i know
...
10 functions:
f_0 = x0+x1+x2+x3+x4+x5+x6+x7+x8+x9
...
f_9 = x0*x1*x2*x3*x4*x5*x6*x7*x8*x9-1
...
We also need to associate the variables with the system. Unassociated variables are left unknown, and retain their value until elsewhere set.
vg = bertini.VariableGroup()
for var in x:
vg.append(var)
sys.add_variable_group(vg)
Letโs simplify this. It will modify elements of the constructed function tree, even those held externally โ Bertini uses shared pointers under the hood, so pay attention to where you re-use parts of your functions, because later modification of them without deep cloning will cause โฆ modification elsewhere, too.
bertini.system.simplify(sys)
Now, letโs evaluate it at the origin โ all zeroโs (0 is the default value for multiprecision complex numbers in Bertini2). The returned value should be all zeroโs except the last entry, which should be -1.
s = numpy.zeros((10,), dtype=bertini.multiprec.complex_mp)
result = sys.eval(s)
assert complex(result[-1]) == -1 # last cyclic function is (prod x) - 1
assert all(complex(v) == 0 for v in result[:-1]) # the rest vanish at the origin
Yay, all zeros, except the last one is -1. Huzzah.
Letโs change the values of our vector, and re-evaluate.
for ii in range(num_vars):
s[ii] = bertini.multiprec.complex_mp(ii)
result = sys.eval(s)
There is much more one can do, too! Please write the authors, particularly Silviana, for more.
Complete exampleยถ
The whole tutorial as one runnable script โ assemble nothing, just run it:
"""Bertini 2 tutorial: Evaluation of cyclic-n polynomials.
Assembles all code fragments from the tutorial into one runnable program.
Run: python evaluation_cyclic.py
"""
import bertini
import numpy
def make_symbols(num_vars=10):
"""Programmatically create num_vars variables x0..x{n-1}."""
x = [None] * num_vars # preallocate the list
for ii in range(num_vars):
x[ii] = bertini.Variable('x' + str(ii))
return x
def cyclic(vars):
"""Produce the cyclic-n polynomials from a list of variables."""
n = len(vars)
f = [None] * len(vars)
y = []
for ii in range(2):
for x in vars:
y.append(x)
for ii in range(n - 1):
f[ii] = numpy.sum([numpy.prod(y[jj:jj + ii + 1]) for jj in range(n)])
# the last one is minus one
f[-1] = numpy.prod(vars) - 1
return f
def build_system(x):
"""Make a System and put the cyclic polynomials into it."""
sys = bertini.System()
for f in cyclic(x):
sys.add_function(f)
print(sys) # long screen output, i know
return sys
def associate_variables(sys, x):
"""Associate the variables with the system via a VariableGroup."""
vg = bertini.VariableGroup()
for var in x:
vg.append(var)
sys.add_variable_group(vg)
def simplify_system(sys):
"""Simplify the system in place (modifies the shared function tree)."""
bertini.system.simplify(sys)
def evaluate_at_origin(sys):
"""Evaluate at the origin; all zeros except the last entry, which is -1."""
s = numpy.zeros((10,), dtype=bertini.multiprec.complex_mp)
result = sys.eval(s)
assert complex(result[-1]) == -1 # last cyclic function is (prod x) - 1
assert all(complex(v) == 0 for v in result[:-1]) # the rest vanish at the origin
return s
def evaluate_at_new_point(sys, s, num_vars=10):
"""Change the values of the vector and re-evaluate."""
for ii in range(num_vars):
s[ii] = bertini.multiprec.complex_mp(ii)
result = sys.eval(s)
return result
def main():
num_vars = 10
x = make_symbols(num_vars)
sys = build_system(x)
associate_variables(sys, x)
simplify_system(sys)
s = evaluate_at_origin(sys)
evaluate_at_new_point(sys, s, num_vars)
if __name__ == '__main__':
main()