Piecewise affine transformations (PATs) and induced transformations¶
Piecewise affine transformations and induced transformations
EXAMPLES:
Recall how to create affine maps:
sage: F = AffineGroup(3, QQ); F
Affine Group of degree 3 over Rational Field
sage: M = matrix(QQ,[[1,2,3],[4,5,6],[7,8,0]])
sage: v = vector(QQ,[10,11,12])
sage: F(M, v)
[1 2 3] [10]
x |-> [4 5 6] x + [11]
[7 8 0] [12]
sage: F.linear(M)
[1 2 3] [0]
x |-> [4 5 6] x + [0]
[7 8 0] [0]
sage: F.translation(v)
[1 0 0] [10]
x |-> [0 1 0] x + [11]
[0 0 1] [12]
A polyhedron partition:
sage: from slabbe import PolyhedronPartition
sage: h = 1/3
sage: p = Polyhedron([(0,h),(0,1),(h,1)])
sage: q = Polyhedron([(0,0), (0,h), (h,1), (h,0)])
sage: r = Polyhedron([(h,1), (1,1), (1,h), (h,0)])
sage: s = Polyhedron([(h,0), (1,0), (1,h)])
sage: P = PolyhedronPartition({0:p, 1:q, 2:r, 3:s})
Inducing a piecewise affine transformation on a sub-domain:
sage: from slabbe import PolyhedronPartition
sage: from slabbe import PiecewiseAffineTransformation
sage: h = 1/3
sage: p = Polyhedron([(0,0),(0,1),(h,1),(h,0)])
sage: q = Polyhedron([(1,0), (1,1), (h,1), (h,0)])
sage: P = PolyhedronPartition({0:p, 1:q})
sage: F = AffineGroup(2, QQ)
sage: M = matrix(2, [0,1,1,0])
sage: f0 = F(M, (0, 2/3))
sage: f1 = F(M, (0, -1/3))
sage: T = PiecewiseAffineTransformation(P, {0:f0, 1:f1})
sage: ieq = [1/2, -1, 0] # x0 <= 1/2
sage: T_induced,sub = T.induced_transformation(ieq)
sage: T_induced.pp()
Piecewise Affine Transformation given by a
Polyhedron partition of 6 atoms with 6 letters
defined by 6 affine maps:
Affine map 0:
[0 1] [ 0]
x |-> [1 0] x + [2/3]
Affine map 1:
[0 1] [ 0]
x |-> [1 0] x + [-1/3]
Affine map 2:
[1 0] [-1/3]
x |-> [0 1] x + [-1/3]
Affine map 3:
[0 1] [-1/3]
x |-> [1 0] x + [ 1/3]
Affine map 4:
[1 0] [ 1/3]
x |-> [0 1] x + [-2/3]
Affine map 5:
[0 1] [-2/3]
x |-> [1 0] x + [ 0]
sage: sub
{0: [0], 1: [1], 2: [1, 1], 3: [0, 1, 1], 4: [0, 1, 1, 1], 5: [0, 1, 1, 1, 1]}
AUTHORS:
Sébastien Labbé, January 2019, added a class for polyhedron exchange transformations
Sébastien Labbé, September 15, 2023, translated PET into piecewise affine transformations
- class slabbe.piecewise_affine_transformation.PiecewiseAffineTransformation(partition, affine_maps, affine_group=None)¶
Bases:
object
Piecewise Affine Transformation (PAT).
INPUT:
partition
– a polyhedron partition (with associated indices)affine_maps
– list or dict, associating each index with an affine mapaffine_group
– affine group (default:None
), the affine group in which the affine maps live. IfNone
, it takes the parent of the first affine map as default value.
EXAMPLES:
Create Polyhedron partition:
sage: from slabbe import PolyhedronPartition sage: h = 1/3 sage: p = Polyhedron([(0,0),(0,1),(h,1),(h,0)]) sage: q = Polyhedron([(1,0), (1,1), (h,1), (h,0)]) sage: P = PolyhedronPartition({0:p, 1:q})
Create affine maps:
sage: F = AffineGroup(2, QQ) sage: M = matrix(2, [0,1,1,0]) sage: f0 = F(M, (0, 2/3)) sage: f1 = F(M, (0, -1/3))
Create a piecewise affine transformation:
sage: from slabbe import PiecewiseAffineTransformation sage: T = PiecewiseAffineTransformation(P, {0:f0, 1:f1})
TESTS:
Works with general indices:
sage: P = PolyhedronPartition({'a':p, 'b':q}) sage: T = PiecewiseAffineTransformation(P, {'a':f0, 'b':f1})
- affine_group()¶
EXAMPLES:
sage: from slabbe import PolyhedronPartition sage: from slabbe import PiecewiseAffineTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(0,1),(h,1),(h,0)]) sage: q = Polyhedron([(1,0), (1,1), (h,1), (h,0)]) sage: P = PolyhedronPartition({0:p, 1:q}) sage: F = AffineGroup(2, QQ) sage: M = matrix(2, [0,1,1,0]) sage: f0 = F(M, (0, 2/3)) sage: f1 = F(M, (0, -1/3)) sage: T = PiecewiseAffineTransformation(P, {0:f0, 1:f1}) sage: T.affine_group() Affine Group of degree 2 over Rational Field
- affine_maps()¶
EXAMPLES:
sage: from slabbe import PolyhedronPartition sage: from slabbe import PiecewiseAffineTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(0,1),(h,1),(h,0)]) sage: q = Polyhedron([(1,0), (1,1), (h,1), (h,0)]) sage: P = PolyhedronPartition({0:p, 1:q}) sage: F = AffineGroup(2, QQ) sage: M = matrix(2, [0,1,1,0]) sage: f0 = F(M, (0, 2/3)) sage: f1 = F(M, (0, -1/3)) sage: T = PiecewiseAffineTransformation(P, {0:f0, 1:f1}) sage: d = T.affine_maps() sage: type(d) <class 'dict'>
- ambient_space()¶
EXAMPLES:
sage: from slabbe import PolyhedronPartition sage: from slabbe import PiecewiseAffineTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(0,1),(h,1),(h,0)]) sage: q = Polyhedron([(1,0), (1,1), (h,1), (h,0)]) sage: P = PolyhedronPartition({0:p, 1:q}) sage: F = AffineGroup(2, QQ) sage: M = matrix(2, [0,1,1,0]) sage: f0 = F(M, (0, 2/3)) sage: f1 = F(M, (0, -1/3)) sage: T = PiecewiseAffineTransformation(P, {0:f0, 1:f1}) sage: T.ambient_space() Vector space of dimension 2 over Rational Field
This code also handle PETs:
sage: from slabbe import PolyhedronExchangeTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(h,0),(h,1),(0,1)]) sage: q = Polyhedron([(1,0),(h,0),(h,1),(1,1)]) sage: P = PolyhedronPartition({0:p, 1:q}) sage: T = {0:(1-h,0), 1:(-h,0)} sage: F = PolyhedronExchangeTransformation(P, T) sage: F.ambient_space() Vector space of dimension 2 over Rational Field
- cylinder(word, partition=None)¶
Return the region associated to the coding word.
INPUT:
word
– listpartition
– polyhedron partition (default:None
), if None, it uses the domain partition of the transformation
OUTPUT:
polyhedron partition
EXAMPLES:
sage: from slabbe import PolyhedronPartition sage: from slabbe import PiecewiseAffineTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(0,1),(h,1),(h,0)]) sage: q = Polyhedron([(1,0), (1,1), (h,1), (h,0)]) sage: P = PolyhedronPartition({0:p, 1:q}) sage: F = AffineGroup(2, QQ) sage: M = matrix(2, [0,1,1,0]) sage: f0 = F(M, (0, 2/3)) sage: f1 = F(M, (0, -1/3)) sage: T = PiecewiseAffineTransformation(P, {0:f0, 1:f1}) sage: c = T.cylinder([0,1,1]); c Polyhedron partition of 1 atoms with 1 letters sage: c.volume() 2/9 sage: T.cylinder([0,1,1,1,1,0]).volume() 1/9 sage: T.cylinder([0,1,1,1,1,1]).volume() 0
Cylinders of words of length 0:
sage: T.cylinder([], P).volume() 1
Cylinders of words of length 1:
sage: C1 = [T.cylinder([a], P).volume() for a in range(3)] sage: C1 [1/3, 2/3, 0] sage: sum(C1) 1
Cylinders of words of length 2:
sage: import itertools sage: L2 = itertools.product(range(3),repeat=2) sage: C2 = [T.cylinder([a,b], P).volume() for (a,b) in L2] sage: C2 [1/9, 2/9, 0, 2/9, 4/9, 0, 0, 0, 0] sage: sum(C2) 1
Cylinders of words of length 3:
sage: L3 = itertools.product(range(3),repeat=3) sage: C3 = [T.cylinder([a,b,c], P).volume() for (a,b,c) in L3] sage: sum(C3) 1
It also works for PETs:
sage: from slabbe import PolyhedronPartition sage: h = 1/2 sage: p = Polyhedron([(0,h),(0,1),(h,1)]) sage: q = Polyhedron([(0,0), (0,h), (h,1), (1,1), (1,h), (h,0)]) sage: r = Polyhedron([(h,0), (1,0), (1,h)]) sage: P = PolyhedronPartition([p,q,r])
sage: from slabbe import PolyhedronExchangeTransformation as PET sage: base = identity_matrix(2) sage: translation = vector((1/3, 0)) sage: u = PET.toral_translation(base, translation) sage: c = u.cylinder([2,2], P); c Polyhedron partition of 1 atoms with 1 letters sage: c.alphabet() {0} sage: u.cylinder([1,1], P) Polyhedron partition of 2 atoms with 2 letters sage: u.cylinder([1], P) Polyhedron partition of 1 atoms with 1 letters sage: u.cylinder([], P).volume() 1 sage: C1 = [u.cylinder([a], P).volume() for a in range(3)] sage: C1 [1/8, 3/4, 1/8] sage: sum(C1) 1 sage: import itertools sage: L2 = itertools.product(range(3),repeat=2) sage: C2 = [u.cylinder([a,b], P).volume() for (a,b) in L2] sage: C2 [1/72, 1/9, 0, 1/9, 19/36, 1/9, 0, 1/9, 1/72] sage: sum(C2) 1 sage: L3 = itertools.product(range(3),repeat=3) sage: C3 = [u.cylinder([a,b,c], P).volume() for (a,b,c) in L3] sage: sum(C3) 1
TESTS:
sage: u.cylinder([0,0,0], P) Polyhedron partition of 0 atoms with 0 letters sage: u.cylinder([2,3], P) Polyhedron partition of 0 atoms with 0 letters sage: u.cylinder([2,1], P) Polyhedron partition of 1 atoms with 1 letters sage: u.cylinder([], P) Polyhedron partition of 3 atoms with 3 letters
- cylinders(size, partition=None)¶
Return the cylinders of given size.
INPUT:
size
– nonnegative integerpartition
– polyhedron partition (default:None
), if None, it uses the domain partition of the transformation
OUTPUT:
polyhedron partition
EXAMPLES:
sage: from slabbe import PolyhedronPartition sage: from slabbe import PiecewiseAffineTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(0,1),(h,1),(h,0)]) sage: q = Polyhedron([(1,0), (1,1), (h,1), (h,0)]) sage: P = PolyhedronPartition({0:p, 1:q}) sage: F = AffineGroup(2, QQ) sage: M = matrix(2, [0,1,1,0]) sage: f0 = F(M, (0, 2/3)) sage: f1 = F(M, (0, -1/3)) sage: T = PiecewiseAffineTransformation(P, {0:f0, 1:f1}) sage: [T.cylinders(i) for i in range(5)] [Polyhedron partition of 1 atoms with 1 letters, Polyhedron partition of 2 atoms with 2 letters, Polyhedron partition of 4 atoms with 4 letters, Polyhedron partition of 6 atoms with 6 letters, Polyhedron partition of 9 atoms with 9 letters] sage: [T.cylinders(i).alphabet() for i in range(5)] [{()}, {0, 1}, {0, 1, 2, 3}, {0, 1, 2, 3, 4, 5}, {0, 1, 2, 3, 4, 5, 6, 7, 8}]
The code works also for PETs:
sage: from slabbe import PolyhedronExchangeTransformation as PET sage: base = identity_matrix(2) sage: translation = vector((1/3, 0)) sage: u = PET.toral_translation(base, translation) sage: [u.cylinders(i) for i in range(5)] [Polyhedron partition of 1 atoms with 1 letters, Polyhedron partition of 2 atoms with 2 letters, Polyhedron partition of 3 atoms with 3 letters, Polyhedron partition of 3 atoms with 3 letters, Polyhedron partition of 3 atoms with 3 letters] sage: [u.cylinders(i).alphabet() for i in range(5)] [{()}, {0, 1}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}]
- domain()¶
Return the domain of the transformation.
OUTPUT:
a polyhedron
EXAMPLES:
sage: from slabbe import PolyhedronPartition sage: from slabbe import PiecewiseAffineTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(0,1),(h,1),(h,0)]) sage: q = Polyhedron([(1,0), (1,1), (h,1), (h,0)]) sage: P = PolyhedronPartition({0:p, 1:q}) sage: F = AffineGroup(2, QQ) sage: M = matrix(2, [0,1,1,0]) sage: f0 = F(M, (0, 2/3)) sage: f1 = F(M, (0, -1/3)) sage: T = PiecewiseAffineTransformation(P, {0:f0, 1:f1}) sage: T.domain() A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices sage: T.domain().vertices() (A vertex at (0, 0), A vertex at (0, 1), A vertex at (1, 0), A vertex at (1, 1))
This code also handle PETs:
sage: from slabbe import PolyhedronExchangeTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(h,0),(h,1),(0,1)]) sage: q = Polyhedron([(1,0),(h,0),(h,1),(1,1)]) sage: P = PolyhedronPartition({0:p, 1:q}) sage: T = {0:(1-h,0), 1:(-h,0)} sage: F = PolyhedronExchangeTransformation(P, T) sage: F.domain() A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices sage: F.domain().vertices() (A vertex at (0, 0), A vertex at (0, 1), A vertex at (1, 0), A vertex at (1, 1))
- image_partition()¶
Return the partition of the image.
EXAMPLES:
sage: from slabbe import PolyhedronPartition sage: from slabbe import PiecewiseAffineTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(0,1),(h,1),(h,0)]) sage: q = Polyhedron([(1,0), (1,1), (h,1), (h,0)]) sage: P = PolyhedronPartition({0:p, 1:q}) sage: F = AffineGroup(2, QQ) sage: M = matrix(2, [0,1,1,0]) sage: f0 = F(M, (0, 2/3)) sage: f1 = F(M, (0, -1/3)) sage: T = PiecewiseAffineTransformation(P, {0:f0, 1:f1}) sage: T.image_partition() Polyhedron partition of 2 atoms with 2 letters
It works also for PETs:
sage: from slabbe import PolyhedronPartition, PolyhedronExchangeTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(h,0),(h,1),(0,1)]) sage: q = Polyhedron([(1,0),(h,0),(h,1),(1,1)]) sage: P = PolyhedronPartition({0:p, 1:q}) sage: T = {0:(1-h,0), 1:(-h,0)} sage: F = PolyhedronExchangeTransformation(P, T) sage: F.image_partition() Polyhedron partition of 2 atoms with 2 letters
sage: h = 1/3 sage: p = Polyhedron([(0,h),(0,1),(h,1)]) sage: q = Polyhedron([(0,0), (0,h), (h,1), (h,0)]) sage: r = Polyhedron([(h,1), (1,1), (1,h), (h,0)]) sage: s = Polyhedron([(h,0), (1,0), (1,h)]) sage: P = PolyhedronPartition([(0,p), (0,q), (1,r), (1,s)]) sage: T = {0:(1-h,0), 1:(-h,0)} sage: F = PolyhedronExchangeTransformation(P, T) sage: F.image_partition() Polyhedron partition of 4 atoms with 2 letters
- induced_partition(ieq, partition=None, substitution_type='dict', ignore_volume=0, verbose=False)¶
Returns the partition of the induced transformation on the domain.
INPUT:
ieq
– list, an inequality. An entry equal to “[-1,7,3,4]” represents the inequality 7x_1+3x_2+4x_3>= 1.partition
– polyhedron partition (default:None
), if None, it uses the domain partition of the transformationsubstitution_type
– string (default:'dict'
), if'column'
or'row'
, it returns a substitution2d, otherwise it returns a dict.ignore_volume
– real (optional:0
), stop the while loop if the volume of what’s not yet returned is less than the given thresholdverbose
– bool (optional:False
), print verbose information
OUTPUT:
a polyhedron partition
a substitution2d or a dict
EXAMPLES:
sage: from slabbe import PolyhedronExchangeTransformation as PET sage: base = identity_matrix(2) sage: translation = vector((1/3, 0)) sage: u = PET.toral_translation(base, translation)
We compute the induced partition of a polyhedron exchange transformation on a subdomain given by an inequality:
sage: ieq = [1/3, -1, 0] # x0 <= 1/3 sage: u.induced_partition(ieq) (Polyhedron partition of 1 atoms with 1 letters, {0: [0, 0, 1]}) sage: ieq = [1/2, -1, 0] # x0 <= 1/2 sage: u.induced_partition(ieq) (Polyhedron partition of 3 atoms with 3 letters, {0: [0], 1: [0, 1], 2: [0, 0, 1]})
The second output can be turned into a column or a row Substitution2d if desired:
sage: u.induced_partition(ieq, substitution_type='row') (Polyhedron partition of 3 atoms with 3 letters, Substitution 2d: {0: [[0]], 1: [[0], [1]], 2: [[0], [0], [1]]})
Now we construct a another coding partition:
sage: from slabbe import PolyhedronPartition sage: h = 1/3 sage: p = Polyhedron([(0,h),(0,1),(h,1)]) sage: q = Polyhedron([(0,0), (0,h), (h,1), (h,0)]) sage: r = Polyhedron([(h,1), (1,1), (1,h), (h,0)]) sage: s = Polyhedron([(h,0), (1,0), (1,h)]) sage: P = PolyhedronPartition({0:p, 1:q, 2:r, 3:s})
We use this other partition to compute the induced partition:
sage: ieq = [h, -1, 0] # x0 <= h sage: Q,sub = u.induced_partition(ieq, P) sage: Q Polyhedron partition of 4 atoms with 4 letters sage: sub {0: [0, 2, 2], 1: [1, 2, 2], 2: [1, 2, 3], 3: [1, 3, 3]}
sage: P = PolyhedronPartition({0:p, 1:q, 2:r, 3:s}) sage: ieq2 = [1/2, -1, 0] # x0 <= 1/2 sage: Q,sub = u.induced_partition(ieq2, P) sage: Q Polyhedron partition of 9 atoms with 9 letters sage: sub {0: [0], 1: [1], 2: [2, 2], 3: [2, 3], 4: [3, 3], 5: [0, 2, 2], 6: [1, 2, 2], 7: [1, 2, 3], 8: [1, 3, 3]}
Irrationnal rotations:
sage: z = polygen(QQ, 'z') #z = QQ['z'].0 # same as sage: K = NumberField(z**2-z-1, 'phi', embedding=RR(1.6)) sage: phi = K.gen() sage: h = 1/phi^2 sage: p = Polyhedron([(0,h),(0,1),(h,1)]) sage: q = Polyhedron([(0,0), (0,h), (h,1), (h,0)]) sage: r = Polyhedron([(h,1), (1,1), (1,h), (h,0)]) sage: s = Polyhedron([(h,0), (1,0), (1,h)]) sage: P = PolyhedronPartition({0:p, 1:q, 2:r, 3:s}, base_ring=K) sage: base = identity_matrix(2) sage: translation = vector((1/phi, 0)) sage: u = PET.toral_translation(base, translation) sage: ieq = [h, -1, 0] # x0 <= h sage: P1,sub01 = u.induced_partition(ieq, P) sage: P1 Polyhedron partition of 7 atoms with 7 letters sage: sub01 {0: [0, 2], 1: [1, 2], 2: [1, 3], 3: [0, 2, 2], 4: [1, 2, 2], 5: [1, 3, 2], 6: [1, 3, 3]}
We do the induction on a smaller domain:
sage: ieq2 = [1/phi^3, -1, 0] # x0 <= h sage: P2,sub02 = u.induced_partition(ieq2, P) sage: P2 Polyhedron partition of 10 atoms with 10 letters sage: sub02 {0: [0, 2, 2], 1: [1, 2, 2], 2: [1, 3, 2], 3: [1, 3, 3], 4: [0, 2, 0, 2, 2], 5: [0, 2, 1, 2, 2], 6: [1, 2, 1, 2, 2], 7: [1, 2, 1, 3, 2], 8: [1, 3, 1, 3, 2], 9: [1, 3, 1, 3, 3]}
We check that inductions commute:
sage: base = diagonal_matrix((phi^-2,1)) sage: translation = vector((phi^-3, 0)) sage: u1 = PET.toral_translation(base, translation) sage: P2_alt,sub12 = u1.induced_partition(ieq2, P1) sage: P2_alt Polyhedron partition of 10 atoms with 10 letters sage: P2_alt == P2 True
Up to a permutation of the alphabet,
sub02
andsub01*sub12
are equal:sage: s01 = WordMorphism(sub01) sage: s12 = WordMorphism(sub12) sage: s02 = WordMorphism(sub02) sage: s02 WordMorphism: 0->022, 1->122, 2->132, 3->133, 4->02022, 5->02122, 6->12122, 7->12132, 8->13132, 9->13133 sage: s01*s12 == s02 True
By chance, the above is true, but in general, we have:
sage: perm = WordMorphism(P2.keys_permutation(P2_alt)) sage: perm WordMorphism: 0->0, 1->1, 2->2, 3->3, 4->4, 5->5, 6->6, 7->7, 8->8, 9->9 sage: s01*s12*perm == s02 True
- induced_transformation(ieq, ignore_volume=0, verbose=False)¶
Return the induced transformation on the domain.
INPUT:
ieq
– list, an inequality. An entry equal to “[-1,7,3,4]” represents the inequality 7x_1+3x_2+4x_3>= 1.ignore_volume
– real (optional:0
), stop the while loop if the volume of what’s not yet returned is less than the given thresholdverbose
– bool (optional:False
), print verbose information
OUTPUT:
a polyhedron exchange transformation on the subdomain
a substitution (dict)
EXAMPLES:
sage: from slabbe import PolyhedronPartition sage: from slabbe import PiecewiseAffineTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(0,1),(h,1),(h,0)]) sage: q = Polyhedron([(1,0), (1,1), (h,1), (h,0)]) sage: P = PolyhedronPartition({0:p, 1:q}) sage: F = AffineGroup(2, QQ) sage: M = matrix(2, [0,1,1,0]) sage: f0 = F(M, (0, 2/3)) sage: f1 = F(M, (0, -1/3)) sage: T = PiecewiseAffineTransformation(P, {0:f0, 1:f1}) sage: ieq = [1/2, -1, 0] # x0 <= 1/2 sage: T_induced,sub = T.induced_transformation(ieq) sage: T_induced.pp() Piecewise Affine Transformation given by a Polyhedron partition of 6 atoms with 6 letters defined by 6 affine maps: Affine map 0: [0 1] [ 0] x |-> [1 0] x + [2/3] Affine map 1: [0 1] [ 0] x |-> [1 0] x + [-1/3] Affine map 2: [1 0] [-1/3] x |-> [0 1] x + [-1/3] Affine map 3: [0 1] [-1/3] x |-> [1 0] x + [ 1/3] Affine map 4: [1 0] [ 1/3] x |-> [0 1] x + [-2/3] Affine map 5: [0 1] [-2/3] x |-> [1 0] x + [ 0] sage: sub {0: [0], 1: [1], 2: [1, 1], 3: [0, 1, 1], 4: [0, 1, 1, 1], 5: [0, 1, 1, 1, 1]}
- inverse()¶
Return the inverse of self.
EXAMPLES:
sage: from slabbe import PolyhedronPartition sage: from slabbe import PiecewiseAffineTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(0,1),(h,1),(h,0)]) sage: q = Polyhedron([(1,0), (1,1), (h,1), (h,0)]) sage: P = PolyhedronPartition({0:p, 1:q}) sage: F = AffineGroup(2, QQ) sage: M = matrix(2, [0,1,1,0]) sage: f0 = F(M, (0, 2/3)) sage: f1 = F(M, (0, -1/3)) sage: T = PiecewiseAffineTransformation(P, {0:f0, 1:f1}) sage: T.pp() Piecewise Affine Transformation given by a Polyhedron partition of 2 atoms with 2 letters defined by 2 affine maps: Affine map 0: [0 1] [ 0] x |-> [1 0] x + [2/3] Affine map 1: [0 1] [ 0] x |-> [1 0] x + [-1/3] sage: T.inverse().pp() Piecewise Affine Transformation given by a Polyhedron partition of 2 atoms with 2 letters defined by 2 affine maps: Affine map 0: [0 1] [-2/3] x |-> [1 0] x + [ 0] Affine map 1: [0 1] [1/3] x |-> [1 0] x + [ 0]
- merge_atoms_with_same_transformation()¶
Return a new partition into convex polyhedrons where atoms mapped by the same transformation are merged if their union is convex.
EXAMPLES:
sage: from slabbe import PolyhedronPartition sage: from slabbe import PiecewiseAffineTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(0,1),(h,1),(h,0)]) sage: q = Polyhedron([(1,1/2), (1,1), (h,1), (h,1/2)]) sage: r = Polyhedron([(1,0), (1,1/2), (h,1/2), (h,0)]) sage: P = PolyhedronPartition({0:p, 1:q, 2:r}) sage: F = AffineGroup(2, QQ) sage: M = matrix(2, [0,1,1,0]) sage: f0 = F(M, (0, 2/3)) sage: f1 = F(M, (0, -1/3)) sage: T = PiecewiseAffineTransformation(P, {0:f0, 1:f1, 2:f1}) sage: T Piecewise Affine Transformation of Polyhedron partition of 3 atoms with 3 letters defined by 3 affine maps sage: T.merge_atoms_with_same_transformation() Piecewise Affine Transformation of Polyhedron partition of 2 atoms with 2 letters defined by 2 affine maps
- partition()¶
EXAMPLES:
sage: from slabbe import PolyhedronPartition sage: from slabbe import PiecewiseAffineTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(0,1),(h,1),(h,0)]) sage: q = Polyhedron([(1,0), (1,1), (h,1), (h,0)]) sage: P = PolyhedronPartition({0:p, 1:q}) sage: F = AffineGroup(2, QQ) sage: M = matrix(2, [0,1,1,0]) sage: f0 = F(M, (0, 2/3)) sage: f1 = F(M, (0, -1/3)) sage: T = PiecewiseAffineTransformation(P, {0:f0, 1:f1}) sage: T.partition() Polyhedron partition of 2 atoms with 2 letters
This code also handle PETs:
sage: from slabbe import PolyhedronExchangeTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(h,0),(h,1),(0,1)]) sage: q = Polyhedron([(1,0),(h,0),(h,1),(1,1)]) sage: P = PolyhedronPartition({0:p, 1:q}) sage: d = {0:(1-h,0), 1:(-h,0)} sage: T = PolyhedronExchangeTransformation(P, d) sage: T.partition() Polyhedron partition of 2 atoms with 2 letters
- plot()¶
Return a image representating the domain and image partition side-to-side.
EXAMPLES:
sage: from slabbe import PolyhedronPartition sage: from slabbe import PiecewiseAffineTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(0,1),(h,1),(h,0)]) sage: q = Polyhedron([(1,0), (1,1), (h,1), (h,0)]) sage: P = PolyhedronPartition({0:p, 1:q}) sage: F = AffineGroup(2, QQ) sage: M = matrix(2, [0,1,1,0]) sage: f0 = F(M, (0, 2/3)) sage: f1 = F(M, (0, -1/3)) sage: T = PiecewiseAffineTransformation(P, {0:f0, 1:f1}) sage: T.plot() Graphics Array of size 1 x 2
Title is still placed correctly if size of domain changes:
sage: (5*T).plot() Graphics Array of size 1 x 2
This code also works for PETs:
sage: from slabbe import PolyhedronExchangeTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(h,0),(h,1),(0,1)]) sage: q = Polyhedron([(1,0),(h,0),(h,1),(1,1)]) sage: P = PolyhedronPartition({0:p, 1:q}) sage: d = {0:(1-h,0), 1:(-h,0)} sage: T = PolyhedronExchangeTransformation(P, d) sage: T.plot() Graphics Array of size 1 x 2
- pp()¶
Pretty print
EXAMPLES:
sage: from slabbe import PolyhedronPartition sage: from slabbe import PiecewiseAffineTransformation sage: h = 1/3 sage: p = Polyhedron([(0,0),(0,1),(h,1),(h,0)]) sage: q = Polyhedron([(1,0), (1,1), (h,1), (h,0)]) sage: P = PolyhedronPartition({0:p, 1:q}) sage: F = AffineGroup(2, QQ) sage: M = matrix(2, [0,1,1,0]) sage: f0 = F(M, (0, 2/3)) sage: f1 = F(M, (0, -1/3)) sage: T = PiecewiseAffineTransformation(P, {0:f0, 1:f1}) sage: T.pp() Piecewise Affine Transformation given by a Polyhedron partition of 2 atoms with 2 letters defined by 2 affine maps: Affine map 0: [0 1] [ 0] x |-> [1 0] x + [2/3] Affine map 1: [0 1] [ 0] x |-> [1 0] x + [-1/3]