user_guide:howto:scripting

Differences

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

Link to this comparison view

Next revision
Previous revision
Next revisionBoth sides next revision
user_guide:howto:scripting [2019/01/25 13:43] – migrated from scripting:start oroehriguser_guide:howto:scripting [2019/03/28 10:53] – put $ into '' '' benmuell
Line 35: Line 35:
   * ''$InstallTop/scripts'' -- standard neutral scripts shipped with polymake   * ''$InstallTop/scripts'' -- standard neutral scripts shipped with polymake
   * ''@lookup_scripts'' -- additional directories of your choice containing your private scripts.  This list is a [[:general#custom_variables|custom variable]] stored in ''~/.polymake/prefer.pl''.   * ''@lookup_scripts'' -- additional directories of your choice containing your private scripts.  This list is a [[:general#custom_variables|custom variable]] stored in ''~/.polymake/prefer.pl''.
-  * ''$Extension/scripts'' -- neutral scripts coming from an [[reference:extensions|extension]]+  * ''$Extension/scripts'' -- neutral scripts coming from an [[user_guide:extend:extensions|extension]]
  
 Application-specific scripts are kept in the applications' subtrees: Application-specific scripts are kept in the applications' subtrees:
Line 79: Line 79:
 For example, ''$BB::z'' will be treated as ''$AA::BB::z'', and ''$CC::w'' will refer to ''$AA::BB::CC::w'' from within ''AA::BB'', ''AA::BB::DD'' and any other enclosed package. For example, ''$BB::z'' will be treated as ''$AA::BB::z'', and ''$CC::w'' will refer to ''$AA::BB::CC::w'' from within ''AA::BB'', ''AA::BB::DD'' and any other enclosed package.
  
-Package names themselves can be shortened too, but only in few contexts.  The most important place is static function call, like a constructor call ''new C(1,2,3)'' .  The package name must be spelled completely in ''bless'' statements, in ''@ISA'' assignments, in ''UNIVERSAL::isa()'' checks, and ''ref'' comparisons.  As a partial alternative for the latter two cases there is a new expression ''instanceof CLASSNAME($object)'', delivering a boolean TRUE if ''$object'' is born in package //CLASSNAME// or derived thereof; here the //CLASSNAME// is subject to namespace lookup again. +Package names themselves can be shortened too, but only in few contexts.  The most important place is static function call, like a constructor call ''new C(1,2,3)'' .  The package name must be spelled completely in ''package'' and ''bless'' statements, in ''@ISA'' assignments, in ''UNIVERSAL::isa()'' checks, and ''ref'' comparisons.  As a partial alternative for the latter two cases there is a new expression ''instanceof CLASSNAME($object)'', delivering a boolean TRUE if ''$object'' is born in package //CLASSNAME// or derived thereof; here the //CLASSNAME// is subject to namespace lookup again.
- +
-The ''package'' statement used to switch between packages also requires full package names, but there are convenient shortcuts for switching between related packages: ''_'' denotes the previous package, and ''%%__%%'' denotes the one enclosing it.  This notation should resemble the widely adopted designators of the "current directory" ''.'' and the "parent directory" ''..'' +
- +
-''package AA::BB;'' \\ # this is interpreted in traditional way, as ::AA::BB +
-   +
-''package _::CC;'' \\ # here the package AA::BB::CC starts +
- +
-''package %%__::DD;%%'' \\ # here the package AA::BB::DD starts +
- +
-''package %%__%%;'' \\ # here we've come back to AA::BB+
  
 === Extending lookup scope === === Extending lookup scope ===
Line 95: Line 85:
 Each package compiled from polymake source code possesses its own lookup list.  By default it consists of all enclosing packages, but can be easily extended by arbitrary further packages.  This is accomplished with a statement <code>using namespaces "OTHER_PACKAGE", ...;</code> put somewhere in the package being extended.  Please note that this is a real function call, not a pragma, therefore it must be executed early enough to have effect on the package code.  The extension relation is transitive. Each package compiled from polymake source code possesses its own lookup list.  By default it consists of all enclosing packages, but can be easily extended by arbitrary further packages.  This is accomplished with a statement <code>using namespaces "OTHER_PACKAGE", ...;</code> put somewhere in the package being extended.  Please note that this is a real function call, not a pragma, therefore it must be executed early enough to have effect on the package code.  The extension relation is transitive.
  
-This extension mechanism is involved, for example, in the process of importing applications: the application polytope imports everything from applications graph and common, so the lookup list for the package ''Polymake::polytope'' contains ''Polymake:::graph'' and ''Polymake::common'' along with the enclosing ''Polymake'' If some other application would import the application polytope, it would automatically inherit its entire lookup list.+This extension mechanism is involved, for example, in the process of importing applications: the application polytope imports everything from applications graph and common, so the lookup list for the package ''Polymake::polytope'' contains ''Polymake::graph'' and ''Polymake::common'' along with the enclosing ''Polymake'' If some other application would import the application polytope, it would automatically inherit its entire lookup list.
  
 Another form of extending the lookup scope are lexical lookup lists.  They are established using pragma statements <code>use namespaces "OTHER_PACKAGE", ...;</code>  Such a lookup list pertains to the lexical scope containing the pragma statement, it effects the code following it up to the end of the scope or the corresponding ''no namespaces ...;'' statement regardless of the package boundaries.  For scripting, you won't probably use this pragma directly, but rather its derivative <code>use application "APPNAME";</code>  Please note the difference between the package-based and lexical lookup lists: if some name has been found using the former, its entry in the current package symbol table is modified as to point to the imported item, so that all other references to this name in the current package are redirected at once; but if the name lookup has been satisfied using the lexical list, only this very reference is redirected, but not other occurrences elsewhere in the code.  This allows, for example, for different applications to define functions with identical names; the user's script can still call them using unqualified names, the correct instance being chosen depending upon which ''use application'' pragma is in effect at each place. Another form of extending the lookup scope are lexical lookup lists.  They are established using pragma statements <code>use namespaces "OTHER_PACKAGE", ...;</code>  Such a lookup list pertains to the lexical scope containing the pragma statement, it effects the code following it up to the end of the scope or the corresponding ''no namespaces ...;'' statement regardless of the package boundaries.  For scripting, you won't probably use this pragma directly, but rather its derivative <code>use application "APPNAME";</code>  Please note the difference between the package-based and lexical lookup lists: if some name has been found using the former, its entry in the current package symbol table is modified as to point to the imported item, so that all other references to this name in the current package are redirected at once; but if the name lookup has been satisfied using the lexical list, only this very reference is redirected, but not other occurrences elsewhere in the code.  This allows, for example, for different applications to define functions with identical names; the user's script can still call them using unqualified names, the correct instance being chosen depending upon which ''use application'' pragma is in effect at each place.
Line 101: Line 91:
 ==== Templates ==== ==== Templates ====
  
-Analogously to C++ templates, polymake allows classes and functions to be parameterized with data types.  Due to obscure technical reasons, //definitions// have to reside in [[reference:rulefiles#type_definitions|rule files]].  However, you can //use// the templates in the scripts too, that's what we are describing here.+Analogously to C++ templates, polymake allows classes and functions to be parameterized with data types.  Due to obscure technical reasons, //definitions// have to reside in [[user_guide:extend:rulefiles#type_definitions|rule files]].  However, you can //use// the templates in the scripts too, that's what we are describing here.
  
 The class templates can be used in constructors and other static method calls: The class templates can be used in constructors and other static method calls:
Line 113: Line 103:
 $c=cast<LatticePolytope>(cube(3)); $c=cast<LatticePolytope>(cube(3));
 </code> </code>
- 
-This syntax is resembling the C++ language as close as possible; unfortunately, this comfort was achieved at the price of severe mistreatment of perl parser.  The consequence is that it can't always correctly recognize the end of the argument list.  If you are going to put several expressions  
-involving templates into a single list (for example, when calling a function), you must enclose each expression in an extra pair of parentheses: 
-  $p=intersection( (new Polytope<Rational>(POINTS=>$p1)), (new Polytope<Rational>(POINTS=>$p2)) ); 
  
 ==== Advanced techniques ==== ==== Advanced techniques ====
Line 131: Line 117:
 === Localizations === === Localizations ===
  
-The standard ''local'' operator is very useful as it allows to make exception-safe temporary changes.  polymake enhances this functionality in two aspects: +The standard ''local'' operator is very useful as it allows to make exception-safe temporary changes.  polymake enhances this functionality in several aspects: 
-   -- ''local'' works with package variables only.  Using new functions ''local_scalar'', ''local_array'', ''local_hash'', and ''local_sub'', you can temporarily modify each data type passed by reference too:\\ ''$a=[1,2];''\\ ''local_array($a[3,4]);'' +   -- ''local'' works with package variables only.  Using additional keywords ''scalar'' and ''ref'', you can temporarily modify lexical variables, scalars returned by lvalue functions, and any data items passed by reference: 
-   .. There are further functions doing temporary changes, which are reverted on leaving the block scope:\\ ''local_incr($scalar, number)'' -- add number\\ ''local_shift(\@array)'' -- hide the first element\\ ''local_pop(\@array)'' -- hide the last element \\ ''local_clip_front(\@arrayn)'' -- hide elements at the front so that the element [n] becomes the first one\\ ''local_clip_back(\@array, n)'' -- hide elements at the end so that the element [n] becomes the last one\\ ''local_unshift(\@arraylist)'' -- prepend elements\\ ''local_push(\@arraylist)'' -- append elements \\ ''local_swap(\@array, i1, i2)'' -- exchange two elements with given indices\\ ''%%local_bless($object, "Package" or \%Package::)%%'' -- change the type of an object +     ? ''local scalar $a=2;'' \\ ''local scalar $obj->member=3;'' 
-   -- You can postpone the reverting actions to an outer enclosing block scope, even located in a different subroutine.  You create a special guard object in the outer scope and pass it to other subroutines.  All temporary modifications remain in effect until the guard object is destroyed+     : Temporarily modify lexical variable or a data member returned as lvalue 
-   .. <code> +     ? ''local scalar $b;'' 
-sub func { +     : Save the current value of a scalar so that it's automatically restored when the localization scope is left 
-  my $guard=shift; +     ? ''local scalar ++$c;'' \\ ''local scalar --$d;'' 
-  $guard->begin_locals; +     : Save the current value and increment/decrement temporarily 
-  local $xyz=123; +     ? ''local ref $e=[3,4];'' \\ ''local ref $f={value => 5};'' 
-  $guard->end_locals; +     :: Temporarily replace an array or hash passed by reference. 
-+     .. Note: it's really the array resp. hash which is modified here, the change will be visible through all references pointing to it. 
-declare $xyz=0; +     ? ''local ref $s=sub { ... }'' 
-+     : Temporarily replace the implementation of subroutine passed by reference 
-  my $guard=new Scope; +     ? ''local bless $obj;'' \\ ''%%local bless $obj, "Package";%%'' 
-  func($guard)+     : Temporarily change the type of an object passed by reference 
-  # $xyz is still 123 +   -- Some basic array modifications can be made temporarily, they are automatically undone when the localization scope is left. Arrays can reside in package or local variables or be passed by reference: 
-+     ? ''local unshift @a, ...;'' \\ ''local push @$b...;'' 
-# $xyz reverted to 0 now</code> +     : Temporarily add elements at the beginning resp. at the end of an array 
-   .. All ''local_XXX'' functions described above can be used in the block ''begin_locals'' .. ''end_locals'' too+     ? ''local shift @a;'' \\ ''local pop @$b;'' 
-   .. There is one session-scope guard dwelling in the variable ''$Polymake::Scope'' (aka ''$Scope'' due to namespace lookup rules).  Its lifetime ends with the complete interpretation of the current input line in the interactive shell, or complete execution of the script started in [[#calling|batch mode]].  This guard is used, among others, by [[:general#preferences|prefer_now]] commands, as well as for purging temporary properties from the objects.+     : Return and temporarily hide the first resp. last element 
 +     ? ''local splice @a0, N;'' 
 +     : Return and temporarily hide the first N elements 
 +     ? ''local splice @aN;'' 
 +     : Return and temporarily hide trailing elements starting with position N (can be negative) 
 +     ? ''local swap @a, i1, i2;'' 
 +     : Temporarily exchange two elements with given indices 
 +   -- Localization scope can be extended to the outer enclosing block or bound to the lifetime of a certain scalar
 +     ? ''local if (...) local $x=1} else { local ref $y=[ 2 ]; }'' 
 +     :: Changes made in then/else branches will be reverted when the block enclosing the entire ''if'' is left 
 +     ? ''local with ($scope{ local $x=1; }'' 
 +     :: Changes made within the block will be reverted when the ''$scope'' scalar is destroyed; this can happen at any later point in time, far away from the block or subroutine enclosing this place.  The same scalar can be used repeatedly in the same or different ''with'' blocks; all reverting actions will be accumulated and applied in reverse order It must have an undefined value before first use
 +     .. There is one session-scope guard ''%%$Scope->locals%%'' used, among others, by [[:general#preferences|prefer_now]] commands and for removing temporary properties from big objects. 
 +     .. If you want to introduce temporary changes lasting until the next interactive shell input or the completion of a script started in [[#calling|batch mode]], \\ use ''%%local with($Scope->locals) { ... }%%'' 
 +     .. If you want to introduce a nested localization scope with shorter lifetime within your script, create a temporary Scope object: ''local $Scope=new Scope();''
  
 ===== Most important interfaces ===== ===== Most important interfaces =====
Line 193: Line 193:
      :: like above, but adding (or replacing) properties      :: like above, but adding (or replacing) properties
      ? ''%%$p->copy_permuted(VERTICES => $v)%%''      ? ''%%$p->copy_permuted(VERTICES => $v)%%''
-     :: first finds a permutation mapping the listed properties of the source object $p to the given values (here: ''%%$p->VERTICES%%'' => ''$v''), then applies it to all source properties and stores the results in the new object.  Invariant properties are copied verbatim.  If no suitable permutation can be found, an exception is raised.+     :: first finds a permutation mapping the listed properties of the source object ''$p'' to the given values (here: ''%%$p->VERTICES%%'' => ''$v''), then applies it to all source properties and stores the results in the new object.  Invariant properties are copied verbatim.  If no suitable permutation can be found, an exception is raised.
  
 === Name and Description === === Name and Description ===
Line 232: Line 232:
  
   ? ''%%$l=$p->lookup("VERTEX_LABELS");%%''   ? ''%%$l=$p->lookup("VERTEX_LABELS");%%''
-  :: returns the property value or ''undef'' if the property does not exist.  [[reference:rules#shortcuts|Shortcut rules]] may be applied if necessary.+  :: returns the property value or ''undef'' if the property does not exist.  [[user_guide:extend:rules#shortcuts|Shortcut rules]] may be applied if necessary.
   ? ''%%$p->VERTICES%%''   ? ''%%$p->VERTICES%%''
   ? ''%%$p->give("VERTICES")%%''   ? ''%%$p->give("VERTICES")%%''
-  :: returns the property value; applies [[reference:rules|production rules]] if the property does not exist yet.  An ''undef'' as result means that the object does not have enough initial properties to compute the requested one, or that all production rules delivering it turned out to be infeasible due to [[reference:rules#preconditions|preconditions]].+  :: returns the property value; applies [[user_guide:extend:rules|production rules]] if the property does not exist yet.  An ''undef'' as result means that the object does not have enough initial properties to compute the requested one, or that all production rules delivering it turned out to be infeasible due to [[user_guide:extend:rules#preconditions|preconditions]].
   ? ''%%$p->VERTICES | POINTS%%''   ? ''%%$p->VERTICES | POINTS%%''
   ? ''%%$p->give("VERTICES | POINTS")%%''   ? ''%%$p->give("VERTICES | POINTS")%%''
Line 432: Line 432:
  
 Except for few special cases, all wrappers for C++ classes are equipped with a set of standard constructors.  Besides the already mentioned copy constructor, these are the default constructor ''new TYPE()'' and the parsing constructor ''%%new TYPE("string")%%'' Except for few special cases, all wrappers for C++ classes are equipped with a set of standard constructors.  Besides the already mentioned copy constructor, these are the default constructor ''new TYPE()'' and the parsing constructor ''%%new TYPE("string")%%''
-taking a printable representation of the value.  Container types like Array or Vector also have a list constructor ''%%new TYPE([ value, value, ... ])%%'' taking an arbitrary list of elements.  If you definitely know that more than one element is going to be passed, you can also omit the square brackets.  The same applies for composite types like Pair, they always have a constructor taking the list of initializers of their members.  Furthermore, type-specific constructors may be defined in the [[reference:rulefiles#property_type_scope_definitions|rulefiles]].+taking a printable representation of the value.  Container types like Array or Vector also have a list constructor ''%%new TYPE([ value, value, ... ])%%'' taking an arbitrary list of elements.  If you definitely know that more than one element is going to be passed, you can also omit the square brackets.  The same applies for composite types like Pair, they always have a constructor taking the list of initializers of their members.  Furthermore, type-specific constructors may be defined in the [[user_guide:extend:rulefiles#property_type_scope_definitions|rulefiles]].
  
 ==== Common operations ==== ==== Common operations ====
  • user_guide/howto/scripting.txt
  • Last modified: 2021/01/12 15:49
  • by gawrilow