# HG changeset patch
# User hthomas@unb.ca
# Date 1369014625 10800
# Node ID 756a267710a5463b85054d8c1cf3f5f964b6de2d
# Parent f398269b85eab62ff1c22230a6def24e5ca76dbb
implement pseudoline arrangements (review patch)
diff git a/sage/geometry/pseudolines.py b/sage/geometry/pseudolines.py
a

b


2  2  Pseudolines 
3  3  
4  4  This module gathers everything that has to do with pseudolines, and for a start 
5   a :class:`PseudolinesArrangement` class that can be used to describe an 
 5  a :class:`PseudolineArrangement` class that can be used to describe an 
6  6  arrangement of pseudolines in several different ways, and to translate one 
7  7  description into another, as well as to display *Wiring diagrams* via the 
8   :meth:`show <sage.geometry.pseudolines.PseudolinesArrangement.show>` method. 
 8  :meth:`show <sage.geometry.pseudolines.PseudolineArrangement.show>` method. 
9  9  
10  10  In the following, we try to stick to the terminology given in [Felsner]_, which 
11  11  can be checked in case of doubt. And please fix this module's documentation 
… 
… 

17  17  `x`monotone curve in the plane. A *set* of pseudolines, however, represents a 
18  18  set of such curves that pairwise intersect exactly once (and hence mimic the 
19  19  behaviour of straight lines in general position). We also assume that those 
20   pseudolines are in general position, that is that no three of them cross on the 
 20  pseudolines are in general position, that is that no three of them cross at the 
21  21  same point. 
22  22  
23  23  The present class is made to deal with a combinatorial encoding of a pseudolines 
… 
… 

25  25  `l_0, ..., l_{n1}` crosses the `n1` other lines. 
26  26  
27  27  .. WARNING:: 
28   
 28  
29  29  It is assumed through all the methods that the given lines are numbered 
30   consistently : it is not possible that the first transposition be ``(0,2)`` 
 30  according to their `y`coordinate on the vertical line `x=\infty`. 
 31  For instance, it is not possible that the first transposition be ``(0,2)`` 
31  32  (or equivalently that the first line `l_0` crosses is `l_2` and conversely), 
32   for it would mean that one of them cuts `l_1`. It is actually assumed that 
33   the pseudolines are numbered according to their `y`coordinate on the 
34   vertical line `x=\infty`. 
 33  because one of them would have to cross `l_1` first. 
35  34  
36  35  Encodings 
37  36   
… 
… 

39  38  **Permutations** 
40  39  
41  40  An arrangement of pseudolines can be described by a sequence of `n` lists of 
42   length `n1`, where the `i` list is a permutation of `\{1, ..., n\} \backslash 
 41  length `n1`, where the `i` list is a permutation of `\{0, ..., n1\} \backslash 
43  42  i` representing the ordering in which the `i` th pseudoline meets the other 
44  43  ones. 
45  44  
46  45  :: 
47  46  
48   sage: from sage.geometry.pseudolines import PseudolinesArrangement 
 47  sage: from sage.geometry.pseudolines import PseudolineArrangement 
49  48  sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] 
50   sage: p = PseudolinesArrangement(permutations) 
51   sage: p 
 49  sage: p = PseudolineArrangement(permutations) 
 50  sage: p 
52  51  Arrangement of pseudolines of size 4 
53  52  sage: p.show() 
54  53  
… 
… 

59  58  transposition `(2,3)` appears before `(8, 2)` iif `l_2` crosses `l_3` before it 
60  59  crosses `l_8`. This encoding is easy to obtain by reading the wiring diagram 
61  60  from left to right (see the :meth:`show 
62   <sage.geometry.pseudolines.PseudolinesArrangement.show>` method). 
 61  <sage.geometry.pseudolines.PseudolineArrangement.show>` method). 
63  62  
64  63  :: 
65  64  
66   sage: from sage.geometry.pseudolines import PseudolinesArrangement 
 65  sage: from sage.geometry.pseudolines import PseudolineArrangement 
67  66  sage: transpositions = [(3, 2), (3, 1), (0, 3), (2, 1), (0, 2), (0, 1)] 
68   sage: p = PseudolinesArrangement(transpositions) 
69   sage: p 
 67  sage: p = PseudolineArrangement(transpositions) 
 68  sage: p 
70  69  Arrangement of pseudolines of size 4 
71  70  sage: p.show() 
72  71  
… 
… 

107  106  transpositions, it is sufficient to look for occurrences of 
108  107  `\begin{array}{c}0\\1\end{array}` in the first column of the matrix, as it 
109  108  corresponds in the wiring diagram to a line going up while the line immediately 
110   above it does down  those two lines cross. Each time such a pattern is found 
 109  above it goes down  those two lines cross. Each time such a pattern is found 
111  110  it yields a new transposition, and the matrix can be updated so that this 
112  111  pattern disappears. A more detailed description of this algorithm is given in 
113  112  [Felsner]_. 
114  113  
115  114  :: 
116  115  
117   sage: from sage.geometry.pseudolines import PseudolinesArrangement 
 116  sage: from sage.geometry.pseudolines import PseudolineArrangement 
118  117  sage: felsner_matrix = [[0, 0, 0], [0, 0, 1], [0, 1, 1], [1, 1, 1]] 
119   sage: p = PseudolinesArrangement(felsner_matrix) 
 118  sage: p = PseudolineArrangement(felsner_matrix) 
120  119  sage: p 
121  120  Arrangement of pseudolines of size 4 
122  121  
… 
… 

133  132  sage: print l[:5] # not tested 
134  133  [(96, 278.0130613051349), (74, 332.92512282478714), (13, 155.65820951249867), (209, 34.753946221755307), (147, 193.51376457741441)] 
135  134  sage: l.sort() 
136   sage: n = len(l) 
137  135  
138   We can now compute for each `i` the order in which line `i` meet the other lines:: 
 136  We can now compute for each `i` the order in which line `i` meets the other lines:: 
139  137  
140  138  sage: permutations = [[0..i1]+[i+1..n1] for i in range(n)] 
141  139  sage: a = lambda x : l[x][0] 
142  140  sage: b = lambda x : l[x][1] 
143  141  sage: for i, perm in enumerate(permutations): 
144   ... perm.sort(key = lambda j : (b(j)b(i))/(a(i)a(j))) 
 142  ....: perm.sort(key = lambda j : (b(j)b(i))/(a(i)a(j))) 
145  143  
146  144  And finally build the line arrangement:: 
147  145  
148   sage: from sage.geometry.pseudolines import PseudolinesArrangement 
149   sage: p = PseudolinesArrangement(permutations) 
 146  sage: from sage.geometry.pseudolines import PseudolineArrangement 
 147  sage: p = PseudolineArrangement(permutations) 
150  148  sage: print p 
151  149  Arrangement of pseudolines of size 20 
152  150  sage: p.show(figsize=[20,8]) 
… 
… 

175  173  
176  174  from copy import deepcopy 
177  175  
178   class PseudolinesArrangement: 
 176  class PseudolineArrangement: 
179  177  
180  178  def __init__(self, seq, encoding = "auto"): 
181  179  r""" 
… 
… 

200  198  * The pseudolines are assumed to be integers `0..(n1)`. 
201  199  
202  200  * For more information on the different encodings, see the 
203   :mod:`pseudolimes module <sage.geometry.pseudolines>`'s 
 201  :mod:`pseudolines module <sage.geometry.pseudolines>`'s 
204  202  documentation. 
205   
 203  
206  204  TESTS: 
207  205  
208  206  From permutations:: 
209   
210   sage: from sage.geometry.pseudolines import PseudolinesArrangement 
 207  
 208  sage: from sage.geometry.pseudolines import PseudolineArrangement 
211  209  sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] 
212   sage: PseudolinesArrangement(permutations) 
 210  sage: PseudolineArrangement(permutations) 
213  211  Arrangement of pseudolines of size 4 
214  212  
215  213  From transpositions :: 
216  214  
217   sage: from sage.geometry.pseudolines import PseudolinesArrangement 
 215  sage: from sage.geometry.pseudolines import PseudolineArrangement 
218  216  sage: transpositions = [(3, 2), (3, 1), (0, 3), (2, 1), (0, 2), (0, 1)] 
219   sage: PseudolinesArrangement(transpositions) 
 217  sage: PseudolineArrangement(transpositions) 
220  218  Arrangement of pseudolines of size 4 
221  219  
222  220  From a Felsner matrix:: 
223  221  
224   sage: from sage.geometry.pseudolines import PseudolinesArrangement 
 222  sage: from sage.geometry.pseudolines import PseudolineArrangement 
225  223  sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] 
226   sage: p = PseudolinesArrangement(permutations) 
 224  sage: p = PseudolineArrangement(permutations) 
227  225  sage: matrix = p.felsner_matrix() 
228   sage: PseudolinesArrangement(matrix) == p 
 226  sage: PseudolineArrangement(matrix) == p 
229  227  True 
230  228  
231  229  TESTS: 
232  230  
233  231  Wrong input:: 
234  232  
235   sage: PseudolinesArrangement([[5, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]]) 
 233  sage: PseudolineArrangement([[5, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]]) 
236  234  Traceback (most recent call last): 
237  235  ... 
238   ValueError: Are the lines really numbered from 0 to n1 ? 
239   sage: PseudolinesArrangement([(3, 2), (3, 1), (0, 3), (2, 1), (0, 2)]) 
 236  ValueError: Are the lines really numbered from 0 to n1? 
 237  sage: PseudolineArrangement([(3, 2), (3, 1), (0, 3), (2, 1), (0, 2)]) 
240  238  Traceback (most recent call last): 
241  239  ... 
242   ValueError: A line is numbered with 3but the number of transpositions ... 
 240  ValueError: A line is numbered 3 but the number of transpositions ... 
243  241  """ 
244   
 242  
245  243  # Sequence of transpositions 
246   if (encoding == "transpositions" or 
 244  if (encoding == "transpositions" or 
247  245  (encoding == "auto" and len(seq[0]) == 2 and len(seq) > 3)): 
248   
249   self._n = max(map(max, seq)) + 1 
 246  
 247  self._n = max(map(max, seq)) + 1 
250  248  if (self._n * (self._n1))/2 != len(seq): 
251  249  raise ValueError( 
252   "A line is numbered with "+str(self._n1)+"but the number "+ 
253   "of transpositions is different from binomial("+ 
254   str(self._n1)+",2). Are the lines numbered from 0 to n1 ?"+ 
255   "Are they really nonparallel ? Please check the documentation.") 
 250  "A line is numbered "+str(self._n1)+" but the number"+ 
 251  " of transpositions is different from binomial("+ 
 252  str(self._n1)+",2). Are the lines numbered from 0 to n1?"+ 
 253  " Are they really nonparallel? Please check the documentation.") 
256  254  
257  255  self._permutations = [[] for i in range(self._n)] 
258  256  
… 
… 

261  259  self._permutations[j].append(i) 
262  260  
263  261  # Sequence of permutations 
264   elif (encoding == "permutations" or 
 262  elif (encoding == "permutations" or 
265  263  (encoding == "auto" and (len(seq[0]) == len(seq)1) and max(seq[0]) > 1)): 
266   
 264  
267  265  self._n = len(seq) 
268  266  self._permutations = deepcopy(seq) 
269  267  
270  268  if max(map(max, seq)) != self._n 1 : 
271   raise ValueError("Are the lines really numbered from 0 to n1 ?") 
 269  raise ValueError("Are the lines really numbered from 0 to n1?") 
272  270  
273  271  # Felsner encoding 
274   elif (encoding == "Felsner" or 
 272  elif (encoding == "Felsner" or 
275  273  (encoding == "auto" and len(seq[0]) == len(seq) 1)): 
276  274  
277  275  seq = deepcopy(seq) 
… 
… 

289  287  seq[i+1][0] == 1)): 
290  288  
291  289  crossings = 1 
292   
 290  
293  291  self._permutations[ordering[i]].append(ordering[i+1]) 
294  292  self._permutations[ordering[i+1]].append(ordering[i]) 
295  293  
296  294  ordering[i], ordering[i+1] = ordering[i+1], ordering[i] 
297  295  seq[i], seq[i+1] = seq[i+1], seq[i] 
298   
 296  
299  297  seq[i].pop(0) 
300  298  seq[i+1].pop(0) 
301  299  
302  300  if i > 0 and seq[i1] is not []: 
303  301  i = 1 
304   elif seq[i] is not []: 
305   i += 1 
 302  else: 
 303  i += 1 
306  304  else: 
307  305  i += 1 
308  306  else: 
… 
… 

310  308  if encoding != "auto": 
311  309  raise ValueError("The value of encoding must be one of 'transpositions', 'permutations', 'Felsner' or 'auto'.") 
312  310  
313   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.") 
 311  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.") 
314  312  
315  313  def transpositions(self): 
316  314  r""" 
317  315  Returns the arrangement as `\binom n 2` transpositions. 
318  316  
319   See the :mod:`pseudolimes module <sage.geometry.pseudolines>`'s 
 317  See the :mod:`pseudolines module <sage.geometry.pseudolines>`'s 
320  318  documentation for more information on this encoding. 
321  319  
322  320  EXAMPLE:: 
323  321  
324   sage: from sage.geometry.pseudolines import PseudolinesArrangement 
 322  sage: from sage.geometry.pseudolines import PseudolineArrangement 
325  323  sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] 
326   sage: p1 = PseudolinesArrangement(permutations) 
 324  sage: p1 = PseudolineArrangement(permutations) 
327  325  sage: transpositions = [(3, 2), (3, 1), (0, 3), (2, 1), (0, 2), (0, 1)] 
328   sage: p2 = PseudolinesArrangement(transpositions) 
 326  sage: p2 = PseudolineArrangement(transpositions) 
329  327  sage: p1 == p2 
330  328  True 
331  329  sage: p1.transpositions() 
… 
… 

366  364  
367  365  if max(map(len,perm)) != 0: 
368  366  raise ValueError("There has been an error while computing the transpositions.") 
369   
 367  
370  368  return t 
371  369  
372  370  def permutations(self): 
373  371  r""" 
374  372  Returns the arrangements as `n` permutations of size `n1`. 
375  373  
376   See the :mod:`pseudolimes module <sage.geometry.pseudolines>`'s 
 374  See the :mod:`pseudolines module <sage.geometry.pseudolines>`'s 
377  375  documentation for more information on this encoding. 
378  376  
379  377  EXAMPLE:: 
380  378  
381   sage: from sage.geometry.pseudolines import PseudolinesArrangement 
 379  sage: from sage.geometry.pseudolines import PseudolineArrangement 
382  380  sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] 
383   sage: p = PseudolinesArrangement(permutations) 
 381  sage: p = PseudolineArrangement(permutations) 
384  382  sage: p.permutations() 
385  383  [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] 
386  384  """ 
… 
… 

390  388  r""" 
391  389  Returns a Felsner matrix describing the arrangement. 
392  390  
393   See the :mod:`pseudolimes module <sage.geometry.pseudolines>`'s 
 391  See the :mod:`pseudolines module <sage.geometry.pseudolines>`'s 
394  392  documentation for more information on this encoding. 
395  393  
396  394  EXAMPLE:: 
397  395  
398   sage: from sage.geometry.pseudolines import PseudolinesArrangement 
 396  sage: from sage.geometry.pseudolines import PseudolineArrangement 
399  397  sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] 
400   sage: p = PseudolinesArrangement(permutations) 
 398  sage: p = PseudolineArrangement(permutations) 
401  399  sage: p.felsner_matrix() 
402  400  [[0, 0, 0], [0, 0, 1], [0, 1, 1], [1, 1, 1]] 
403  401  """ 
… 
… 

417  415  r""" 
418  416  Displays the pseudoline arrangement as a wiring diagram. 
419  417  
420   INPUT: 
 418  INPUT: 
421  419  
422  420   ``**args``  any arguments to be forwarded to the ``show`` method. In 
423  421  particular, to tune the dimensions, use the ``figsize`` argument 
… 
… 

425  423  
426  424  EXAMPLE:: 
427  425  
428   sage: from sage.geometry.pseudolines import PseudolinesArrangement 
 426  sage: from sage.geometry.pseudolines import PseudolineArrangement 
429  427  sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] 
430   sage: p = PseudolinesArrangement(permutations) 
 428  sage: p = PseudolineArrangement(permutations) 
431  429  sage: p.show(figsize=[7,5]) 
432  430  
433  431  TESTS:: 
434  432  
435   sage: from sage.geometry.pseudolines import PseudolinesArrangement 
 433  sage: from sage.geometry.pseudolines import PseudolineArrangement 
436  434  sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 0, 1], [2, 0, 1]] 
437   sage: p = PseudolinesArrangement(permutations) 
 435  sage: p = PseudolineArrangement(permutations) 
438  436  sage: p.show() 
439  437  Traceback (most recent call last): 
440  438  ... 
… 
… 

464  462  lines[j].append((x+2,iy)) 
465  463  
466  464  x += 2 
467   
 465  
468  466  L = line([(1,1)]) 
469   
 467  
470  468  for i, l in enumerate(lines): 
471  469  l.append((x+2, l[1][1])) 
472  470  L += line(l) 
473   
474   L += text(str(i), (0, l[0][1]+.3)) 
475   L += text(str(i), (x+2, l[1][1]+.3)) 
 471  
 472  L += text(str(i), (0, l[0][1]+.3), horizontal_alignment="right") 
 473  L += text(str(i), (x+2, l[1][1]+.3), horizontal_alignment="left") 
476  474  
477  475  return L.show(axes = False, **args) 
478   
 476  
479  477  
480  478  def __repr__(self): 
481  479  r""" 
482   A short txt description of the pseudolines arrangement. 
 480  A short txt description of the pseudoline arrangement. 
483  481  
484  482  EXAMPLE:: 
485  483  
486   sage: from sage.geometry.pseudolines import PseudolinesArrangement 
 484  sage: from sage.geometry.pseudolines import PseudolineArrangement 
487  485  sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] 
488   sage: p = PseudolinesArrangement(permutations) 
 486  sage: p = PseudolineArrangement(permutations) 
489  487  sage: p 
490  488  Arrangement of pseudolines of size 4 
491  489  """ 
… 
… 

497  495  
498  496  TEST:: 
499  497  
500   sage: from sage.geometry.pseudolines import PseudolinesArrangement 
 498  sage: from sage.geometry.pseudolines import PseudolineArrangement 
501  499  sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] 
502   sage: p1 = PseudolinesArrangement(permutations) 
 500  sage: p1 = PseudolineArrangement(permutations) 
503  501  sage: transpositions = [(3, 2), (3, 1), (0, 3), (2, 1), (0, 2), (0, 1)] 
504   sage: p2 = PseudolinesArrangement(transpositions) 
 502  sage: p2 = PseudolineArrangement(transpositions) 
505  503  sage: p1 == p2 
506   True 
 504  True 
507  505  """ 
508  506  return (self._n == other._n) and (self._permutations == other._permutations) 