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:
|