MATLAB Examples

# The first run

Below we show how BertiniLab can be used to set up and solve a simple example, the system of equations

$x^2-1 = 0$

$y^2-4 =0.$

The solution set consists of the four points:

$(\pm 1,\pm 2).$

## Defining the problem

The main input for Bertini is the input file. A simple example of such an input file is shown below:

variable_group x,y;
function f,g;

f = x^2 - 1;
g = y^2 - 4;
END;


Bertini is then run with the command

bertini input


A BertiniLab equivalent to the input file is shown below:

polysyms x y f = x^2 - 1; g = y^2 - 4; poly_system = BertiniLab('variable_group',[x; y],'function_def',[f; g]); 

The object poly_system looks like this:

disp(poly_system) 
 BertiniLab with properties: config: [0x0 struct] function_def: [2x1 polysym] variable: [] variable_group: [2x1 polysym] hom_variable_group: [] pathvariable: [] random: [] random_real: [] definedSubfunction: [] parameter: [0x2 polysym] constant: [0x2 polysym] subfunction: [0x2 polysym] starting_points: [0x0 struct] final_parameters: [] member_points: [] interactive_choices: {} Bertini_io_folder: '' view_progress: 0 solve_summary: '' function_name: [2x1 polysym] 

There are many different ways of setting up BertiniLab for the same problem. In this example, the variables and equations are input as cell arrays of strings:

poly_system = BertiniLab('variable_group',{'x';'y'},'function_def',{'x^2-1'; 'y^2-1'}); 

In this example, a MATLAB function is used:

polysyms x y polyFun = @(a,b) [a^2-1; b^2-1]; poly_system = BertiniLab('variable_group',[x; y],'function_def',polyFun(x,y)); 

In this example, the variables and declarations are assigned separately:

poly_system = BertiniLab; poly_system.variable_group = {'x';'y'}; poly_system.function_def = {'x^2-1'; 'y^2-1'}; 

## Running Bertini

Once the problem is defined, it is solved using the method solve. This creates the file input and runs Bertini.

poly_system = poly_system.solve; 

Note that poly_system should be the output of the command (the LHS of the above equation) so it can store some information from the run. The resulting object poly_system is shown below:

disp(poly_system) 
 BertiniLab with properties: config: [0x0 struct] function_def: [2x1 polysym] variable: [] variable_group: [2x1 polysym] hom_variable_group: [] pathvariable: [] random: [] random_real: [] definedSubfunction: [] parameter: [0x2 polysym] constant: [0x2 polysym] subfunction: [0x2 polysym] starting_points: [0x0 struct] final_parameters: [] member_points: [] interactive_choices: {} Bertini_io_folder: '' view_progress: 0 solve_summary: ' Bertini(TM) v1.4 (October 23, 2013) D....' function_name: [2x1 polysym] 

A lot of the properties are empty, but function_def and variable_group are assigned; and after solve was called, values are assigned to order_of_variables, solve_summary and output_file_names.

order_of_variables stores the order in which the variables were declared in the Bertini input file:

disp(poly_system.order_of_variables) 
x y 

output_file_names retrieves the names of the files that were created by Bertini during its run:

disp(poly_system.output_file_names(:)) 
 'main_data' 'raw_solutions' 'raw_data' 'real_finite_solutions' 'finite_solutions' 'nonsingular_solutions' 'singular_solutions' 

Finally, solve_summary contains the summary of the run that would go to the screen if Bertini were called in a command window:

disp(poly_system.solve_summary) 
 Bertini(TM) v1.4 (October 23, 2013) D.J. Bates, J.D. Hauenstein, A.J. Sommese, C.W. Wampler (using GMP v5.1.3, MPFR v3.1.2) NOTE: You have requested to use adaptive path tracking. Please make sure that you have setup the following tolerances appropriately: CoeffBound: 1.699664000000e+00, DegreeBound: 2.000000000000e+00 AMPSafetyDigits1: 1, AMPSafetyDigits2: 1, AMPMaxPrec: 1024 Tracking path 0 of 4 Finite Solution Summary NOTE: nonsingular vs singular is based on condition number and identical endpoints | Number of real solns | Number of non-real solns | Total ------------------------------------------------------------------------------------------ Non-singular | 4 | 0 | 4 Singular | 0 | 0 | 0 ------------------------------------------------------------------------------------------ Total | 4 | 0 | 4 Finite Multiplicity Summary Multiplicity | Number of real solns | Number of non-real solns ------------------------------------------------------------------------------------------ 1 | 4 | 0 ------------------------------------------------------------------------------------------ The following files may be of interest to you: main_data: A human-readable version of the solutions - main output file. raw_solutions: A list of the solutions with the corresponding path numbers. raw_data: Similar to the previous, but with the points in Bertini's homogeneous coordinates along with more information about the solutions. real_finite_solutions: A list of all real finite solutions. finite_solutions: A list of all finite solutions. nonsingular_solutions: A list of all nonsingular solutions. singular_solutions: A list of all singular solutions. ------------------------------------------------------------------------------------------ Paths Tracked: 4 

## Retrieving the solutions

The output summary explains the outputs of Bertini. If the users wishes to simply retrieve the solution points, all of them are contained in raw_solutions. Since the solutions are real, nonsingular and finite, they should all be in finite_solutions, real_finite_solutions and nonsingular_solutions. The method match_solutions retrieves the data and assigns it to the correct variables:

sols = poly_system.match_solutions('real_finite_solutions'); disp(sols) 
 x: [4x1 polysym] y: [4x1 polysym] 

The solutions are:

disp([sols.x sols.y]) 
 1.000000000000000e+00+(0.000000000000000e+00)*I 1.000000000000000e+00+(0.000000000000000e+00)*I 9.999999999999999e-01+(0.000000000000000e+00)*I -9.999999999999999e-01+(0.000000000000000e+00)*I -1.000000000000000e+00+(-5.551115123125783e-17)*I 1.000000000000000e+00+(5.551115123125783e-17)*I -1.000000000000000e+00+(5.551115123125783e-17)*I -1.000000000000000e+00+(5.551115123125783e-17)*I 

That's a bit messy. Since the solutions are classified as real, the imaginary part can be ignored. The class polysym has the method real_imag to do this, and we can add the variable names as titles by putting the polysym variables in the top row:

[x_re,~] = sols.x.real_imag; [y_re,~] = sols.y.real_imag; disp([x y; x_re y_re]) 
 x y 1.000000000000000e+00 1.000000000000000e+00 9.999999999999999e-01 -9.999999999999999e-01 -1.000000000000000e+00 1.000000000000000e+00 -1.000000000000000e+00 -1.000000000000000e+00 

The solutions can also be converted to other classes such as double precision:

disp(double([x_re y_re])) 
 1.0000 1.0000 1.0000 -1.0000 -1.0000 1.0000 -1.0000 -1.0000