File: orbit_polytope_helpers.rules

package info (click to toggle)
polymake 4.15-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 35,892 kB
  • sloc: cpp: 168,945; perl: 43,410; javascript: 31,575; ansic: 3,007; java: 2,654; python: 632; sh: 268; xml: 117; makefile: 61
file content (253 lines) | stat: -rw-r--r-- 8,909 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
#  Copyright (c) 1997-2024
#  Ewgenij Gawrilow, Michael Joswig, and the polymake team
#  Technische Universität Berlin, Germany
#  https://polymake.org
#
#  This program is free software; you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by the
#  Free Software Foundation; either version 2, or (at your option) any
#  later version: http://www.gnu.org/licenses/gpl.txt.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#-------------------------------------------------------------------------------

###################################################################
# subs:
# - getContainedPoints($p, $points)
# - getContainedPointsIndices($p, $points)
# - getContainedOrbReps($rep_index, $group, $lp_reps, $selection)
# - getIndexFromMatrix(Vector vec, Matrix mat) 
# - getArrayNumberFromArrayOfSets(Int $index, Array $arrOfSets) -> Int
# - getLexMin($mat)
# user_functions:
# - nestedOPGraph($gen_point, $points, $lattice_points, $group)
# - ortho_project($p)
# - vlabels(Matrix vertices, Bool wo_zero)
###################################################################


sub getContainedPointsIndices {
   my ($p, $points) = @_;
   my $indices = new Set<Int>();
   for ( my $i=0; $i<$points->rows; ++$i ) {
      if ( !separable($p, $points->[$i]) ) { # points->row(i) is contained in $p
         $indices += $i;
      }
   }
   return $indices;
}

sub getContainedPoints {
   my ($p, $points) = @_;
   return $points->minor(getContainedPointsIndices($p, $points), All);
}


# without the point //rep// itself!
sub getContainedOrbReps {
   my ($rep_index, $group, $lp_reps, $selection) = @_;
   my $p = orbit_polytope($lp_reps->[$rep_index], $group); 
   $p->VERTICES; # just to help the scheduler
   my $indices = new Set<Int>();

   foreach my $sel ( @$selection ) { 
      if ( $rep_index != $sel ) { # exclude rep from output
         if ( !separable($p, $lp_reps->[$sel]) ) { # lp_reps->row(sel) cannot be separated from $p
            $indices += $sel;
         }
      }
   }
   return $indices;
}

sub getIndexFromMatrix {
   my ($vec, $mat) = @_;
   for ( my $i = 0; $i < $mat->rows; ++$i ) {
      if ( $vec == $mat->row($i) ) {
         return $i;
      }
   }
   return -1;
}

sub getLexMin {
   my ($mat) = @_;
   my @rows = map {$mat->row($_)} 0..$mat->rows-1;
   my @sorted = sort @rows;
   return new Vector($sorted[0]);
}

sub getArrayNumberFromArrayOfSets {
   my ($index, $arrOfSets) = @_;

   for ( my $i=0; $i<$arrOfSets->size; ++$i ) {
      if ( $arrOfSets->[$i]->contains($index) ) {
         return $i;
      }
   }

   croak("The index $index was not contained in the array of sets");

}

# @category Symmetry
# Constructs the NOP-graph of an orbit polytope.
# It is used by the rule for the [[NOP_GRAPH]].
# @param Vector gen_point the generating point
# @param Matrix points the vertices of the orbit polytope
# @param Matrix lattice_points the lattice points of the orbit polytope
# @param group::Group group the generating group
# @param Bool verbose print out additional information
# @return ARRAY ($Graph, $lp_reps, $minInStartOrbit, \@core_point_reps, $CPindices)

user_function nestedOPGraph (Vector, Matrix, Matrix, group::PermutationAction, $){
    my ($gen_point, $points, $lattice_points, $group, $verbose) = @_;
    
    my @core_point_reps = ();

#    # construct orbit polytope orb_\Gamma($gen_point)
#    my $p = orbitPolytope($gen_point,$group); 
#    $p = new Polytope(VERTICES=>$p->POINTS, LINEALITY_SPACE=>[], LATTICE=>1, BOUNDED=>1);
#    #$p->VERTICES; # just to help the scheduler
#    prefer_now "normaliz2"; $p->LATTICE_POINTS;
#    my $lattice_points=$p->LATTICE_POINTS;


    my $minInStartOrbit = getLexMin( $points ); 
    # compute orbit decomposition of lattice points in orb_\Gamma($gen_point)
    my $orbit_decomp = group::orbits_of_coordinate_action($group,$lattice_points);

    my $CPindices=new Set<Int>();
    if ($orbit_decomp->size == 1) {
       if ($verbose) {
          print "The starting point [$gen_point] is a core point!\n";
       }
       $CPindices += 0;
       push(@core_point_reps, $gen_point);
    }

    # filter out starting point
    my $index=getIndexFromMatrix($minInStartOrbit,$lattice_points);
    my $orbOfStart = getArrayNumberFromArrayOfSets( $index, $orbit_decomp );

    my @permsOfStart = map{$lattice_points->row($_)} @{$orbit_decomp->[$orbOfStart]};
    my $permsOfStartMat = new Matrix(\@permsOfStart);
    #print $orbOfStart.": ".$permsOfStartMat."\n";

    # take any(!) representative per orbit except for orbit of starting point
    my @rep_ind = map{ if($_ != $orbOfStart) { @{$orbit_decomp->[$_]}[0]; } else {} } 0..$orbit_decomp->size-1;
    my $rep_ind = new Set<Int>(\@rep_ind);
    my $lp_reps = new Matrix<Rational>(convert_to<Rational>($minInStartOrbit) / convert_to<Rational>($lattice_points->minor($rep_ind, All))); #$start at row 0
    if ($verbose) {
       print "All lattice point representatives in orb([$gen_point]):\n".$lp_reps."\n";
    }

    # fill graph
    my $graph=new GraphAdjacency<Directed>();
    $graph->add_node; # added node for start
    for ( my $i=1; $i<$lp_reps->rows; ++$i) { # add edges to all lattice points inside orb\Gamma(start); skip $start at row 0
       $graph->add_node; # the node has the same number as the corresponding row in $lp_reps
       $graph->edge(0, $i); # edges reflect inclusions between orbit polytopes
    }


    for ( my $i=1; $i<$lp_reps->rows; ++$i) { # index-based! Be careful: number in graph must coincide with row number in lp_reps!

       my $selection = new Set<Int>(0..$lp_reps->rows-1);
       my $containedOrbReps = getContainedOrbReps($i, $group, $lp_reps, $selection);

       if ($containedOrbReps->size == 0) {
          my $cp = $lp_reps->[$i];
          if ($verbose) {
             print "[$cp] is a core point!\n";
          }
          $CPindices += $i;
          push(@core_point_reps, $cp);
       } else {

          if ($verbose) {
             print "Representatives of contained orbits w.r.t. [($lp_reps->[$i])] : ".$containedOrbReps."\n";
          }

          foreach (@$containedOrbReps) {
             $graph->edge($i, $_); # add edge from current node to contained reps
          }
       }


    }

    my @labels = map{ sprintf($lp_reps->[$_]) } 0..$lp_reps->rows-1;
    my $Graph = new Graph<Directed>(ADJACENCY=>$graph, NODE_LABELS=>\@labels);
    my $sliced_minstart=$minInStartOrbit->slice(sequence(1, $minInStartOrbit->dim-1));
    my $groupname = $group->name;  
    #$Graph->name="Orbit-Polytope-Graph of [$sliced_minstart] w.r.t. Group $groupname";
    $Graph->name="NOP-graph of [$gen_point] ([$sliced_minstart]) w.r.t. Group $groupname";
    return ($Graph, $lp_reps, $minInStartOrbit, \@core_point_reps, $CPindices);

}





# @category Symmetry
# Projects a symmetric polytope in R<sup>4</sup> cap H<sub>1,k</sub> to R<sup>3</sup>.
# (See also the polymake extension 'tropmat' by S. Horn.)
# @param Polytope p the symmetric polytope to be projected
# @return Polytope the image of //p// in R<sup>3</sup>

user_function ortho_project (Polytope) {
   my $poly = $_[0];
   if ($poly->AMBIENT_DIM != 4) { 
      die "ortho_poly: the ambient dimension of the given polytope is not equal to 4!"
   }
   my @nvs = ();
   for (my $i=0; $i<$poly->N_VERTICES; ++$i) {
      my $v = $poly->VERTICES->[$i];
      my $nv = new Vector(4);
      $nv->[0]=1;
      for (my $j=1; $j<4; ++$j) {
         $nv->[$j] = $v->[$j] - 1/3*$v->[4];
         push(@nvs,$nv);
      }
   }

   my $r = new polytope::Polytope(POINTS=>\@nvs);
   return $r;
}


# @category Visualization
# Creates vertex labels for visualization from the //vertices// 
# of the polytope. The parameter //wo_zero// decides whether
# the entry at position 0 (homogenizing coordinate) is omitted (1)
# or included (0) in the label string." 
# @param Matrix vertices the vertices of the polytope
# @param Bool wo_zero includes (0) or omits (1) the entry at position 0
# @return ARRAY a reference to an array of vertex label strings
# @example This prints the vertex labels for the square with the origin as its center and 
# side length 2, where we omit the leading 1:
# > $l = vlabels(cube(2)->VERTICES,1);
# > print join(', ', @{$l});
# | (-1,-1), (1,-1), (-1,1), (1,1)

user_function vlabels (Matrix,$) {
   my ($vertices, $wo_zero) = @_;
   my @vlabels=();
   if ($wo_zero) {
      @vlabels = map {"(".join(",",@{$vertices->[$_]->slice(sequence(1, $vertices->cols-1))}).")"} 0..$vertices->rows-1;
   } else {
      @vlabels = map {"(".join(",",@{$vertices->[$_]}).")"} 0..$vertices->rows-1;	
   }
   return \@vlabels;
}


# Local Variables:
# mode: perl
# c-basic-offset:4
# End: