File: fan_properties.rules

package info (click to toggle)
polymake 4.12-3
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 35,992 kB
  • sloc: cpp: 168,768; perl: 43,375; javascript: 31,575; ansic: 3,007; java: 2,654; python: 633; sh: 268; xml: 117; makefile: 61
file content (855 lines) | stat: -rw-r--r-- 31,217 bytes parent folder | download | duplicates (2)
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
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
#  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.
#-------------------------------------------------------------------------------

object PolyhedralFan {

# to be overloaded in special cases like Scalar==Float
sub prepare_computations { undef }

# @category Geometry
# Dimension of the space which contains the polyhedral fan.
# Note: To avoid confusion in context of (in-)homogenuous coordinates it is generally advised to use the method [[AMBIENT_DIM]].
# @example The fan living in the plane containing only the cone which consists of the ray pointing in positive x-direction is
# by definition embedded in the plane:
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0]],INPUT_CONES=>[[0]]);
# > print $f->FAN_AMBIENT_DIM;
# | 2

property FAN_AMBIENT_DIM : Int;


# @category Geometry
# Dimension of the polyhedral fan.
# # Note: To avoid confusion in context of (in-)homogenuous coordinates it is generally advised to use the method [[DIM]].
# @example The fan living in the plane containing only the cone which consists of the ray pointing in positive x-direction is
# 1-dimensional:
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0]],INPUT_CONES=>[[0]]);
# > print $f->FAN_DIM;
# | 1

property FAN_DIM : Int;

# @category Combinatorics
# Combinatorial dimension of the fan.
# @example The [[normal_fan|normal fan]] of the 6-cube has combinatorial dimension 5:
# > print normal_fan(cube(6))->COMBINATORIAL_DIM;
# | 5

property COMBINATORIAL_DIM : Int;

# @category Geometry
# A fan is __full-dimensional__ if its [[FAN_DIM|dimension]] and [[FAN_AMBIENT_DIM|ambient dimension]] coincide.
# @example The [[normal_fan|normal fan]] of a polytope is always full-dimensional, which we see here for the 5-dimensional [[cross|cross polytope]]:
# > $nf = normal_fan(cross(5));
# > print $nf->FULL_DIM;
# | true

property FULL_DIM : Bool;

# @category Geometry
# A fan is __pointed__ if the [[LINEALITY_SPACE|lineality space]] is trivial.
# @example The [[normal_fan|normal fan]] of a polytope is pointed if and only if the polytope is full-dimensional. Here we confirm this for
# the normal fans of the 2-cube living in 2- and in 3-space, respectively:
# > $nf_full = normal_fan(cube(2));
# > print $nf_full->POINTED;
# | true
# > $nf_not_full = normal_fan(product(cube(2),new Polytope(POINTS=>[[1,0]])));
# > print $nf_not_full->POINTED;
# | false

property POINTED : Bool;

# @category Geometry
# Since we do not require our cones to be [[POINTED|pointed]]: a basis of the lineality space of the fan. Co-exists with [[RAYS]].
# @example We can create a fan in 3-space from the two 2-dimensional cones which are the (x,y)- and (x,z)-halfspaces where
# y and z are non-negative, respectively. Both cones and thus the fan contain lineality in x-direction:
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0,0],[0,1,0],[0,0,1],[-1,0,0]],INPUT_CONES=>[[0,1,3],[0,2,3]]);
# > print $f->LINEALITY_SPACE;
# | 1 0 0

property LINEALITY_SPACE : Matrix<Scalar>;


# @category Geometry
# A basis of the orthogonal complement to [[LINEALITY_SPACE]].
# @example In 3-space, we build a fan containing only the ray pointing in positive x-direction, together with lineality in y-direction.
# The definition of the cones yields no additional lineality, thus the orthogonal complement to the lineality space is spanned
# by (1,0,0) and (0,0,1):
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0,0]],INPUT_CONES=>[[0]],INPUT_LINEALITY=>[[0,1,0]]);
# > print $f->ORTH_LINEALITY_SPACE;
# | 1 0 0
# | 0 0 1

property ORTH_LINEALITY_SPACE : Matrix<Scalar>;


# @category Geometry
# Dimension of the [[LINEALITY_SPACE|lineality space]].
# @example A [[POINTED|pointed]] fan has no lineality, thus the dimension of its lineality space is 0. The most simple example is a fan
# only consisting of one ray, here in the plane:
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0]],INPUT_CONES=>[[0]]);
# > print $f->LINEALITY_DIM;
# | 0

property LINEALITY_DIM : Int;


# @category Input property
# Rays from which the cones are formed.  May be redundant. All vectors in the input must be non-zero.
# You also need to provide [[INPUT_CONES]] to define a fan completely.
# Input section only. Ask for [[RAYS]] if you want a list of non-redundant rays.
# @example When constructing the fan which displays the division of the plane into quadrants, we can use
# redundant rays such that the indices given in [[INPUT_CONES]] suggest that two rays form the border of our fan, but due
# to our choice in [[INPUT_RAYS]], they actually are the same ray adjacent to two distinct 2-dimensional cones:
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0],[0,1],[-1,0],[0,-1],[2,0]],INPUT_CONES=>[[0,1],[1,2],[2,3],[3,4]]);
# > print rows_labeled($f->RAYS);
# | 0:1 0
# | 1:0 1
# | 2:-1 0
# | 3:0 -1
# > print $f->CONES;
# | <{0}
# | {1}
# | {2}
# | {3}
# | >
# | <{0 1}
# | {1 2}
# | {2 3}
# | {0 3}
# | >


property INPUT_RAYS : Matrix<Scalar>;


# @category Input property
# Maybe redundant list of not necessarily maximal cones.  Indices refer to [[INPUT_RAYS]].
# Each cone must list all rays of [[INPUT_RAYS]] it contains.
# Any incident cones will automatically be added.
# The cones are allowed to contain lineality.
# Cones which do not have any rays correspond to the trivial cone (contains only the origin).
# An empty fan does not have any cones.
# Input section only. Ask for [[MAXIMAL_CONES]] if you want to know the maximal cones (indexed by [[RAYS]]).
# @example In 3-space, we construct the fan containing the closure of the all-positive octant and the
# (x<=0, y>=0, z=0) quadrant with the following input (note that we do not have to state the combinatorics for
# cones contained in a given cone of higher dimension, e.g. the the (x>=0, z>=0) quadrant in the y=0 plane):
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0,0],[0,1,0],[0,0,1],[-1,0,0]],INPUT_CONES=>[[0,1,2],[1,3]]);
# > print rows_labeled($f->RAYS);
# | 0:1 0 0
# | 1:0 1 0
# | 2:0 0 1
# | 3:-1 0 0
# > print $f->CONES;
# | <{1}
# | {3}
# | {2}
# | {0}
# | >
# | <{1 3}
# | {1 2}
# | {0 2}
# | {0 1}
# | >
# | <{0 1 2}
# | >


property INPUT_CONES : IncidenceMatrix;

# @category Input property
# Vectors whose linear span defines a subset of the lineality space of the fan; 
# redundancies are allowed.
#
# Input section only.  Ask for [[LINEALITY_SPACE]] if you want to know the lineality space.
# @example In 3-space, we can "stretch" the (x>=0, y>=0) quadrant in the z=0 hyperplane to obtain the joint of the
# two octants where x and y are non-negative by adding linearity in z-direction:
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0,0],[0,1,0]],INPUT_CONES=>[[0,1]],INPUT_LINEALITY=>[[0,0,1]]);

property INPUT_LINEALITY : Matrix<Scalar>;


# @category Geometry
# Rays of the [[PolyhedralFan]]. Non-redundant. Co-exists with [[LINEALITY_SPACE]].
# @example The rays of the [[face_fan|face fan]] of a 3-dimensioanl cube. This fan has one ray in the direcction of each vertex of the cube.
# > print face_fan(cube(3))->RAYS;
# | -1 -1 -1
# | 1 -1 -1
# | -1 1 -1
# | 1 1 -1
# | -1 -1 1
# | 1 -1 1
# | -1 1 1
# | 1 1 1

property RAYS : Matrix<Scalar> {
   sub canonical { &canonicalize_rays; }
}

# permuting the [[RAYS]]
permutation RaysPerm : PermBase;

rule RaysPerm.PERMUTATION : RaysPerm.RAYS, RAYS, LINEALITY_SPACE {
   my $cmp = $this->prepare_computations;
   $this->RaysPerm->PERMUTATION = find_representation_permutation($this->RaysPerm->RAYS, $this->RAYS, $this->LINEALITY_SPACE, 0)
      // die "no permutation";
}

rule RAYS : RaysPerm.RAYS, RaysPerm.PERMUTATION {
   $this->RAYS=permuted_rows($this->RaysPerm->RAYS, $this->RaysPerm->PERMUTATION);
}
weight 1.10;

# @category Geometry
# Number of [[RAYS]].
# @example The number of facets of a polytope is the number of rays of the corresponding [[normal_fan|normal fan]]. Here we see this for the 3-cube:
# > print normal_fan(cube(3))->N_RAYS;
# | 6

property N_RAYS : Int;

# @category Geometry
# Number of [[INPUT_RAYS]].
# @example To determine the combined amount of redundant and unused rays given by [[INPUT_RAYS]], we compare this number
# to [[N_RAYS]]:
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0],[0,1],[-1,0],[0,-1],[2,0],[1,1]],INPUT_CONES=>[[0,1],[1,2],[2,3],[3,4]]);
# > print ($f->N_INPUT_RAYS-$f->N_RAYS);
# | 2

property N_INPUT_RAYS : Int;

# @category Combinatorics
# Non redundant list of maximal cones.  Indices refer to [[RAYS]].
# Cones which do not have any rays correspond to the trivial cone (contains only the origin).
# An empty fan does not have any cones.
# @example The maximal cones of the normal fan of the 3-cube describe which faces share a common vertex:
# > print normal_fan(cube(3))->MAXIMAL_CONES;
# | {0 2 4}
# | {1 2 4}
# | {0 3 4}
# | {1 3 4}
# | {0 2 5}
# | {1 2 5}
# | {0 3 5}
# | {1 3 5}

property MAXIMAL_CONES : IncidenceMatrix;

rule MAXIMAL_CONES : RaysPerm.MAXIMAL_CONES, RaysPerm.PERMUTATION {
   $this->MAXIMAL_CONES = permuted_cols($this->RaysPerm->MAXIMAL_CONES, $this->RaysPerm->PERMUTATION);
}

# permuting the [[MAXIMAL_CONES]]
permutation ConesPerm : PermBase;

rule ConesPerm.PERMUTATION : ConesPerm.MAXIMAL_CONES, MAXIMAL_CONES  {
   $this->ConesPerm->PERMUTATION = find_permutation(new Array<Set<Int>>(rows($this->ConesPerm->MAXIMAL_CONES)), new Array<Set<Int>>(rows($this->MAXIMAL_CONES)))
      // die "no permutation";
}
weight 1.10;


rule MAXIMAL_CONES : ConesPerm.MAXIMAL_CONES, ConesPerm.PERMUTATION {
   $this->MAXIMAL_CONES = permuted_rows($this->ConesPerm->MAXIMAL_CONES, $this->ConesPerm->PERMUTATION);
}
weight 1.10;

# @category Combinatorics
# Transposed to [[MAXIMAL_CONES]].
# Notice that this is a temporary property; it will not be stored in any file.
property MAXIMAL_CONES_THRU_RAYS : IncidenceMatrix;

rule MAXIMAL_CONES_THRU_RAYS : MAXIMAL_CONES {
    $this->MAXIMAL_CONES_THRU_RAYS(temporary)=transpose($this->MAXIMAL_CONES);
}


# @category Combinatorics
# List of all cones of the fan of each dimension.  Indices refer to [[RAYS]].
# @example A fan constructed with a 2-dimensional cone in [[INPUT_CONES]] also contains the incident 1-dimensional
# cones.
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0],[0,1]],INPUT_CONES=>[[0,1]]);
# > print $f->CONES;
# | <{0}
# | {1}
# | >
# | <{0 1}
# | >
property CONES : Array<IncidenceMatrix>;

# @category Combinatorics
# Number of [[MAXIMAL_CONES]].
# @example The number of facets of a polytope is the same as the number of maximal cones of its face fan;
# here we can see this for the 3-cube:
# > print face_fan(cube(3))->N_MAXIMAL_CONES;
# | 6
property N_MAXIMAL_CONES : Int;

# @category Combinatorics
# Number of [[CONES]].
property N_CONES : Int;

# @category Combinatorics
# Array of incidence matrices of all [[MAXIMAL_CONES|maximal cones]]. Indices refer to [[RAYS]].
# @example Here we construct a fan with a 3-dimensional and a 2-dimensional maximal cone and then display the incident cones:
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0,0],[0,1,0],[0,0,1],[-1,0,0]],INPUT_CONES=>[[0,1,2],[1,3]]);
# > print $f->MAXIMAL_CONES;
# | {0 1 2}
# | {1 3}
# > print $f->MAXIMAL_CONES_INCIDENCES;
# | <{1 2}
# | {0 2}
# | {0 1}
# | >
# | <{1}
# | {3}
# | >

property MAXIMAL_CONES_INCIDENCES : Array<IncidenceMatrix>;

rule MAXIMAL_CONES_INCIDENCES : ConesPerm.MAXIMAL_CONES_INCIDENCES, ConesPerm.PERMUTATION {
   $this->MAXIMAL_CONES_INCIDENCES=permuted($this->ConesPerm->MAXIMAL_CONES_INCIDENCES, $this->ConesPerm->PERMUTATION);
}
weight 1.10;

rule MAXIMAL_CONES_INCIDENCES : RaysPerm.MAXIMAL_CONES_INCIDENCES, RaysPerm.PERMUTATION {
  my $n_mc=scalar(@{$this->RaysPerm->MAXIMAL_CONES_INCIDENCES});
  my $mci=new Array<IncidenceMatrix>($n_mc);
  foreach my $i (0..$n_mc-1) {
      $mci->[$i]=permuted_cols($this->RaysPerm->MAXIMAL_CONES_INCIDENCES->[$i], $this->RaysPerm->PERMUTATION);
    }
  $this->MAXIMAL_CONES_INCIDENCES=$mci;
}
weight 1.10;

# @category Combinatorics
# The combinatorial dimensions of the [[MAXIMAL_CONES|maximal cones]].
# @example Here we construct a fan with a 3-dimensional and a 2-dimensional maximal cone, of which the latter contains lineality,
# and then display the corresponding combinatorial dimensions:
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0,0],[0,1,0],[0,0,1],[-1,0,0],[0,-1,0]],INPUT_CONES=>[[0,1,2],[1,3,4]]);
# > print $f->MAXIMAL_CONES;
# | {0 1 2}
# | {3}
# > print $f->MAXIMAL_CONES_COMBINATORIAL_DIMS;
# | 2 0

property MAXIMAL_CONES_COMBINATORIAL_DIMS : Array<Int>;

rule MAXIMAL_CONES_COMBINATORIAL_DIMS : ConesPerm.MAXIMAL_CONES_COMBINATORIAL_DIMS, ConesPerm.PERMUTATION {
   $this->MAXIMAL_CONES_COMBINATORIAL_DIMS=permuted($this->ConesPerm->MAXIMAL_CONES_COMBINATORIAL_DIMS, $this->ConesPerm->PERMUTATION);
}
weight 1.10;

# @category Combinatorics
# The combinatorial dimensions of the [[CONES|cones]].
property CONES_COMBINATORIAL_DIMS : Array<Int>;

rule CONES_COMBINATORIAL_DIMS : ConesPerm.CONES_COMBINATORIAL_DIMS, ConesPerm.PERMUTATION {
   $this->CONES_COMBINATORIAL_DIMS=permuted($this->ConesPerm->CONES_COMBINATORIAL_DIMS, $this->ConesPerm->PERMUTATION);
}
weight 1.10;


# @category Combinatorics
# The dimensions of the [[CONES|cones]].
# @return Array<Int>
user_method CONES_DIMS : FAN_DIM, CONES_COMBINATORIAL_DIMS {
    my $this=shift;
    my @mcd;
    my $cd=$this->COMBINATORIAL_DIM;
    my $d=0;
    if ( defined ($this->lookup( "RAYS | INPUT_RAYS | INPUT_LINEALITY | LINEALITY_SPACE | LINEALITY_DIM | FAN_DIM | FACET_NORMALS | ORTH_LINEALITY_SPACE" ) ) ) {
        $d=$this->FAN_DIM-$cd;
    }
    foreach (@{$this->CONES_COMBINATORIAL_DIMS}) {
        push @mcd, $_+$d;
    }
    return new Array<Int>(@mcd);
}


# @category Visualization
# Unique names assigned to the [[RAYS]].
# If specified, they are shown by visualization tools instead of vertex indices.
#
# For a polyhedral fan built from scratch, you should create this property by yourself,
# either manually in a text editor, or with a client program.
# @example The [[normal_fan|normal fan]] of the 2-cube has 4 rays; to assign the labels 'a', 'b' and 'any label' to the first
# three entries of [[RAYS]], do this (note that the unspecified label of the last ray is blank when visualizing, and that,
# depending on your visualization settings, not the whole string of the third label might be displayed):
# > $f = normal_fan(cube(2));
# > $f->RAY_LABELS=['a','b','any label'];

property RAY_LABELS : Array<String> : mutable;

rule RAY_LABELS : RaysPerm.RAY_LABELS, RaysPerm.PERMUTATION {
   $this->RAY_LABELS=permuted($this->RaysPerm->RAY_LABELS, $this->RaysPerm->PERMUTATION);
}
weight 1.10;

# @category Visualization
# Unique names assigned to the [[INPUT_RAYS]].  Similar to [[RAY_LABELS]] for [[RAYS]].

property INPUT_RAY_LABELS : Array<String> : mutable;

# @category Visualization
# Unique names assigned to the [[MAXIMAL_CONES]].  Similar to [[RAY_LABELS]] for [[RAYS]].

property MAXIMAL_CONE_LABELS : Array<String> : mutable;

# @category Combinatorics
# The poset of subcones of the polyhedral fan organized as a directed graph.
# Each node corresponds to some proper subcone of the fan.
# The nodes corresponding to the maximal cones appear in the same order
# as the elements of [[MAXIMAL_CONES]].
#
# One special node represents the origin and one special node represents the full fan
# (even if the fan only has one maximal cone).
# @example To compute the Hasse diagram of the [[normal_fan|normal fan]] of the 2-cube and display its
# decoration, we can do the following. Note the artificial node on top and the empty node at the bottom. The latter represents the trivial cone consisting only of the origin.
# > $h = normal_fan(cube(2))->HASSE_DIAGRAM;
# print $h->DECORATION;
# | ({-1} 3)
# | ({0 2} 2)
# | ({1 2} 2)
# | ({0 3} 2)
# | ({1 3} 2)
# | ({0} 1)
# | ({2} 1)
# | ({1} 1)
# | ({3} 1)
# | ({} 0)

property HASSE_DIAGRAM : Lattice<BasicDecoration> {

	method get_shift() {
		my $this = shift;
		return $this->parent->isa("fan::PolyhedralComplex") ? 1 : 0;
	}

   # @category Combinatorics
   # @return Int
   user_method dim {
		my $this = shift;
      return $this->rank() - $this->get_shift();
   }

   # @category Combinatorics
   # @param Int d dimension
   # @return Set<Int>
   user_method nodes_of_dim($) {
      my ($this,$d) = @_;
      return $this->nodes_of_rank($d + $this->get_shift());
   }

   # @category Combinatorics
   # @param Int d1 lower dimension
   # @param Int d1 upper dimension
   # @return Set<Int>
   user_method nodes_of_dim_range($,$) {
      my ($this,$d1,$d2) = @_;
		my $st = $this->get_shift();
      return shift->nodes_of_rank_range($d1+$st,$d2+$st);
   }

   method cones_of_dim($) {
      my ($this, $k) = @_;
      my $n = $this->nodes_of_rank(1)->size();
      my @rows = map { $this->DECORATION->[$_]->face } @{$this->nodes_of_rank($k)};
      return @rows ? new IncidenceMatrix(\@rows, $n) : new IncidenceMatrix(0, $n);
   }
                                                           
}

# @category Combinatorics
# f<sub>ik</sub> is the number of incident pairs of i-dimensional cones and k-dimensional cones; the main diagonal contains the [[F_VECTOR]].

property F2_VECTOR : Matrix<Integer>;


# @category Combinatorics
# f<sub>k</sub> is the number of k-dimensional cones starting from dimension k=1.
# The f-vector of a polytope and the f-vector of any of its [[face_fan|face fans]] coincide; for the 3-cube:
# > print face_fan(cube(3))->F_VECTOR;
# | 8 12 6

property F_VECTOR : Vector<Integer>;

# @category Combinatorics
# The polyhedral fan is __pure__ if all [[MAXIMAL_CONES|maximal cones]] are of the same dimension.
# @example Generating a fan from two distinct 2-dimensional cones gives a pure fan:
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0],[0,1],[-1,0],[0,-1]],INPUT_CONES=>[[0,1],[2,3]]);
# > print $f->PURE;
# | true
# @example Gnerating a fan from a 2-dimensional and a 1-dimensional cone results in the fan not being pure if the latter is a ray
# not contained in the former:
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,1],[-1,1],[0,-1]],INPUT_CONES=>[[0,1],[2]]);
# > print $f->PURE;
# | false

property PURE : Bool;

# @category Combinatorics
# The polyhedral fan is __complete__ if its suport is the whole space.
#
# Due to undecidability issues this is checked heuristically only.
# See the remarks on [[topaz::SimplicialComplex::SPHERE|SPHERE]] for details.
# Note that in the case of a polyhedral complex, this refers to the underlying fan, so should always be false.
# @example The [[normal_fan|normal fan]] of a polytope always is complete; here we see this for the 8-cube:
# > print normal_fan(cube(8))->COMPLETE;
# | true

property COMPLETE : Bool;


# @category Combinatorics
# The polyhedral fan is __simplicial__ if all [[MAXIMAL_CONES|maximal cones]] are [[Cone::SIMPLICIAL|simplicial]].
# @example The [[normal_fan|normal fan]] of a d-cube is __simplicial__; here we see this for the 3-cube:
# > print normal_fan(cube(3))->SIMPLICIAL;
# | true

property SIMPLICIAL : Bool;

# @category Geometry
# True if the fan is the [[normal_fan|normal fan]] of a [[Polytope::BOUNDED|bounded]] polytope.
# @example The [[face_fan|face fan]] of the centered d-dimensional cross polytope w.r.t. the origin 
# is the [[normal_fan|normal fan]] of the d-cube; here we confirm the regularity of the face fan for d=7:
# > print face_fan(cross(7))->REGULAR;
# | true
# @example A [[normal_fan|normal fan]] always is complete; thus a fan which is not complete can not be regular:
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0],[0,1]],INPUT_CONES=>[[0,1]]);
# > print $f->REGULAR;
# | false

property REGULAR : Bool;

# @category Geometry
# True if the fan is a subfan of a [[REGULAR]] fan
# @example Here we build a fan in the plane with the non-negative quadrant and the ray pointing in negative y-direction
# as its [[MAXIMAL_CONES|maximal cones]]. This is a subfan of the fan with all four quadrants as its maximal cones which is the
# [[normal_fan|normal fan]] of the 2-cube; thus, our fan is pseudo regular:
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0],[0,1],[-1,0]],INPUT_CONES=>[[0,1],[2]]);
# > print $f->PSEUDO_REGULAR;
# | true

property PSEUDO_REGULAR : Bool;

# @category Combinatorics
# The graph of the fan intersected with a sphere, that is,
# the vertices are the rays which are connected if they are
# contained in a common two-dimensional cone.
# @example The graph of a [[face_fan|face fan]] of a polytope is isomorphic to the vertex-edge graph of the polytope.
# Here we see this for the 3-cube:
# > $c = cube(3);
# > $f = face_fan($c);
# > $g1 = $f->GRAPH;
# > $g2 = $c->GRAPH;
# > print isomorphic($g1->ADJACENCY,$g2->ADJACENCY);
# | true

property GRAPH : Graph;

rule GRAPH.NodePerm.PERMUTATION = RaysPerm.PERMUTATION;

# @category Combinatorics
# The graph whose nodes are the maximal cones which
# are connected if they share a common facet.
# Only defined if [[PURE]].
# @example The dual graph of a [[face_fan|face fan]] of the 3-cube is isomorphic to the vertex-edge graph of the
# 3-dimensional cross polytope.
# > $c = cross(3);
# > $f = face_fan(cube(3));
# > $g1 = $f->DUAL_GRAPH;
# > $g2 = $c->GRAPH;
# > print isomorphic($g1->ADJACENCY,$g2->ADJACENCY);
# | true

property DUAL_GRAPH : Graph;

rule DUAL_GRAPH.NodePerm.PERMUTATION = ConesPerm.PERMUTATION;

# @category Geometry
# The possible facet normals of all maximal cones.
# @example The two facet normals of the complete fan dividing the plane into the four quadrants (which can be obtained by
# computing the [[normal_fan|normal fan]] of the 2-cube) point in x- and in y-direction, respectively:
# > print normal_fan(cube(2))->FACET_NORMALS;
# | 1 0
# | 0 1

property FACET_NORMALS : Matrix<Scalar>;

# @category Geometry
# The number of possible facet normals of all maximal cones.
# @example The facets of the [[normal_fan|normal fan]] of the 3-cube are each spanned by a ray pointing in positive or negative
# direction of one axis and another ray pointing in positive or negative direction of another axis; thus, the third axis
# is normal to this facet. This leaves us with three possible facet normals:
# > print normal_fan(cube(3))->N_FACET_NORMALS;
# | 3

property N_FACET_NORMALS : Int;

# @category Geometry
# Tells for each maximal cone what are its facet normals, thus implying the facets.
# Each row corresponds to a maximal cone and each column to the row with the same index of [[FACET_NORMALS]].
# A negative number means that the corresponding row of
# [[FACET_NORMALS]] has to be negated.
# @example The two facet normals of the complete fan dividing the plane into the four quadrants (which can be obtained by
# computing the [[normal_fan|normal fan]] of the 2-cube) point in x- and in y-direction, respectively. Each quadrant has both of these
# as normals only differing by the combination of how they point in- or outside:
# > $f = normal_fan(cube(2));
# > print $f->MAXIMAL_CONES;
# | {0 2}
# | {1 2}
# | {0 3}
# | {1 3}
# > print rows_numbered($f->FACET_NORMALS);
# | 0:1 0
# | 1:0 1
# > print $f->MAXIMAL_CONES_FACETS;
# | 1 1
# | -1 1
# | 1 -1
# | -1 -1

property MAXIMAL_CONES_FACETS : SparseMatrix<Int>;

rule MAXIMAL_CONES_FACETS : ConesPerm.MAXIMAL_CONES_FACETS, ConesPerm.PERMUTATION {
   $this->MAXIMAL_CONES_FACETS=permuted_rows($this->ConesPerm->MAXIMAL_CONES_FACETS, $this->ConesPerm->PERMUTATION);
}
weight 1.10;

# @category Geometry
# The possible linear span normals of all maximal cones.
# Empty if [[PURE]] and [[FULL_DIM]], i.e. each maximal cone has the same dimension as the ambient space.
# @example We construct a fan in 3-space with two 2-dimensional maximal cones and a 1-dimensional maximal cone. Note that
# there are two possible normals for the latter, but one of these also is a normal for one of the 2-dimensional cones; thus
# we receive three normals:
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0,0],[0,1,0],[-1,0,1],[-1,-1,0]],INPUT_CONES=>[[0,1],[1,2],[3]]);
# > print $f->LINEAR_SPAN_NORMALS;
# | 0 0 1
# | 1 0 1
# | -1 1 0

property LINEAR_SPAN_NORMALS : Matrix<Scalar>;

# @category Geometry
# Tells for each maximal cone what is its linear span by naming its normals.
# Indices refer to [[LINEAR_SPAN_NORMALS]].
# Rows correspond to [[MAXIMAL_CONES]].
# An empty row corresponds to a full-dimensional cone.
# @example We construct a fan in 3-space with two 2-dimensional maximal cones and a 1-dimensional maximal cone. This way
# we receive two cones with one normal and one cone with two normals:
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0,0],[0,1,0],[-1,0,1],[-1,-1,0]],INPUT_CONES=>[[0,1],[1,2],[3]]);
# > print $f->MAXIMAL_CONES;
# | {0 1}
# | {1 2}
# | {3}
# > print rows_numbered($f->LINEAR_SPAN_NORMALS);
# | 0:0 0 1
# | 1:1 0 1
# | 2:-1 1 0
# > print $f->MAXIMAL_CONES_LINEAR_SPAN_NORMALS;
# | {0}
# | {1}
# | {0 2}

property MAXIMAL_CONES_LINEAR_SPAN_NORMALS : IncidenceMatrix;

rule MAXIMAL_CONES_LINEAR_SPAN_NORMALS : LINEAR_SPAN_NORMALS, ConesPerm.MAXIMAL_CONES_LINEAR_SPAN_NORMALS, ConesPerm.PERMUTATION {
   if ($this->LINEAR_SPAN_NORMALS->rows) {
      $this->MAXIMAL_CONES_LINEAR_SPAN_NORMALS = permuted_rows($this->ConesPerm->MAXIMAL_CONES_LINEAR_SPAN_NORMALS, $this->ConesPerm->PERMUTATION);
   } else {
      # the linear span matrix is empty, nothing to permute
      $this->MAXIMAL_CONES_LINEAR_SPAN_NORMALS = $this->ConesPerm->MAXIMAL_CONES_LINEAR_SPAN_NORMALS;
   }
}
weight 1.10;

# @category Topology
# If the fan is [[SIMPLICIAL]] the simplicial complex obtained by intersecting
# the fan with the unit sphere.
# If the fan is not [[SIMPLICIAL]] the crosscut complex of the intersection.
# @example When intersecting, the [[normal_fan|normal fan]] of the 3-cube gives us a simplicial complex which is a topological 2-sphere:
# > $ic = normal_fan(cube(3))->INTERSECTION_COMPLEX;
# print $ic->SPHERE;
# | true

property INTERSECTION_COMPLEX : topaz::SimplicialComplex;


# @category Topology
# The homology of the intersection of the fan with the unit sphere.
# # @example When intersecting, the [[normal_fan|normal fan]] of the 3-cube gives us a simplicial complex which is a topological 2-sphere:
# > print normal_fan(cube(3))->HOMOLOGY;
# | ({} 0)
# | ({} 0)
# | ({} 1)

property HOMOLOGY : Array<topaz::HomologyGroup<Integer>>;

rule HOMOLOGY = INTERSECTION_COMPLEX.HOMOLOGY;

# @category Combinatorics
# Returns the //i//-th [[MAXIMAL_CONES|maximal cone]].
# @param Int i
# @return Cone
# @example To obtain the cone generated by the x-, y- and z-axis, we can take the first cone of the [[normal_fan|normal fan]] of
# the 3-cube:
# > $c = normal_fan(cube(3))->cone(0);
# > print $c->RAYS;
# | 1 0 0
# | 0 1 0
# | 0 0 1

user_method cone($) : MAXIMAL_CONES {
   my ($self,$i)=@_;
   my $c=new Cone<Scalar>;

   my $a_dim=$c->CONE_AMBIENT_DIM=$self->FAN_AMBIENT_DIM;
   if (defined(my $ls=$self->lookup("LINEALITY_SPACE"))) {
      $c->LINEALITY_SPACE=$ls;
   }
   if (defined(my $ld=$self->lookup("LINEALITY_DIM"))) {
      $c->LINEALITY_DIM=$ld;
   }
   if (defined(my $r=$self->lookup("RAYS")) and defined(my $mc=$self->lookup("MAXIMAL_CONES"))) {
      $c->RAYS=$r->minor($mc->[$i],All);
   }
   if (defined(my $mcf=$self->lookup("MAXIMAL_CONES_FACETS")) and defined(my $fn=$self->lookup("FACET_NORMALS"))) {
      my @facets;
      my $a=0;
      foreach (@{$mcf->row($i)}) {
         if($_!=0) {push(@facets,$_*$fn->row($a)); }
         ++$a;
      }
      $c->FACETS=\@facets;
   }
   if (defined(my $mclsn=$self->lookup("MAXIMAL_CONES_LINEAR_SPAN_NORMALS")) and defined(my $lsn=$self->lookup("LINEAR_SPAN_NORMALS"))) {
      if ($mclsn->rows==0) {
         $c->LINEAR_SPAN=new Matrix<Scalar>(0,$a_dim);
      }
      else {
         $c->LINEAR_SPAN=$lsn->minor($mclsn->[$i],All);
      }
   }
   if (defined(my $mci=$self->lookup("MAXIMAL_CONES_INCIDENCES"))) {
      $c->RAYS_IN_FACETS=$mci->[$i];
   }
   if (defined(my $mccd=$self->lookup("MAXIMAL_CONES_COMBINATORIAL_DIMS"))) {
      $c->COMBINATORIAL_DIM=$mccd->[$i];
   }
   if (defined(my $simp=$self->lookup("SIMPLICIAL"))) {
      if ($simp) {
         $c->SIMPLICIAL=$simp;
      }
   
      if (defined(my $pure=$self->lookup("PURE"))) {
         if ($pure) {
            if (defined(my $fd=$self->lookup("FAN_DIM"))) {
               $c->CONE_DIM=$fd;
            }
            if (defined(my $cd=$self->lookup("COMBINATORIAL_DIM"))) {
               $c->COMBINATORIAL_DIM=$cd;
            }
         }
      }
   }
   return $c;
}

# @category Combinatorics
# Returns an incidence matrix containing the cones of dimension //k//
# @param Int k
# @return IncidenceMatrix
# @example To obtain the 2-dimensional cones in the normal fan of the 3-cube, type
# > $c = normal_fan(cube(3));
# > print $c->cones_of_dim(2);
# | {2 4}
# | {0 4}
# | {0 2}
# | {1 4}
# | {1 2}
# | {3 4}
# | {0 3}
# | {1 3}
# | {2 5}
# | {0 5}
# | {1 5}
# | {3 5}

user_method cones_of_dim($) : HASSE_DIAGRAM {
    my ($self, $k) = @_;
    if ($k < 1) {
        croak("Need k>0");
    }
    my $d = $self->HASSE_DIAGRAM->rank;
    if ($k >= $d) {
        croak("Asking for cones of dimension $k is futile for a cone of combinatorial dimension $d");
    }
    return $self->HASSE_DIAGRAM->cones_of_dim($k);
}
                 
# @category Geometry
# Returns the dimension of the ambient space.
# @return Int
# @example The fan living in the plane containing only the cone which consists of the ray pointing in positive x-direction is
# by definition embedded in the plane:
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0]],INPUT_CONES=>[[0]]);
# > print $f->AMBIENT_DIM;
# | 2
user_method AMBIENT_DIM() : FAN_AMBIENT_DIM {
  my ($self)=@_;
  return $self->FAN_AMBIENT_DIM;
}

# @category Geometry
# Returns the dimension of the linear space spanned by the fan.
# @return Int
# @example The fan living in the plane containing only the cone which consists of the ray pointing in positive x-direction is
# 1-dimensional:
# > $f = new PolyhedralFan(INPUT_RAYS=>[[1,0]],INPUT_CONES=>[[0]]);
# > print $f->DIM;
# | 1

user_method DIM {
  my ($self)=@_;
  if (!defined ($self->lookup("LINEALITY_SPACE | INPUT_LINEALITY | INPUT_RAYS | RAYS | FACET_NORMALS | LINEAR_SPAN_NORMALS"))) {
    return $self->COMBINATORIAL_DIM;
 }
  return $self->FAN_DIM;
}

}

object topaz::HyperbolicSurface {
   
   # The secondary fan of the hyperbolic surface.
   # The k-th maximal cone corresponds to the Delaunay triangulation obtained by applying the k-th flip word of [[FLIP_WORDS]].
   # See M. Joswig, R. Löwe, and B. Springborn. Secondary fans and secondary polyhedra of punctured Riemann surfaces. arXiv:1708.08714.
   property SECONDARY_FAN : PolyhedralFan<Rational>;

   rule SECONDARY_FAN, FLIP_WORDS : DCEL, PENNER_COORDINATES {
      secondary_fan_and_flipwords($this);
   }

}


# Local Variables:
# mode: perl
# cperl-indent-level:3
# indent-tabs-mode:nil
# End: