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). $$

Contents

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