user_guide:tutorials:latest:perl_intro

Differences

This shows you the differences between two versions of the page.


user_guide:tutorials:latest:perl_intro [2023/11/06 10:57] (current) – created - external edit 127.0.0.1
Line 1: Line 1:
 +====== Using Perl within polymake ======
 +
 +The language that the interactive version of ''%%polymake%%'' speaks is a dialect of Perl that we refer to as ''%%polymake%%''/Perl. See [[http://www.perl.org|www.perl.org]] for comprehensive Perl information. Note also that the ordinary Perl manual pages are particularly useful, especially the perlintro man page which is also available on [[http://perldoc.perl.org/perlintro.html|perldoc]]. This short section here cannot be a replacement for a thorough introduction to this language, but we want to focus on a few key points that are relevant to ''%%polymake%%''.
 +
 +==== Standard data structures ====
 +
 +The Perl programming language originally provides three different data structures, scalars(''%%$%%''), arrays(''%%@%%''), and hashes(''%%%%%''). The user always has to specify the type of a variable using the appropriate symbol ''%%$%%'', ''%%@%%'', or ''%%%%%''. If you forget to do so, you will receive the following error message:
 +
 +<code>
 +> i=5;
 +polymake:  ERROR: Unquoted string "i" may clash with future reserved word.
 +</code>
 +Here are some simple commands illustrating how to use the different data structures:
 +
 +== Scalars ==
 +
 +<code perl>
 +> $i=5;
 +> $j=6;
 +> $sum=$i+$j; print $sum;
 +11
 +</code>
 +== Arrays ==
 +
 +<code perl>
 +> @array=("a","b","c"); print scalar(@array);
 +> push(@array,"d"); print "@array"; 
 +> $first_entry=$array[0]; print $first_entry;
 +> print join("\n",@array);
 +> @array2=(3,1,4,2);
 +> print sort(@array2);
 +3a b c daa
 +b
 +c
 +d1234
 +</code>
 +== Hashes ==
 +
 +<code perl>
 +> %hash=();
 +> $hash{"zero"}=0;
 +> $hash{"four"}=4;
 +> print keys %hash;
 +> print join(", ",keys %hash);
 +> print join(", ",values %hash);
 +> %hash=("one",1,"two",2);
 +> %hash=("one"=>1,"two"=>2);
 +fourzerofour, zero4, 0
 +</code>
 +==== polymake-Perl ====
 +
 +In addition to the three standard data structures, the enriched version of ''%%Perl%%'' used in ''%%polymake%%'' also provides special data structures for dealing with more complicated concepts. For an introduction to the polymake object model see [[properties#objects|here]].
 +
 +''%%polymake%%'''s object hierarchy is completely reflected on the Perl side. Let us create a small polytope as an example object.
 +
 +<code perl>
 +> $p = new Polytope(POINTS=>[[1,0,1],[1,0,-1],[1,1,0],[1,-1,0]]);
 +</code>
 +Note that the ''%%Perl%%''-type of the variable ''%%$p%%'' is ''%%Scalar%%'', as the variable is internally treated as a reference to a ''%%C++%%''-object. The true nature of the object becomes visible if it is printed:
 +
 +<code perl>
 +> print $p;
 +Polymake::polytope::Polytope__Rational=ARRAY(0x55c8aa54c778)
 +</code>
 +In this case it is a ''%%polymake%%'' object from the application ''%%polytope%%'', and it happens to be of type ''%%Polytope<Rational>%%''. Technically, ''%%$p%%'' is a reference to an array (but it should be never treated as an array unless you are deliberately trying to crash ''%%polymake%%''). If you want less technical information on the type of your object, use this:
 +
 +<code perl>
 +> print $p->type->full_name;
 +Polytope<Rational>
 +</code>
 +=== "Small objects": Data structures inherited from C++ ===
 +
 +You can use objects that are inherited from the ''%%C++%%''-side of ''%%polymake%%'' in the interactive shell. A complete list of so-called "small objects" can be found in the [[documentation:latest:common#property_types|online documentation]]. Here is a selection of three different structures that facilitate everyday work with ''%%polymake%%'':
 +
 +== Arrays ==
 +
 +The small object ''%%Array%%'' can be initialized in different ways and with different template parameters:
 +
 +<code perl>
 +> @array=("a","b","c");
 +> $arr1=new Array<String>(\@array); print $arr1;
 +> $arr2=new Array<Int>([3,2,5]); print $arr2;
 +> $arr3=new Array<Int>(0,1,2,3); print $arr3;
 +> $arr4=new Array<Int>(0..4); print $arr4;
 +> $arr5=new Array<Int>($arr4); print $arr5;
 +a b c3 2 50 1 2 30 1 2 3 40 1 2 3 4
 +</code>
 +You have random access:
 +
 +<code perl>
 +> $arr5->[0] = 100;
 +> print $arr5;
 +100 1 2 3 4
 +</code>
 +It is also possible to convert the ''%%C++%%''-object ''%%Array%%'' into a ''%%Perl%%''-array by writing
 +
 +<code perl>
 +> @arr4=@{$arr4}; print $arr2;
 +3 2 5
 +</code>
 +or simply
 +
 +<code perl>
 +> @arr4=@$arr4;
 +</code>
 +== Sets ==
 +
 +On ''%%C++%%''-side sets are stored in a balanced binary search (AVL) tree. For more information see the [[https://polymake.org/release_docs/master/PTL/classpm_1_1Set.html|PTL-documentation]]. In many cases, the small objects can be converted into ''%%Perl%%''-types in the expected way:
 +
 +<code perl>
 +> $set=new Set<Int>(3,2,5); print $set;
 +> print $set->size;
 +> @array_from_set=@$set;
 +{2 3 5}3
 +</code>
 +== Matrices ==
 +
 +Here is a simple way to initialize a matrix:
 +
 +<code perl>
 +> $mat=new Matrix<Rational>([[2,1,4,0,0],[3,1,5,2,1],[1,0,4,0,6]]);
 +> print $mat;
 +2 1 4 0 0
 +3 1 5 2 1
 +1 0 4 0 6
 +</code>
 +You could also define it by passing a reference to an (''%%Perl%%''-)array of ''%%Vectors%%''. The single entries are interpreted as different rows:
 +
 +<code perl>
 +> $row1=new Vector<Rational>([2,1,4,0,0]);
 +> $row2=new Vector<Rational>([3,1,5,2,1]);
 +> $row3=new Vector<Rational>([1,0,4,0,6]);
 +> @matrix_rows=($row1,$row2,$row3);
 +> $matrix_from_array=new Matrix<Rational>(\@matrix_rows);
 +</code>
 +You can change a single entry of a matrix in the following way (if it is not already assigned to an immutable property like ''%%VERTICES%%''!):
 +
 +<code perl>
 +> $mat->row(1)->[1]=7;
 +> print $mat->row(1)->[1], "\n";
 +> print $mat, "\n";
 +> $mat->elem(1,2)=8;
 +> print $mat;
 +7
 +2 1 4 0 0
 +3 7 5 2 1
 +1 0 4 0 6
 +
 +2 1 4 0 0
 +3 7 8 2 1
 +1 0 4 0 6
 +</code>
 +A unit matrix of a certain dimension can be defined via the user-function ''%%unit_matrix<COORDINATE_TYPE>(.)%%'':
 +
 +<code perl>
 +> $unit_mat=4*unit_matrix<Rational>(3);
 +> print $unit_mat;
 +(3) (0 4)
 +(3) (1 4)
 +(3) (2 4)
 +</code>
 +The reason for the "strange output" is the implementation as //sparse matrix//:
 +
 +<code perl>
 +> print ref($unit_mat);
 +Polymake::common::SparseMatrix_A_Rational_I_NonSymmetric_Z
 +</code>
 +However, some functions cannot deal with this special type of matrix. In this case it is necessary to transform the sparse matrix into a dense matrix first via:
 +
 +<code perl>
 +> $dense=new Matrix<Rational>($unit_mat);print $dense;
 +4 0 0
 +0 4 0
 +0 0 4
 +</code>
 +or just
 +
 +<code perl>
 +> $dense2=dense($unit_mat);print $dense2;
 +4 0 0
 +0 4 0
 +0 0 4
 +</code>
 +You can also work with matrices that have different types of coordinates like ''%%Rational%%'', ''%%Float%%'', or ''%%Int%%'':
 +
 +<code perl>
 +> $m_rat=new Matrix<Rational>(3/5*unit_matrix<Rational>(5)); print $m_rat, "\n"; 
 +> $m2=$mat/$m_rat; print $m2, "\n";
 +> $m_int=new Matrix<Int>(unit_matrix<Rational>(5)); print $m_int, "\n";
 +3/5 0 0 0 0
 +0 3/5 0 0 0
 +0 0 3/5 0 0
 +0 0 0 3/5 0
 +0 0 0 0 3/5
 +
 +2 1 4 0 0
 +3 7 8 2 1
 +1 0 4 0 6
 +3/5 0 0 0 0
 +0 3/5 0 0 0
 +0 0 3/5 0 0
 +0 0 0 3/5 0
 +0 0 0 0 3/5
 +
 +1 0 0 0 0
 +0 1 0 0 0
 +0 0 1 0 0
 +0 0 0 1 0
 +0 0 0 0 1
 +
 +</code>
 +Sometimes there is incompatible types:
 +
 +<code perl>
 +> $m3=$m_rat/$m_int;
 +C++/perl Interface module compilation failed; most likely due to a type mismatch.
 +Set the variable $Polymake::User::Verbose::cpp to a positive value and repeat for more details.
 +</code>
 +The error message indicates that you need to convert the integer matrix to a rational matrix first:
 +
 +<code perl>
 +> $m3=$m_rat/(convert_to<Rational>($m_int)); print $m3;
 +3/5 0 0 0 0
 +0 3/5 0 0 0
 +0 0 3/5 0 0
 +0 0 0 3/5 0
 +0 0 0 0 3/5
 +1 0 0 0 0
 +0 1 0 0 0
 +0 0 1 0 0
 +0 0 0 1 0
 +0 0 0 0 1
 +</code>
 +By "/" you can add rows to a matrix, whereas "|" adds columns. By the way, this also works for ''%%Vector%%''.
 +
 +<code perl>
 +> $z_vec=zero_vector<Int>($m_int->rows);
 +> $extended_matrix=($z_vec|$m_int); print $extended_matrix;
 +0 1 0 0 0 0
 +0 0 1 0 0 0
 +0 0 0 1 0 0
 +0 0 0 0 1 0
 +0 0 0 0 0 1
 +</code>
 +It is also possible to nest template parameters in any way you like, e.g.
 +
 +<code perl>
 +> $set=new Set<Int>(3,2,5);
 +> $template_Ex=new Array<Set<Int>>((new Set<Int>(5,2,6)),$set); print $template_Ex; print ref($template_Ex);
 +{2 5 6}
 +{2 3 5}
 +Polymake::common::Array__Set__Int
 +</code>
 +However, if you use a template combination, you have never used before, it may take some time until you see the result. This is due to the fact that ''%%polymake%%'' compiles your new combination //on the fly//. But this is only a one-time effect, and next time you use this combination it will work without delay.
 +
 +=== "Big Objects": Objects with properties ===
 +
 +A big object is an instance of a data type which represents a mathematical concept with clear semantics. They may have template parameters.
 +
 +<code perl>
 +> $p=new Polytope<Rational>(POINTS=>cube(4)->VERTICES);
 +> $lp=new LinearProgram<Rational>(LINEAR_OBJECTIVE=>[0,1,1,1,1]);
 +</code>
 +Big objects have properties which come with a type, which is either built-in or a small object type or a big object type, and which can be accessed using the ''%%-``>%%'' operator.
 +
 +<code perl>
 +> # access the property named `LP`:
 +> $p->LP=$lp;
 +> # properties can have properties themselves.
 +> print $p->LP->MAXIMAL_VALUE;
 +4
 +</code>
 +Scalar properties can be used in arithmetic expressions right away.
 +
 +<code perl>
 +> $i = ($p->N_FACETS * $p->N_FACETS) * 15;
 +> print $i;
 +960
 +</code>
 +Check out the tutorial on properties to learn more about the way properties are used and computed.
 +
 +==== A small example script... ====
 +
 +...to demonstrate the usage of ''%%polymake%%''/Perl. You can download the matrix file {{:points.demo|here}}.
 +
 +<code perl>
 +> ### load matrix from file
 +> open(INPUT, "< demo/Workshop2011/points.demo");
 +> $matrix=new Matrix<Rational>(<INPUT>);
 +> close(INPUT);
 +> print $matrix;
 +
 +
 +> ### create a polytope from the matrix
 +> $p=new Polytope<Rational>(POINTS=>$matrix);
 +> print $p->FACETS;
 +> print $p->DIM;
 +> print $p->VERTEX_SIZES;
 +
 +
 +> ### print "simple" vertices
 +> for(my $i=0;$i<scalar(@{$p->VERTEX_SIZES});$i++){
 +>     if($p->VERTEX_SIZES->[$i]==$p->DIM){
 +>     print $i.": ".$p->VERTICES->row($i)."\n";
 +>     }
 +> }
 +
 +
 +> ### put their indices in a set
 +> $s=new Set<Int>();
 +> for(my $i=0;$i<scalar(@{$p->VERTEX_SIZES});$i++){
 +>     if($p->VERTEX_SIZES->[$i]==$p->DIM){
 +>     $s+=$i;
 +>     }
 +> }
 +
 +
 +> ### iterate the set in two different ways
 +> foreach(@{$s}){
 +>     print $p->VERTICES->row($_)."\n";
 +> }
 +> foreach my $index(@{$s}){
 +>     print $p->VERTICES->row($index)."\n";
 +> }
 +
 +
 +> ### create a minor of the vertices matrix that only contains the simple ones
 +> $special_points=$p->VERTICES->minor($s,All); print $special_points;
 +-1
 +</code>
 +==== Writing scripts ====
 +
 +Comprehensive information on how to use scripts within ''%%polymake%%'' can be found [[user_guide:howto:scripting|here]].
 +