# Ticket #12090: trac_12090-review.patch

File trac_12090-review.patch, 17.8 KB (added by hthomas, 8 years ago)
• ## sage/geometry/pseudolines.py

# HG changeset patch
# User hthomas@unb.ca
# Date 1369014625 10800
# Node ID 756a267710a5463b85054d8c1cf3f5f964b6de2d
# Parent  f398269b85eab62ff1c22230a6def24e5ca76dbb
implement pseudo-line arrangements (review patch)

diff --git a/sage/geometry/pseudolines.py b/sage/geometry/pseudolines.py
 a Pseudolines This module gathers everything that has to do with pseudolines, and for a start a :class:PseudolinesArrangement class that can be used to describe an a :class:PseudolineArrangement class that can be used to describe an arrangement of pseudolines in several different ways, and to translate one description into another, as well as to display *Wiring diagrams* via the :meth:show  method. :meth:show  method. In the following, we try to stick to the terminology given in [Felsner]_, which can be checked in case of doubt. And please fix this module's documentation x-monotone curve in the plane. A *set* of pseudolines, however, represents a set of such curves that pairwise intersect exactly once (and hence mimic the behaviour of straight lines in general position). We also assume that those pseudolines are in general position, that is that no three of them cross on the pseudolines are in general position, that is that no three of them cross at the same point. The present class is made to deal with a combinatorial encoding of a pseudolines l_0, ..., l_{n-1} crosses the n-1 other lines. .. WARNING:: It is assumed through all the methods that the given lines are numbered consistently : it is not possible that the first transposition be (0,2) according to their y-coordinate on the vertical line x=-\infty. For instance, it is not possible that the first transposition be (0,2) (or equivalently that the first line l_0 crosses is l_2 and conversely), for it would mean that one of them cuts l_1. It is actually assumed that the pseudolines are numbered according to their y-coordinate on the vertical line x=-\infty. because one of them would have to cross l_1 first. Encodings ---------- **Permutations** An arrangement of pseudolines can be described by a sequence of n lists of length n-1, where the i list is a permutation of \{1, ..., n\} \backslash length n-1, where the i list is a permutation of \{0, ..., n-1\} \backslash i representing the ordering in which the i th pseudoline meets the other ones. :: sage: from sage.geometry.pseudolines import PseudolinesArrangement sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] sage: p = PseudolinesArrangement(permutations) sage: p sage: p = PseudolineArrangement(permutations) sage: p Arrangement of pseudolines of size 4 sage: p.show() transposition (2,3) appears before (8, 2) iif l_2 crosses l_3 before it crosses l_8. This encoding is easy to obtain by reading the wiring diagram from left to right (see the :meth:show  method).  method). :: sage: from sage.geometry.pseudolines import PseudolinesArrangement sage: from sage.geometry.pseudolines import PseudolineArrangement sage: transpositions = [(3, 2), (3, 1), (0, 3), (2, 1), (0, 2), (0, 1)] sage: p = PseudolinesArrangement(transpositions) sage: p sage: p = PseudolineArrangement(transpositions) sage: p Arrangement of pseudolines of size 4 sage: p.show() transpositions, it is sufficient to look for occurrences of \begin{array}{c}0\\1\end{array} in the first column of the matrix, as it corresponds in the wiring diagram to a line going up while the line immediately above it does down -- those two lines cross. Each time such a pattern is found above it goes down -- those two lines cross. Each time such a pattern is found it yields a new transposition, and the matrix can be updated so that this pattern disappears. A more detailed description of this algorithm is given in [Felsner]_. :: sage: from sage.geometry.pseudolines import PseudolinesArrangement sage: from sage.geometry.pseudolines import PseudolineArrangement sage: felsner_matrix = [[0, 0, 0], [0, 0, 1], [0, 1, 1], [1, 1, 1]] sage: p = PseudolinesArrangement(felsner_matrix) sage: p = PseudolineArrangement(felsner_matrix) sage: p Arrangement of pseudolines of size 4 sage: print l[:5]                            # not tested [(96, 278.0130613051349), (74, 332.92512282478714), (13, 155.65820951249867), (209, 34.753946221755307), (147, 193.51376457741441)] sage: l.sort() sage: n = len(l) We can now compute for each i the order in which line i meet the other lines:: We can now compute for each i the order in which line i meets the other lines:: sage: permutations = [[0..i-1]+[i+1..n-1] for i in range(n)] sage: a = lambda x : l[x][0] sage: b = lambda x : l[x][1] sage: for i, perm in enumerate(permutations): ...       perm.sort(key = lambda j : (b(j)-b(i))/(a(i)-a(j))) ....:     perm.sort(key = lambda j : (b(j)-b(i))/(a(i)-a(j))) And finally build the line arrangement:: sage: from sage.geometry.pseudolines import PseudolinesArrangement sage: p = PseudolinesArrangement(permutations) sage: from sage.geometry.pseudolines import PseudolineArrangement sage: p = PseudolineArrangement(permutations) sage: print p Arrangement of pseudolines of size 20 sage: p.show(figsize=[20,8]) from copy import deepcopy class PseudolinesArrangement: class PseudolineArrangement: def __init__(self, seq, encoding = "auto"): r""" * The pseudolines are assumed to be integers 0..(n-1). * For more information on the different encodings, see the :mod:pseudolimes module 's :mod:pseudolines module 's documentation. TESTS: From permutations:: sage: from sage.geometry.pseudolines import PseudolinesArrangement sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] sage: PseudolinesArrangement(permutations) sage: PseudolineArrangement(permutations) Arrangement of pseudolines of size 4 From transpositions :: sage: from sage.geometry.pseudolines import PseudolinesArrangement sage: from sage.geometry.pseudolines import PseudolineArrangement sage: transpositions = [(3, 2), (3, 1), (0, 3), (2, 1), (0, 2), (0, 1)] sage: PseudolinesArrangement(transpositions) sage: PseudolineArrangement(transpositions) Arrangement of pseudolines of size 4 From a Felsner matrix:: sage: from sage.geometry.pseudolines import PseudolinesArrangement sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] sage: p = PseudolinesArrangement(permutations) sage: p = PseudolineArrangement(permutations) sage: matrix = p.felsner_matrix() sage: PseudolinesArrangement(matrix) == p sage: PseudolineArrangement(matrix) == p True TESTS: Wrong input:: sage: PseudolinesArrangement([[5, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]]) sage: PseudolineArrangement([[5, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]]) Traceback (most recent call last): ... ValueError: Are the lines really numbered from 0 to n-1 ? sage: PseudolinesArrangement([(3, 2), (3, 1), (0, 3), (2, 1), (0, 2)]) ValueError: Are the lines really numbered from 0 to n-1? sage: PseudolineArrangement([(3, 2), (3, 1), (0, 3), (2, 1), (0, 2)]) Traceback (most recent call last): ... ValueError: A line is numbered with 3but the number of transpositions ... ValueError: A line is numbered 3 but the number of transpositions ... """ # Sequence of transpositions if (encoding == "transpositions" or if (encoding == "transpositions" or (encoding == "auto" and len(seq[0]) == 2 and len(seq) > 3)): self._n = max(map(max, seq)) + 1 self._n = max(map(max, seq)) + 1 if (self._n * (self._n-1))/2 != len(seq): raise ValueError( "A line is numbered with "+str(self._n-1)+"but the number "+ "of transpositions is different from binomial("+ str(self._n-1)+",2). Are the lines numbered from 0 to n-1 ?"+ "Are they really non-parallel ? Please check the documentation.") "A line is numbered "+str(self._n-1)+" but the number"+ " of transpositions is different from binomial("+ str(self._n-1)+",2). Are the lines numbered from 0 to n-1?"+ " Are they really non-parallel? Please check the documentation.") self._permutations = [[] for i in range(self._n)] self._permutations[j].append(i) # Sequence of permutations elif (encoding == "permutations" or elif (encoding == "permutations" or (encoding == "auto" and (len(seq[0]) == len(seq)-1) and max(seq[0]) > 1)): self._n = len(seq) self._permutations = deepcopy(seq) if max(map(max, seq)) != self._n -1 : raise ValueError("Are the lines really numbered from 0 to n-1 ?") raise ValueError("Are the lines really numbered from 0 to n-1?") # Felsner encoding elif (encoding == "Felsner" or elif (encoding == "Felsner" or (encoding == "auto" and len(seq[0]) == len(seq) -1)): seq = deepcopy(seq) seq[i+1][0] == 1)): crossings -= 1 self._permutations[ordering[i]].append(ordering[i+1]) self._permutations[ordering[i+1]].append(ordering[i]) ordering[i], ordering[i+1] = ordering[i+1], ordering[i] seq[i], seq[i+1] = seq[i+1], seq[i] seq[i].pop(0) seq[i+1].pop(0) if i > 0 and seq[i-1] is not []: i -= 1 elif seq[i] is not []: i += 1 else: i += 1 else: i += 1 else: if encoding != "auto": raise ValueError("The value of encoding must be one of 'transpositions', 'permutations', 'Felsner' or 'auto'.") raise ValueError("The encoding you use could not be guessed. Your input string is probably badly formatted, or you have less than 3 lines and we can make no diffence between the encoding. Please specify the encoding you used.") raise ValueError("The encoding you used could not be guessed. Your input string is probably badly formatted, or you have at most 3 lines and we cannot distinguish the encoding. Please specify the encoding you used.") def transpositions(self): r""" Returns the arrangement as \binom n 2 transpositions. See the :mod:pseudolimes module 's See the :mod:pseudolines module 's documentation for more information on this encoding. EXAMPLE:: sage: from sage.geometry.pseudolines import PseudolinesArrangement sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] sage: p1 = PseudolinesArrangement(permutations) sage: p1 = PseudolineArrangement(permutations) sage: transpositions = [(3, 2), (3, 1), (0, 3), (2, 1), (0, 2), (0, 1)] sage: p2 = PseudolinesArrangement(transpositions) sage: p2 = PseudolineArrangement(transpositions) sage: p1 == p2 True sage: p1.transpositions() if max(map(len,perm)) != 0: raise ValueError("There has been an error while computing the transpositions.") return t def permutations(self): r""" Returns the arrangements as n permutations of size n-1. See the :mod:pseudolimes module 's See the :mod:pseudolines module 's documentation for more information on this encoding. EXAMPLE:: sage: from sage.geometry.pseudolines import PseudolinesArrangement sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] sage: p = PseudolinesArrangement(permutations) sage: p = PseudolineArrangement(permutations) sage: p.permutations() [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] """ r""" Returns a Felsner matrix describing the arrangement. See the :mod:pseudolimes module 's See the :mod:pseudolines module 's documentation for more information on this encoding. EXAMPLE:: sage: from sage.geometry.pseudolines import PseudolinesArrangement sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] sage: p = PseudolinesArrangement(permutations) sage: p = PseudolineArrangement(permutations) sage: p.felsner_matrix() [[0, 0, 0], [0, 0, 1], [0, 1, 1], [1, 1, 1]] """ r""" Displays the pseudoline arrangement as a wiring diagram. INPUT: INPUT: - **args -- any arguments to be forwarded to the show method. In particular, to tune the dimensions, use the figsize argument EXAMPLE:: sage: from sage.geometry.pseudolines import PseudolinesArrangement sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] sage: p = PseudolinesArrangement(permutations) sage: p = PseudolineArrangement(permutations) sage: p.show(figsize=[7,5]) TESTS:: sage: from sage.geometry.pseudolines import PseudolinesArrangement sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 0, 1], [2, 0, 1]] sage: p = PseudolinesArrangement(permutations) sage: p = PseudolineArrangement(permutations) sage: p.show() Traceback (most recent call last): ... lines[j].append((x+2,iy)) x += 2 L = line([(1,1)]) for i, l in enumerate(lines): l.append((x+2, l[-1][1])) L += line(l) L += text(str(i), (0, l[0][1]+.3)) L += text(str(i), (x+2, l[-1][1]+.3)) L += text(str(i), (0, l[0][1]+.3), horizontal_alignment="right") L += text(str(i), (x+2, l[-1][1]+.3), horizontal_alignment="left") return L.show(axes = False, **args) def __repr__(self): r""" A short txt description of the pseudolines arrangement. A short txt description of the pseudoline arrangement. EXAMPLE:: sage: from sage.geometry.pseudolines import PseudolinesArrangement sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] sage: p = PseudolinesArrangement(permutations) sage: p = PseudolineArrangement(permutations) sage: p Arrangement of pseudolines of size 4 """ TEST:: sage: from sage.geometry.pseudolines import PseudolinesArrangement sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] sage: p1 = PseudolinesArrangement(permutations) sage: p1 = PseudolineArrangement(permutations) sage: transpositions = [(3, 2), (3, 1), (0, 3), (2, 1), (0, 2), (0, 1)] sage: p2 = PseudolinesArrangement(transpositions) sage: p2 = PseudolineArrangement(transpositions) sage: p1 == p2 True True """ return (self._n == other._n) and (self._permutations == other._permutations)