/usr/include/polymake/tropical/psi_classes.h is in libpolymake-dev-common 3.2r2-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | /*
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
of the License, or (at your option) any later version.
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
---
Copyright (C) 2011 - 2015, Simon Hampe <simon.hampe@googlemail.com>
Functions to compute psi classes and products thereof.
*/
#ifndef POLYMAKE_ATINT_PSI_CLASSES_H
#define POLYMAKE_ATINT_PSI_CLASSES_H
#include "polymake/client.h"
#include "polymake/Matrix.h"
#include "polymake/Rational.h"
#include "polymake/Vector.h"
#include "polymake/PowerSet.h"
#include "polymake/tropical/moduli_rational.h"
namespace polymake { namespace tropical {
//Documentation see perl wrapper
template <typename Addition>
perl::Object psi_product(int n, Vector<int> exponents) {
//First we make sure that the exponent vector is valid
if(exponents.dim() != n) {
throw std::runtime_error("Cannot compute psi class product: Exponent vector length is not n.");
}
int k_sum = 0;
for(int i = 0; i < exponents.dim(); i++) {
if(exponents[i] < 0) {
throw std::runtime_error("Cannot compute psi class product: Negative exponents are not allowed.");
}
k_sum += exponents[i];
}
//Check the trivial cases
if(n < 3 || k_sum > n-3) {
return call_function("zero_cycle");
}
//We have to divide each weight by this:
Integer divisor = 1;
for(int k = 0; k < exponents.dim(); k++) {
divisor *= Integer::fac(exponents[k]);
}
if(k_sum == n-3) {
//Compute the weight of the origin
Matrix<Rational> norays(1,(n*(n-3))/2 + 2);
norays(0,0) = 1;
Vector<Set<int> > vertexcone; vertexcone |= scalar2set(0);
Vector<Integer> singleweight; singleweight |= (Integer::fac(k_sum) / divisor);
perl::Object origin(perl::ObjectType::construct<Addition>("Cycle"));
origin.take("PROJECTIVE_VERTICES") << norays;
origin.take("MAXIMAL_POLYTOPES") << vertexcone;
origin.take("WEIGHTS") << singleweight;
return origin;
}
// ORDER EXPONENT VECTOR ------------------------------------------------------
//We have to put the exponent vector in descending order, i.e. we have to apply a permutation to
//the exponents and later to the resulting Pruefer sequence
Vector<int> ordered_exponents;
Vector<int> permutation;
Set<int> assigned;
while(ordered_exponents.dim() < exponents.dim()) {
int max = -1; int max_index = 0;
for(int i = 0; i < exponents.dim(); i++) {
if(exponents[i] > max && !assigned.contains(i)) {
max = exponents[i]; max_index = i;
}
}
ordered_exponents |= max;
permutation |= max_index;
assigned += max_index;
}
// PRÜFER SEQUENCE COMPUTATION ------------------------------------------------
//Prepare all variables for the Prüfer sequence computation
//The vertex we currently try to place in the sequence
//More precisely: The vertex is current_vertex + n
int current_vertex = 0;
//At [i][j] contains the positions in the sequence (counting from 0)
//that we have already tried for the (j+1)-st occurence of vertex i
//for the given placement of 0,..,current_vertex-1
Vector<Vector<Vector<int> > > placements_tried(n-2-k_sum);
placements_tried[0] |= Vector<int>();
//The current Prüfer sequence (0 = entry we haven't filled yet)
Vector<int> current_sequence(2*n - 4 - k_sum);
//The exponent weights of each entry. The first n are the exponents, the rest is 0
Vector<int> weight = ordered_exponents | zero_vector<int>(n - 4 - k_sum);
Vector<int> orig_weight = exponents | zero_vector<int>(n - 4 - k_sum);
//At entry i contains the number of occurences we still need for vertex i
//given the current placement
Vector<int> numbers_needed = 2*ones_vector<int>(n-2-k_sum);
//This will contain the resulting sequences
Matrix<int> result_sequences(0,2*n-4-k_sum);
while(current_vertex >= 0) {
//Find the next free space after the last tried position
int next_pos = -1;
int occurences_so_far = 0;
//If the vertex index is too large, we have found a solution
if(current_vertex < numbers_needed.dim()) {
occurences_so_far = placements_tried[current_vertex].dim()-1;
//If its' the first occurence (or the last vertex), we always take the first free position, so we only
//have to look something up, if it's not the first occurence and not the last vertex
if(occurences_so_far > 0 && current_vertex < numbers_needed.dim() - 1) {
int placements_so_far = (placements_tried[current_vertex])[occurences_so_far].dim() ;
//If we have tried any placements so far, we try to take the next free position after
//the last one tried, otherwise we take the first free entry after the placement of
//the last occurence
if(placements_so_far > 0) {
next_pos = ((placements_tried[current_vertex])[occurences_so_far] )[ placements_so_far-1];
}
else {
int last_placements = (placements_tried[current_vertex])[occurences_so_far-1].dim();
next_pos = ((placements_tried[current_vertex]) [occurences_so_far-1])[last_placements-1];
}
}
//If it is the first occurence, we still have to check if we already tried the first free
//position
else {
if( (placements_tried[current_vertex])[occurences_so_far].dim() > 0) {
next_pos = current_sequence.dim();
}
}
do {
next_pos++;
if(next_pos >= current_sequence.dim()) break;
}while(current_sequence[next_pos] != 0);
}
else {
if(!(Set<int>(current_sequence)).contains(0)) {
result_sequences /= current_sequence;
}
next_pos = current_sequence.dim();
}
//STEP DOWN: If we cannot place the vertex, we go back a step
if (next_pos >= current_sequence.dim()) {
//Remove placements of the current step
if (current_vertex < numbers_needed.dim())
placements_tried[current_vertex] = placements_tried[current_vertex].slice(
~scalar2set(occurences_so_far));
//and go back one vertex if this is the first occurence
if (occurences_so_far == 0) {
current_vertex--;
}
if(current_vertex >= 0) {
//Remove the occurence of the step we moved back to, since we want to recompute it
int occurence_to_remove = placements_tried[current_vertex].dim();
int placement_to_remove = (placements_tried[current_vertex])[occurence_to_remove-1].dim();
int position_to_remove = ((placements_tried[current_vertex])[occurence_to_remove-1])
[placement_to_remove-1];
current_sequence[position_to_remove] = 0;
numbers_needed[current_vertex] += (1 - weight[position_to_remove]);
}
}//END step down
//INSERT
else {
//Insert current vertex and recompute number of entries needed
current_sequence[next_pos] = current_vertex + n ;
numbers_needed[current_vertex] += (weight[next_pos] -1);
((placements_tried[current_vertex])[occurences_so_far]) |= next_pos;
//STEP UP
//If we still need entries with this vertex, we try the next placement,
//otherwise we go to the next vertex
if (numbers_needed[current_vertex] == 0) {
current_vertex++;
}
if(current_vertex < numbers_needed.dim()) placements_tried[current_vertex] |= Vector<int>();
}//END Insert and step up
}//END compute Prüfer sequences
//Now we have to permute the columns of the sequences back according to the reordering on the
//exponents
result_sequences.minor(All,sequence(0,n)) = permuted_inv_cols(result_sequences.minor(All,sequence(0,n)), permutation);
// MODULI CONE CONVERSION -----------------------------------------------------------
//Prepare variables for the tropical fan
Matrix<Rational> rays(0, (n*(n-3))/2 + 1);
Vector<Rational> newray( (n*(n-3))/2 + 1);
Vector<Set<int> > cones;
Vector<Integer> tropical_weights;
//First we create the edge index matrix E(i,j) that contains at element i,j the edge index of edge (i,j)
//in the complete graph on n-1 nodes
int nextindex = 0;
Matrix<int> E(n-1,n-1);
for(int i = 0; i < n-1; i++) {
for(int j = i+1; j < n-1; j++) {
E(i,j) = nextindex;
E(j,i) = nextindex;
nextindex++;
}
}
//Iterate all Pruefer sequences
for(int s = 0; s < result_sequences.rows(); s++) {
//Convert to partition list
Vector<Set<int> > partitions = decodePrueferSequence(result_sequences.row(s),n);
Set<int> newcone;
//Go through each partition and compute its ray
for(int p = 0; p < partitions.dim(); p++) {
newray.fill(0);
for(pm::Subsets_of_k_iterator<const pm::Set<int>& > raypair = entire(all_subsets_of_k(partitions[p],2)); !raypair.at_end(); raypair++) {
int smaller_index = (*raypair).front();
int larger_index = (*raypair).back();
newray[ E(smaller_index,larger_index)] = Addition::orientation();
}//END iterate pairs in partition
//Now see if the ray is already in our list, otherwise add it
int ray_index = -1;
for(int oray = 0; oray < rays.rows(); oray++) {
if(rays.row(oray) == newray) {
ray_index = oray; break;
}
}
if(ray_index == -1) {
rays /= newray;
ray_index = rays.rows()-1;
}
newcone += ray_index;
}//END iterate partitions
//Add the cone
cones |= newcone;
//Compute its weight from the Pruefer sequence
Vector<int> weights_at_vertices(newcone.size() +1);
//Read off the k-weight at each vertex from the sequence
for(int i = 0; i < n; i++) {
weights_at_vertices[result_sequences(s,i) - n] += orig_weight[i];
}
Integer w = 1;
for(int i = 0; i < weights_at_vertices.dim(); i++) {
w *= Integer::fac(weights_at_vertices[i]);
}
tropical_weights |= (w / divisor);
}//END iterate sequences
//Add a vertex
rays = zero_vector<Rational>() | rays;
rays /= unit_vector<Rational>(rays.cols(),0);
for(int mc = 0; mc < cones.dim(); mc++) {
cones[mc] += scalar2set(rays.rows()-1);
}
perl::Object result(perl::ObjectType::construct<Addition>("Cycle"));
result.take("PROJECTIVE_VERTICES") << rays;
result.take("MAXIMAL_POLYTOPES") << cones;
result.take("WEIGHTS") << tropical_weights;
return result;
}//END function psi_product
//Documentation see perl wrapper
template <typename Addition>
perl::Object psi_class(int n, int i) {
if(n < 0 || i < 1 || i > n) {
throw std::runtime_error("Cannot compute psi_class: Invalid parameters");
}
return psi_product<Addition>(n, unit_vector<int>(n,i-1));
}//END function psi_class
///////////////////////////////////////////////////////////////////////////////////////
}}
#endif
|