====== 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:
> i=5;
polymake: ERROR: Unquoted string "i" may clash with future reserved word.
Here are some simple commands illustrating how to use the different data structures:
== Scalars ==
> $i=5;
> $j=6;
> $sum=$i+$j; print $sum;
11
== Arrays ==
> @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
== Hashes ==
> %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
==== 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.
> $p = new Polytope(POINTS=>[[1,0,1],[1,0,-1],[1,1,0],[1,-1,0]]);
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:
> print $p;
Polymake::polytope::Polytope__Rational=ARRAY(0x55c8aa54c778)
In this case it is a ''%%polymake%%'' object from the application ''%%polytope%%'', and it happens to be of type ''%%Polytope%%''. 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:
> print $p->type->full_name;
Polytope
=== "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:
> @array=("a","b","c");
> $arr1=new Array(\@array); print $arr1;
> $arr2=new Array([3,2,5]); print $arr2;
> $arr3=new Array(0,1,2,3); print $arr3;
> $arr4=new Array(0..4); print $arr4;
> $arr5=new Array($arr4); print $arr5;
a b c3 2 50 1 2 30 1 2 3 40 1 2 3 4
You have random access:
> $arr5->[0] = 100;
> print $arr5;
100 1 2 3 4
It is also possible to convert the ''%%C++%%''-object ''%%Array%%'' into a ''%%Perl%%''-array by writing
> @arr4=@{$arr4}; print $arr2;
3 2 5
or simply
> @arr4=@$arr4;
== 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:
> $set=new Set(3,2,5); print $set;
> print $set->size;
> @array_from_set=@$set;
{2 3 5}3
== Matrices ==
Here is a simple way to initialize a matrix:
> $mat=new Matrix([[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
You could also define it by passing a reference to an (''%%Perl%%''-)array of ''%%Vectors%%''. The single entries are interpreted as different rows:
> $row1=new Vector([2,1,4,0,0]);
> $row2=new Vector([3,1,5,2,1]);
> $row3=new Vector([1,0,4,0,6]);
> @matrix_rows=($row1,$row2,$row3);
> $matrix_from_array=new Matrix(\@matrix_rows);
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%%''!):
> $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
A unit matrix of a certain dimension can be defined via the user-function ''%%unit_matrix(.)%%'':
> $unit_mat=4*unit_matrix(3);
> print $unit_mat;
(3) (0 4)
(3) (1 4)
(3) (2 4)
The reason for the "strange output" is the implementation as //sparse matrix//:
> print ref($unit_mat);
Polymake::common::SparseMatrix_A_Rational_I_NonSymmetric_Z
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:
> $dense=new Matrix($unit_mat);print $dense;
4 0 0
0 4 0
0 0 4
or just
> $dense2=dense($unit_mat);print $dense2;
4 0 0
0 4 0
0 0 4
You can also work with matrices that have different types of coordinates like ''%%Rational%%'', ''%%Float%%'', or ''%%Int%%'':
> $m_rat=new Matrix(3/5*unit_matrix(5)); print $m_rat, "\n";
> $m2=$mat/$m_rat; print $m2, "\n";
> $m_int=new Matrix(unit_matrix(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
Sometimes there is incompatible types:
> $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.
The error message indicates that you need to convert the integer matrix to a rational matrix first:
> $m3=$m_rat/(convert_to($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
By "/" you can add rows to a matrix, whereas "|" adds columns. By the way, this also works for ''%%Vector%%''.
> $z_vec=zero_vector($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
It is also possible to nest template parameters in any way you like, e.g.
> $set=new Set(3,2,5);
> $template_Ex=new Array>((new Set(5,2,6)),$set); print $template_Ex; print ref($template_Ex);
{2 5 6}
{2 3 5}
Polymake::common::Array__Set__Int
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.
> $p=new Polytope(POINTS=>cube(4)->VERTICES);
> $lp=new LinearProgram(LINEAR_OBJECTIVE=>[0,1,1,1,1]);
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.
> # access the property named `LP`:
> $p->LP=$lp;
> # properties can have properties themselves.
> print $p->LP->MAXIMAL_VALUE;
4
Scalar properties can be used in arithmetic expressions right away.
> $i = ($p->N_FACETS * $p->N_FACETS) * 15;
> print $i;
960
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}}.
> ### load matrix from file
> open(INPUT, "< demo/Workshop2011/points.demo");
> $matrix=new Matrix();
> close(INPUT);
> print $matrix;
>
>
> ### create a polytope from the matrix
> $p=new Polytope(POINTS=>$matrix);
> print $p->FACETS;
> print $p->DIM;
> print $p->VERTEX_SIZES;
>
>
> ### print "simple" vertices
> for(my $i=0;$iVERTEX_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();
> for(my $i=0;$iVERTEX_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
==== Writing scripts ====
Comprehensive information on how to use scripts within ''%%polymake%%'' can be found [[user_guide:howto:scripting|here]].