# Discrete Subset¶

Digital geometry primitives

Subsets of ZZ^d with the edge relation +e_i and -e_i.

EXAMPLES:

sage: from slabbe import DiscreteSubset
sage: DiscreteSubset(dimension=2)
Subset of ZZ^2
sage: DiscreteSubset(dimension=4)
Subset of ZZ^4


A subset from an iterable:

sage: L = [(0,0,0,0), (1,0,0,0), (2,0,0,0), (3,0,0,0)]
sage: s = DiscreteSubset.from_subset(L)
sage: s
Subset of ZZ^4


A discrete 2d disk:

sage: D = DiscreteSubset(dimension=2, predicate=lambda p: p[0]^2 + p[1]^2 < 4)
sage: sorted(D.list())
[(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 0), (0, 1), (1, -1), (1, 0), (1, 1)]
sage: D
Subset of ZZ^2


A discrete 3d ball:

sage: predicate = lambda p: p[0]^2 + p[1]^2 + p[2]^2 <= 4
sage: D = DiscreteSubset(dimension=3, predicate=predicate)
sage: D
Subset of ZZ^3
sage: (0,0,0) in D
True
sage: (10,10,10) in D
False
sage: len(D.list())
33
sage: D.plot()    # optional long


A discrete 4d hyperplane:

sage: predicate = lambda p: 0 <= 2*p[0] + 3*p[1] + 4*p[2] + 5*p[3] < 14
sage: D = DiscreteSubset(dimension=4, predicate=predicate)
sage: D
Subset of ZZ^4
sage: D.an_element()
(0, 0, 0, 0)


A 2d discrete box:

sage: from slabbe import DiscreteBox
sage: b = DiscreteBox([-5,5], [-5,5])
sage: b
Box: [-5, 5] x [-5, 5]
sage: b.plot()       # optional long


A 3d discrete box:

sage: b = DiscreteBox([-2,2], [-5,5], [-5,5])
sage: b
Box: [-2, 2] x [-5, 5] x [-5, 5]
sage: b.plot()       # optional long


The intersection of two discrete objects of the same dimension:

sage: circ = DiscreteSubset(dimension=2, predicate=lambda p: p[0]^2+p[1]^2<=100)
sage: b = DiscreteBox([0,10], [0,10])
sage: I = circ & b
sage: I
Intersection of the following objects:
Subset of ZZ^2
[0, 10] x [0, 10]
sage: I.an_element()
(0, 0)
sage: I.plot()      # optional long


A discrete tube (preimage of a discrete box by a matrix):

sage: from slabbe import M3to2
sage: M3to2
[-0.866025403784439  0.866025403784439  0.000000000000000]
[-0.500000000000000 -0.500000000000000   1.00000000000000]
sage: from slabbe import DiscreteTube
sage: tube = DiscreteTube([-5,5],[-5,5], projmat=M3to2)
sage: tube
DiscreteTube: Preimage of [-5, 5] x [-5, 5] by a 2 by 3 matrix
sage: it = iter(tube)
sage: [next(it) for _ in range(4)]  # random
[(0, 0, 0), (1, 0, 0), (0, 0, 1), (0, 0, -1)]


TODO:

• Code Complement

• The method projection_matrix should be outside of the class?

• DiscreteTube should have a method projection_matrix

• Their should be an input saying whether the object is connected or not and what kind of neighbor connectedness

class slabbe.discrete_subset.DiscreteBox(*args)

Cartesian product of intervals.

INPUT:

• *args - intervals, lists of size two : [min, max]

EXAMPLES:

sage: from slabbe import DiscreteBox
sage: DiscreteBox([-5,5],[-5,5])
Box: [-5, 5] x [-5, 5]

sage: D = DiscreteBox([-3,3],[-3,3],[-3,3],[-3,3])
sage: next(iter(D))
(0, 0, 0, 0)


TESTS:

sage: d = DiscreteBox([-5,5], [-5,5], [-4,4])
sage: next(d.edges_iterator())
((0, 0, 0), (1, 0, 0))

clip(space=1)

Return a good clip rectangle for this box.

INPUT:

• space – number (default: 1), inner space within the box

EXAMPLES:

sage: from slabbe import DiscreteBox
sage: box = DiscreteBox([-6,6],[-6,6])
sage: box
Box: [-6, 6] x [-6, 6]
sage: box.clip()
[(-5, -5), (5, -5), (5, 5), (-5, 5), (-5, -5)]

sage: box = DiscreteBox([-6,6],[-4,3])
sage: box.clip()
[(-5, -3), (5, -3), (5, 2), (-5, 2), (-5, -3)]

class slabbe.discrete_subset.DiscreteSubset(dimension=3, predicate=None, edge_predicate=None, iterator=None, roots=None)

Bases: sage.structure.sage_object.SageObject

A subset of ZZ^d.

INPUT:

• dimension – integer, dimension of the space

• predicate – function ZZ^d -> {False, True} (default: None)

• edge_predicate – function ZZ^d,ZZ^d -> {False, True} (default: None)

• iterator – function (default: None) returning an iterator of points, it must be consistent with the predicate

• roots – list (default: None) of some elements in self. If iterator is not provided, it is used to iterate the elements throught connectedness.

EXAMPLES:

sage: from slabbe import DiscreteSubset
sage: DiscreteSubset(dimension=3)
Subset of ZZ^3

sage: p = DiscreteSubset(dimension=3, predicate=lambda x:True)
sage: p
Subset of ZZ^3

sage: fn = lambda p : p[0]+p[1]<p[2]
sage: p = DiscreteSubset(dimension=3, predicate=fn, roots=[(0,0,1)])
sage: p
Subset of ZZ^3

sage: F = lambda p: Integers(7)(2*p[0]+5*p[1])
sage: edge_predicate = lambda p,s: F(s) < F(s)
sage: D = DiscreteSubset(dimension=3, edge_predicate=edge_predicate)
sage: D
Subset of ZZ^3


From a list:

sage: L = [(0,0,0), (1,0,0), (2,0,0), (3,0,0)]
sage: s = DiscreteSubset.from_subset(L)
sage: s
Subset of ZZ^3


Providing a root may be necessary if zero (the origin) is not inside:

sage: predicate = lambda p : 4 < p[0]^2 + p[1]^2 < 25
sage: D = DiscreteSubset(dimension=2, predicate=predicate, roots=[(3,0)])


TESTS:

No edges go outside of the box:

sage: from slabbe import DiscreteBox
sage: B = DiscreteBox([-1,1],[-1,1])
sage: len(list(B.edges_iterator()))
12
sage: sorted(B.edges_iterator())
[((-1, -1), (-1, 0)), ((-1, -1), (0, -1)), ((-1, 0), (-1, 1)),
((-1, 0), (0, 0)), ((-1, 1), (0, 1)), ((0, -1), (0, 0)), ((0, -1),
(1, -1)), ((0, 0), (0, 1)), ((0, 0), (1, 0)), ((0, 1), (1, 1)),
((1, -1), (1, 0)), ((1, 0), (1, 1))]

an_element()

Returns an immutable element in self.

EXAMPLES:

sage: from slabbe import DiscreteSubset
sage: p = DiscreteSubset(dimension=3)
sage: p.an_element()
(0, 0, 0)
sage: p.an_element().is_immutable()
True

sage: predicate = lambda p : 4 < p[0]^2 + p[1]^2 < 25
sage: D = DiscreteSubset(dimension=2, predicate=predicate, roots=[(3,0)])
sage: D.an_element()
(3, 0)

base_edges()

Return a list of positive canonical vectors.

EXAMPLES:

sage: from slabbe import DiscreteSubset
sage: d = DiscreteSubset(dimension=2)
sage: d.base_edges()
[(1, 0), (0, 1)]

sage: from slabbe import DiscretePlane
sage: P = DiscretePlane([3,4,5], 12)
sage: P.base_edges()
[(1, 0, 0), (0, 1, 0), (0, 0, 1)]

children(p)

EXAMPLES:

sage: from slabbe import DiscretePlane
sage: p = DiscretePlane([1,pi,7], 1+pi+7, mu=0)
sage: list(p.children(vector((0,0,0))))
[(1, 0, 0), (0, 1, 0), (0, 0, 1)]

connected_component_iterator(roots=None)

Return an iterator over the connected component of the root.

INPUT:

• roots - list of some elements immutable in self

EXAMPLES:

sage: from slabbe import DiscreteSubset
sage: p = DiscreteSubset(dimension=3, roots=[(0,0,0)])
sage: it = p.connected_component_iterator()
sage: [next(it) for _ in range(5)]     # random
[(0, 0, 0), (1, 0, 0), (0, 0, 1), (0, 0, -1), (0, -1, 0)]

sage: from slabbe import DiscretePlane
sage: p = DiscretePlane([1,pi,7], 1+pi+7, mu=0)
sage: root = vector((0,0,0))
sage: root.set_immutable()
sage: it = p.connected_component_iterator(roots=[root])
sage: [next(it) for _ in range(5)]     # random
[(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1), (-1, 1, 0)]

d_neighbors(p, d=2)

Retourne le voisinage du point p, i.e. les points parmi les 3^d possible qui appartiennent a l’objet discret.

INPUT:

• p - un point discret

• d - integer (optional, default:2),

OUTPUT:

liste de points

EXAMPLES:

sage: from slabbe import DiscretePlane
sage: p = DiscretePlane([1,3,7], 10)
sage: p.d_neighbors((0,0,0))
[(-1, -1, 1), (-1, 0, 1), (-1, 1, 0), (-1, 1, 1), (0, -1, 1),
(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, -1, 1), (1, 0, 0), (1, 0,
1), (1, 1, 0)]

dimension()

Returns the dimension of the ambiant space.

OUTPUT:

integer

EXAMPLES:

sage: from slabbe import DiscreteSubset
sage: d = DiscreteSubset(dimension=3)
sage: d.dimension()
3

sage: from slabbe import DiscreteBox
sage: p = DiscreteBox([0,3], [0,3], [0,3], [0,3])
sage: p.dimension()
4

edges_iterator()

Returns an iterator over the pair of points in self that are adjacents, i.e. their difference is a canonical vector.

It considers only points that are connected to the given roots.

INPUT:

EXAMPLES:

sage: from slabbe import DiscretePlane
sage: p = DiscretePlane([1,pi,7], 1+pi+7, mu=0)
sage: it = p.edges_iterator()
sage: next(it)
((0, 0, 0), (1, 0, 0))
sage: next(it)
((0, 0, 0), (0, 1, 0))
sage: next(it)
((0, 0, 0), (0, 0, 1))
sage: next(it)         # random
((-1, 1, 0), (0, 1, 0))
sage: next(it)         # random
((-2, 1, 0), (-1, 1, 0))

classmethod from_subset(subset)

Constructor from a finite subset.

INPUT:

• subset – iterable of integer coordinate points

EXAMPLES:

sage: from slabbe import DiscreteSubset
sage: L = [(0,0,0), (1,0,0), (2,0,0), (3,0,0)]
sage: s = DiscreteSubset.from_subset(L)
sage: s
Subset of ZZ^3
sage: all(p in s for p in s)
True


Note that tuple or mutable vectors work fine:

sage: (0,0,0) in s
True
sage: vector((0,0,0)) in s
True


TESTS:

sage: DiscreteSubset.from_subset([])
Subset of ZZ^3

has_edge(p, s)

Returns whether it has the edge (p, s) where s-p is a canonical vector.

INPUT:

• p - point in the space

• s - point in the space

EXAMPLES:

sage: from slabbe import DiscreteSubset
sage: F = lambda p: Integers(7)(2*p[0]+5*p[1])
sage: edge_predicate = lambda p,s: F(p) < F(s)
sage: D = DiscreteSubset(dimension=3, edge_predicate=edge_predicate)
sage: D.has_edge(vector((0,0)),vector((1,0)))
True
sage: D.has_edge(vector((0,0)),vector((-1,0)))
True
sage: D.has_edge(vector((-1,1)),vector((1,0)))
False

level_iterator()

This returns an iterator of the levels according to the given roots.

EXAMPLES:

sage: from slabbe import DiscreteSubset
sage: p = DiscreteSubset(dimension=3, roots=[(0,0,0)])
sage: it = p.level_iterator()
sage: sorted(next(it))
[(0, 0, 0)]
sage: sorted(next(it))
[(-1, 0, 0), (0, -1, 0), (0, 0, -1), (0, 0, 1), (0, 1, 0), (1, 0, 0)]
sage: sorted(next(it))
[(-2, 0, 0),
(-1, -1, 0),
(-1, 0, -1),
(-1, 0, 1),
(-1, 1, 0),
(0, -2, 0),
(0, -1, -1),
(0, -1, 1),
(0, 0, -2),
(0, 0, 2),
(0, 1, -1),
(0, 1, 1),
(0, 2, 0),
(1, -1, 0),
(1, 0, -1),
(1, 0, 1),
(1, 1, 0),
(2, 0, 0)]

sage: from slabbe import DiscretePlane
sage: p = DiscretePlane([1,pi,7], 1+pi+7, mu=0)
sage: it = p.level_iterator()
sage: sorted(next(it))
[(0, 0, 0)]
sage: sorted(next(it))
[(0, 0, 1), (0, 1, 0), (1, 0, 0)]
sage: sorted(next(it))
[(-1, 0, 1),
(-1, 1, 0),
(0, -1, 1),
(0, 1, 1),
(0, 2, 0),
(1, 0, 1),
(1, 1, 0),
(2, 0, 0)]

list()

Return the list of elements in self.

EXAMPLES:

sage: from slabbe import DiscretePlane, DiscreteTube
sage: P = DiscretePlane([3,4,5], 12, mu=20)
sage: tube = DiscreteTube([0,2],[0,2])
sage: I = P & tube
sage: sorted(I.list())
[(-3, -1, -1), (-3, -1, 0), (-2, -2, -1), (-2, -2, 0), (-2, -1,
-1), (-2, -1, 0), (-2, 0, -1), (-1, -1, -1)]

plot(frame=False, edgecolor='blue', pointcolor='blue')

Return a plot (2d or 3d) of the points and edges of self.

INPUT:

• frame - (default: False) if True, draw a bounding frame with labels

• edgecolor – string (default: 'blue'), the color of the edges

• pointcolor – string (default: 'blue'), the color of the points

EXAMPLES:

2d example:

sage: from slabbe import DiscreteBox
sage: box = DiscreteBox([-5,5],[-5,5])
sage: box.plot() # optional long


3d example:

sage: from slabbe import DiscretePlane, DiscreteTube
sage: P = DiscretePlane([1,3,7], 11)
sage: tube = DiscreteTube([-5,5],[-5,5])
sage: I = P & tube
sage: I.plot() # optional long

plot_cubes(**kwds)

Returns the discrete object as cubes in 3d.

EXAMPLES:

sage: from slabbe import DiscretePlane, DiscreteTube
sage: P = DiscretePlane([3,4,5], 12, mu=20)
sage: tube = DiscreteTube([-5,5],[-5,5])
sage: I = P & tube
sage: I.plot_cubes(color='red', frame_thickness=1 # optional long)


TESTS:

sage: from slabbe import DiscreteBox
sage: box = DiscreteBox([-5,5],[-5,5])
sage: box.plot_cubes() # optional long
Traceback (most recent call last):
...
ValueError: this method is currently implemented only for objects living in 3 dimensions

plot_edges(color='blue', m=None)

Returns the mesh of the plane. The mesh is the union of segments joining two adjacents points.

INPUT:

• color – string (default: 'blue'), the color of the edges

• m – projection matrix (default: None), it can be one of the following:

• None - no projection is done

• 'isometric' - the isometric projection

• matrix - a 2 x 3 matrix

• 'belle' - shortcut for matrix(2, [1/3.0, 1, 0, 2/3.0, 0, 1])

• vector - defines the projection on the plane orthogonal to the vector.

EXAMPLES:

A 2d plot of a 2d object:

sage: from slabbe import DiscreteSubset, DiscreteBox
sage: D = DiscreteSubset(dimension=2)
sage: box = DiscreteBox([-5,5],[-5,5])
sage: I = D & box
sage: I.plot_edges(color='green') # optional long


A 3d plot of a 3d object:

sage: D = DiscreteSubset(dimension=3)
sage: box = DiscreteBox([-3,3],[-3,3],[-3,3])
sage: I = D & box
sage: I.plot_edges(color='green') # optional long


A 2d plot of a 3d object:

sage: D = DiscreteSubset(dimension=3)
sage: box = DiscreteBox([-3,3],[-3,3],[-3,3])
sage: I = D & box
sage: I.plot_edges(color='green', m='isometric') # optional long

plot_points(color='blue', m=None)

Returns a 2d or 3d graphics object of the points of self.

INPUT:

• color – string (default: 'blue'), the color of the points

• m – projection matrix (default: None), it can be one of the following:

• None - no projection is done

• 'isometric' - the isometric projection

• matrix - a 2 x n projection matrix

• 'belle' - shortcut for matrix(2, [1/3.0, 1, 0, 2/3.0, 0, 1])

• vector - defines the projection on the plane orthogonal to the vector.

EXAMPLES:

A 2d plot of a 2d object:

sage: from slabbe import DiscreteSubset, DiscreteBox
sage: D = DiscreteSubset(dimension=2)
sage: box = DiscreteBox([-5,5],[-5,5])
sage: I = D & box
sage: I.plot_points(color='green')      # optional long


A 3d plot of a 3d object:

sage: D = DiscreteSubset(dimension=3)
sage: box = DiscreteBox([-5,5],[-5,5],[-5,5])
sage: I = D & box
sage: I.plot_points(color='green')      # optional long


A 2d plot of a 3d object:

sage: D = DiscreteSubset(dimension=3)
sage: box = DiscreteBox([-5,5],[-5,5],[-5,5])
sage: I = D & box
sage: I.plot_points(color='green', m='isometric')      # optional long

plot_points_at_distance(k, color='blue', projmat=None)

Plot points at distance k from the roots.

INPUT:

• k - integer

EXAMPLES:

sage: alpha = solve(x+x**2+x**3==1, x)[2].right()
sage: vv = vector((alpha, alpha+alpha**2, 1))
sage: omega = (1+alpha)**2 / 2
sage: from slabbe import DiscretePlane
sage: Pr = DiscretePlane(vv, omega, mu=pi, prec=200)
sage: Pr.plot_points_at_distance(200)               # optional long
sage: Pr.plot_points_at_distance(200, projmat='isometric') # optional long

projection_matrix(m='isometric', oblique=None)

Return a projection matrix.

INPUT:

• m – projection matrix (default: 'isometric'), it can be one of the following:

• 'isometric' - the isometric projection is used by default

• matrix - a 2 x 3 matrix

• 'belle' - shortcut for matrix(2, [1/3.0, 1, 0, 2/3.0, 0, 1])

• vector - defines the projection on the plane orthogonal to the vector.

• oblique – vector (default: None), vector perpendicular to the range space

EXAMPLES:

sage: from slabbe import DiscreteSubset
sage: d = DiscreteSubset(dimension=3)
sage: d.projection_matrix(vector((2,3,4))) # tolerance 0.00001
[  1.00000000000000  0.000000000000000 -0.500000000000000]
[ 0.000000000000000   1.00000000000000 -0.750000000000000]
sage: d.projection_matrix((2,3,4)) # tolerance 0.00001
[  1.00000000000000  0.000000000000000 -0.500000000000000]
[ 0.000000000000000   1.00000000000000 -0.750000000000000]
sage: d.projection_matrix()         # tolerance 0.00001
[-0.866025403784  0.866025403784             0.0]
[           -0.5            -0.5             1.0]
sage: d.projection_matrix(_) # tolerance 0.00001
[-0.866025403784439  0.866025403784439  0.000000000000000]
[-0.500000000000000 -0.500000000000000   1.00000000000000]
sage: d.projection_matrix('belle')    # tolerance 0.00001
[0.333333333333            1.0            0.0]
[0.666666666667            0.0            1.0]

roots()

Return the roots, i.e., a list of elements in self.

It also makes sure the roots are in self and raises an error otherwise.

EXAMPLES:

sage: from slabbe import DiscreteSubset
sage: s = DiscreteSubset.from_subset([(0,0,0)])
sage: s.roots()
[(0, 0, 0)]

sage: predicate = lambda p : 4 < p[0]^2 + p[1]^2 < 25
sage: D = DiscreteSubset(dimension=2, predicate=predicate, roots=[(3,0)])
sage: D.roots()
[(3, 0)]


TESTS:

sage: predicate = lambda p : 4 < p[0]^2 + p[1]^2 < 25
sage: D = DiscreteSubset(dimension=2, predicate=predicate, roots=[(2,0)])
sage: D.roots()
Traceback (most recent call last):
...
ValueError: root element (=(2, 0)) provided at initialisation is not in self


An error is raised if the roots are inconsistent:

sage: s = DiscreteSubset.from_subset([])
sage: s.roots()
Traceback (most recent call last):
...
ValueError: default element (=(0, 0, 0)) is not in self, please provide one at initialisation

DiscreteSubset.tikz(projmat=[-0.866025403784439 0.866025403784439 0.000000000000000]
[-0.500000000000000 -0.500000000000000 1.00000000000000], scale=1, clip=[], contour=[], edges=True, points=True, axes=False, point_kwds={}, edge_kwds={}, axes_kwds={}, extra_code='')

INPUT:

• projmat – (default: M3to2) 2 x dim projection matrix where dim is the dimensoin of self, the isometric projection is used by default

• scale – real number (default: 1), scaling constant for the whole figure

• clip - list (default: []), list of points whose convex hull describes a cliping path

• contour - list (default: []), list of points describing a contour path to be drawn

• edges - bool (default: True), whether to draw edges

• points - bool (default: True), whether to draw points

• axes - bool (default: False), whether to draw axes

• point_kwds - dict (default: {})

• edge_kwds - dict (default: {})

• axes_kwds - dict (default: {})

• extra_code – string (default: ''), extra tikz code to add

EXAMPLES:

sage: from slabbe import DiscretePlane
sage: p = DiscretePlane([2,3,5], 10)
sage: t = p.tikz(points=False, edges=False)

tikz_axes(xshift=0, yshift=0, label='e', projmat='isometric')

Return the tikz code for drawing axes.

INPUT:

• xshift - integer (default: 0), x shift

• yshift - integer (default: 0), y shift

• label - string (default: "e"), label for base vectors

• projmat - matrix (default: 'isometric'), projection matrix

OUTPUT:

string

EXAMPLES:

2d example:

sage: from slabbe import DiscreteSubset
sage: d = DiscreteSubset(dimension=2)
sage: d.tikz_axes()
%the axes
\begin{scope}[xshift=0cm,yshift=0cm]
\draw[->,>=latex, very thick, blue] (0,0) -- (1, 0);
\draw[->,>=latex, very thick, blue] (0,0) -- (0, 1);
\node at (1.40000000000000,0) {$e_1$};
\node at (0,1.40000000000000) {$e_2$};
\end{scope}


3d example:

sage: d = DiscreteSubset(dimension=3)
sage: d.tikz_axes(projmat='isometric')
%the axes
\begin{scope}
[x={(-0.866025cm,-0.500000cm)}, y={(0.866025cm,-0.500000cm)},
z={(0.000000cm,1.000000cm)}, scale=1,xshift=0,yshift=0]
\draw[fill=white] (2,0,0) rectangle (-1.8,.1,1);
\draw[->,>=latex, very thick, blue] (0,0,0) -- (1, 0, 0);
\draw[->,>=latex, very thick, blue] (0,0,0) -- (0, 1, 0);
\draw[->,>=latex, very thick, blue] (0,0,0) -- (0, 0, 1);
\node at (1.40000000000000,0,0) {$e_1$};
\node at (0,1.40000000000000,0) {$e_2$};
\node at (0,0,1.40000000000000) {$e_3$};
\end{scope}

tikz_edges(style='very thick', color='blue', projmat=None)

Returns the mesh of the object. The mesh is the union of segments joining two adjacents points.

INPUT:

• style - string (default: 'dashed, very thick')

• color - string or callable (default: 'blue'), the color of all edges or a function : (u,v) -> color of the edge (u,v)

• projmat - matrix (default: None), projection matrix, if None, no projection is done.

EXAMPLES:

sage: from slabbe import DiscretePlane
sage: p = DiscretePlane([2,3,5], 4)
sage: p.tikz_edges()
\draw[very thick, blue] (0, 0, 0) -- (1, 0, 0);
\draw[very thick, blue] (0, 0, 0) -- (0, 1, 0);
\draw[very thick, blue] (-1, 1, 0) -- (0, 1, 0);

sage: p.tikz_edges(color='orange')
\draw[very thick, orange] (0, 0, 0) -- (1, 0, 0);
\draw[very thick, orange] (0, 0, 0) -- (0, 1, 0);
\draw[very thick, orange] (-1, 1, 0) -- (0, 1, 0);

sage: c = lambda u,v: 'red' if u == 0 else 'blue'
sage: p.tikz_edges(color=c)
\draw[very thick, red] (0, 0, 0) -- (1, 0, 0);
\draw[very thick, red] (0, 0, 0) -- (0, 1, 0);
\draw[very thick, blue] (-1, 1, 0) -- (0, 1, 0);

sage: from slabbe.discrete_subset import M3to2
sage: p.tikz_edges(projmat=M3to2)
\draw[very thick, blue] (0.00000, 0.00000) -- (-0.86603, -0.50000);
\draw[very thick, blue] (0.00000, 0.00000) -- (0.86603, -0.50000);
\draw[very thick, blue] (1.73205, 0.00000) -- (0.86603, -0.50000);

tikz_noprojection(projmat=None, scale=1, clip=[], edges=True, points=True, axes=False, point_kwds={}, edge_kwds={}, axes_kwds={}, extra_code='')

Return the tikz code of self.

In this version, the points are not projected. If the points are in 3d, the tikz 3d picture is used.

INPUT:

• projmat – (default: None) 2*3 projection matrix for drawing unit faces, the isometric projection is used by default

• scale – real number (default: 1), scaling constant for the whole figure

• clip - list (default: []), list of points describing a cliping path once projected. Works only if self.dimension() is 2.

• edges - bool (default: True), whether to draw edges

• points - bool (default: True), whether to draw points

• axes - bool (default: False), whether to draw axes

• point_kwds - dict (default: {})

• edge_kwds - dict (default: {})

• axes_kwds - dict (default: {})

• extra_code – string (default: ''), extra tikz code to add

EXAMPLES:

Object in 2d:

sage: from slabbe import DiscreteLine, DiscreteBox
sage: L = DiscreteLine([2,5], 2+5, mu=0)
sage: b = DiscreteBox([-5,5],[-5,5])
sage: I = L & b
sage: point_kwds = {'label':lambda p:2*p[0]+5*p[1],'label_pos':'above right'}
sage: tikz = I.tikz_noprojection(scale=0.5,point_kwds=point_kwds)
sage: tikz
\documentclass[tikz]{standalone}
\usepackage{amsmath}
\begin{document}
\begin{tikzpicture}
[scale=0.500000000000000]
\draw[very thick, blue] (0, 0) -- (1, 0);
\draw[very thick, blue] (0, 0) -- (0, 1);
\draw[very thick, blue] (2, 0) -- (3, 0);
...
... 40 lines not printed (2659 characters in total) ...
...
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at (-5, 2) {};
\node[above right] at (-5, 2) {$0$};
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at (-5, 3) {};
\node[above right] at (-5, 3) {$5$};
\end{tikzpicture}
\end{document}


Object in 3d:

sage: from slabbe import DiscretePlane, DiscreteTube
sage: p = DiscretePlane([1,3,7], 11)
sage: d = DiscreteTube([-5,5],[-5,5])
sage: I = p & d
sage: s = I.tikz_noprojection()
sage: s
\documentclass[tikz]{standalone}
\usepackage{amsmath}
\begin{document}
\begin{tikzpicture}
[x={(-0.866025cm,-0.500000cm)}, y={(0.866025cm,-0.500000cm)},
z={(0.000000cm,1.000000cm)}, scale=1]
\draw[very thick, blue] (0, 0, 0) -- (1, 0, 0);
\draw[very thick, blue] (0, 0, 0) -- (0, 1, 0);
...
... 311 lines not printed (20339 characters in total) ...
...
\end{tikzpicture}
\end{document}

tikz_points(size='0.8mm', label=None, label_pos='right', fill='black', options='', filter=None, projmat=None)

INPUT:

• size - string (default: '0.8mm'), size of the points

• label - function (default: None), print some label next to the point

• label_pos - function (default: 'right'), tikz label position

• fill - string (default: 'black'), fill color

• options - string (default: ''), author tikz node circle options

• filter - boolean function, if filter(p) is False, the point p is not drawn

• projmat - matrix (default: None), projection matrix, if None, no projection is done.

EXAMPLES:

sage: from slabbe import DiscreteBox
sage: p = DiscreteBox([0,3], [0,3], [0,3])
sage: s = p.tikz_points()
sage: lines = s.splitlines()
sage: lines[0]
'\\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at (...) {};'

sage: from slabbe import DiscretePlane, DiscreteTube
sage: p = DiscretePlane([1,3,7], 11)
sage: d = DiscreteTube([-1,1],[-1,1])
sage: I = p & d
sage: I.tikz_points()
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at (...) {};
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at (...) {};
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at (...) {};
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at (...) {};
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at (...) {};
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at (...) {};
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at (...) {};


Using a filter on the points:

sage: I.tikz_points(filter=lambda x:sum(x)==1)
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at (1, 0, 0) {};
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at (0, 1, 0) {};
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at (0, 0, 1) {};


Of a finite subset:

sage: from slabbe import DiscreteSubset
sage: V = [(0,0,0), (1,1,0), (1,-1,1), (-2,1,0), (2,0,1), (-1,2,0),
....:      (-1,0,1), (0,1,1)]
sage: s = DiscreteSubset.from_subset(V)
sage: s.tikz_points()
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at ... {};
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at ... {};
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at ... {};
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at ... {};
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at ... {};
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at ... {};
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at ... {};
\node[circle,fill=black,draw=black,minimum size=0.8mm,inner sep=0pt,] at ... {};

tikz_projection_scale(projmat='isometric', scale=1, extra='')

INPUT:

• projmat – (default: 'isometric') It can be one of the following:

• 'isometric' - the isometric projection is used by default

• matrix - a 2 x 3 matrix

• 'belle' - shortcut for matrix(2, [1/3.0, 1, 0, 2/3.0, 0, 1])

• vector - defines the projection on the plane orthogonal to the vector.

• scale – real number (default: 1), scaling constant for the whole figure

• extra – string (default: '')

EXAMPLES:

sage: from slabbe import DiscretePlane
sage: p = DiscretePlane([1,3,7], 11)
sage: p.tikz_projection_scale()
[x={(-0.866025cm,-0.500000cm)}, y={(0.866025cm,-0.500000cm)},
z={(0.000000cm,1.000000cm)}, scale=1]
sage: p.tikz_projection_scale(extra="xshift=4cm")
[x={(-0.866025cm,-0.500000cm)}, y={(0.866025cm,-0.500000cm)},
z={(0.000000cm,1.000000cm)}, scale=1,xshift=4cm]

DiscreteTube(projmat=[-0.866025403784439 0.866025403784439 0.000000000000000]
[-0.500000000000000 -0.500000000000000 1.00000000000000], *args, **kwds)

Discrete Tube (preimage of a box by a projection matrix)

Subset of a discrete object such that its projection by a matrix is inside a certain box.

INPUT:

• *args - intervals, lists of size two : [min, max]

• projmat - matrix (default: M3to2), projection matrix

EXAMPLES:

sage: from slabbe import DiscreteTube
sage: DiscreteTube([-5,5],[-5,5])
DiscreteTube: Preimage of [-5, 5] x [-5, 5] by a 2 by 3 matrix

sage: m = matrix(3,4,range(12))
sage: DiscreteTube([2,10],[3,4],[6,7], projmat=m)
DiscreteTube: Preimage of [2, 10] x [3, 4] x [6, 7] by a 3 by 4 matrix


EXAMPLES:

sage: from slabbe import DiscretePlane, DiscreteTube
sage: p = DiscretePlane([1,pi,7], 1+pi+7, mu=0)
sage: tube = DiscreteTube([-5,5],[-5,5])
sage: I = p & tube
sage: I
Intersection of the following objects:
Set of points x in ZZ^3 satisfying: 0 <= (1, pi, 7) . x + 0 < pi + 8
DiscreteTube: Preimage of [-5, 5] x [-5, 5] by a 2 by 3 matrix
sage: len(list(I))
115

DiscreteTube.clip(space=1)

Return a good clip rectangle for this box.

INPUT:

• space – number (default: 1), inner space within the box

EXAMPLES:

sage: from slabbe import DiscreteTube
sage: tube = DiscreteTube([-6,6],[-4,3])
sage: tube.clip()
[(-5, -3), (5, -3), (5, 2), (-5, 2), (-5, -3)]

class slabbe.discrete_subset.Intersection(objets)

Intersection

todo:

• Rendre l’heritage 3d automatique

INPUT:

• objets - un tuple d’objets discrets

EXAMPLES:

Intersection de deux plans:

sage: from slabbe import DiscretePlane, Intersection
sage: p = DiscretePlane([1,3,7],11)
sage: q = DiscretePlane([1,3,5],9)
sage: Intersection((p,q))
Intersection of the following objects:
Set of points x in ZZ^3 satisfying: 0 <= (1, 3, 7) . x + 0 < 11
Set of points x in ZZ^3 satisfying: 0 <= (1, 3, 5) . x + 0 < 9


Shortcut:

sage: p & q
Intersection of the following objects:
Set of points x in ZZ^3 satisfying: 0 <= (1, 3, 7) . x + 0 < 11
Set of points x in ZZ^3 satisfying: 0 <= (1, 3, 5) . x + 0 < 9


Intersection of a plane and a tube:

sage: from slabbe import DiscreteTube
sage: p = DiscretePlane([1,pi,7], 1+pi+7, mu=0)
sage: d = DiscreteTube([-5,5],[-5,5])
sage: I = p & d
sage: I
Intersection of the following objects:
Set of points x in ZZ^3 satisfying: 0 <= (1, pi, 7) . x + 0 < pi + 8
DiscreteTube: Preimage of [-5, 5] x [-5, 5] by a 2 by 3 matrix
sage: len(list(I))
115


Intersection of a line and a box:

sage: from slabbe import DiscreteLine, DiscreteBox
sage: L = DiscreteLine([2,5], 2+5, mu=0)
sage: b = DiscreteBox([-5,5],[-5,5])
sage: I = L & b
sage: I
Intersection of the following objects:
Set of points x in ZZ^2 satisfying: 0 <= (2, 5) . x + 0 < 7
[-5, 5] x [-5, 5]


TESTS:

Intersected objects must be of the same dimension:

sage: box = DiscreteBox([-5,5],[-5,5])
sage: p = DiscretePlane([1,pi,7], 1+pi+7)
sage: p & box
Traceback (most recent call last):
...
ValueError: Intersection not defined for objects not of the same dimension

an_element()

Returns an element in self.

EXAMPLES:

sage: from slabbe import DiscretePlane, DiscreteTube
sage: P = DiscretePlane([4,6,7], 17, mu=0)
sage: tube = DiscreteTube([-6.4, 6.4], [-5.2, 5.2])
sage: I = tube & P
sage: I.an_element()
(0, 0, 0)
sage: I.an_element() in I
True


TESTS:

sage: P = DiscretePlane([4,6,7], 17, mu=0)
sage: def contain(p): return 0 < P._v.dot_product(p) + P._mu <= P._omega
sage: P._predicate = contain
sage: tube = DiscreteTube([-6.4, 6.4], [-5.2, 5.2])
sage: I = tube & P
sage: I.an_element()
(0, 0, 0) not in the plane
trying similar points
(0, 0, 1)

has_edge(p, s)

Returns whether it has the edge (p, s) where s-p is a canonical vector.

INPUT:

• p - point in the space

• s - point in the space

EXAMPLES:

sage: from slabbe import DiscretePlane, DiscreteSubset
sage: d3 = DiscreteSubset(dimension=3)
sage: p = DiscretePlane([1,pi,7], 1+pi+7, mu=0)
sage: I = p & d3
sage: I.has_edge(vector((0,0,0)),vector((0,0,1)))
True
sage: I.has_edge(vector((0,0,0)),vector((0,0,-1)))
False


TESTS:

sage: from slabbe import DiscreteBox
sage: F = lambda p: (2*p[0]+5*p[1]) % 7
sage: edge_predicate = lambda p,s: F(p) < F(s)
sage: D = DiscreteSubset(dimension=2, edge_predicate=edge_predicate)
sage: b = DiscreteBox([-5,5],[-5,5])
sage: I = D & b
sage: all(I.has_edge(a,b) for a,b in I.edges_iterator())
True
sage: all(D.has_edge(a,b) for a,b in I.edges_iterator())
True

sage: from slabbe import ChristoffelGraph
sage: C = ChristoffelGraph((2,5))
sage: b = DiscreteBox([-5,5],[-5,5])
sage: I = C & b
sage: all(I.has_edge(a,b) for a,b in I.edges_iterator())
True
sage: all(C.has_edge(a,b) for a,b in I.edges_iterator())
True

roots()

EXAMPLES:

sage: from slabbe import DiscreteBox, DiscreteSubset
sage: d3 = DiscreteSubset(dimension=3, roots=[(0,0,0), (1,1,1)])
sage: box = DiscreteBox([-5,5],[-5,5],[-5,5])
sage: I = d3 & box
sage: sorted(d3.roots())
[(0, 0, 0), (1, 1, 1)]
sage: box.roots()
[(0, 0, 0)]
sage: sorted(I.roots())
[(0, 0, 0), (1, 1, 1)]

slabbe.discrete_subset.convex_boundary(L)

EXAMPLES:

sage: from slabbe.discrete_subset import convex_boundary
sage: convex_boundary([(3,4), (1,2), (3,5)])
[(3, 5), (1, 2), (3, 4)]