1 package org.thegalactic.lattice;
2
3 /*
4 * LatticeFactory.java
5 *
6 * Copyright: 2010-2015 Karell Bertet, France
7 * Copyright: 2015-2016 The Galactic Organization, France
8 *
9 * License: http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html CeCILL-B license
10 *
11 * This file is part of java-lattices.
12 * You can redistribute it and/or modify it under the terms of the CeCILL-B license.
13 */
14 import java.util.BitSet;
15 import java.util.Iterator;
16
17 import org.thegalactic.dgraph.DAGraph;
18 import org.thegalactic.dgraph.DAGraphFactory;
19 import org.thegalactic.dgraph.Node;
20 import org.thegalactic.util.Couple;
21
22 /**
23 * This class provides a few methods to constructs lattice examples.
24 *
25 * ![LatticeFactory](LatticeFactory.png)
26 *
27 * @uml LatticeFactory.png
28 * !include resources/org/thegalactic/lattice/LatticeFactory.iuml
29 *
30 * class LatticeFactory #LightCyan
31 * title LatticeFactory UML graph
32 * @author jeff
33 */
34 public class LatticeFactory {
35
36 /**
37 * Returns a randomly generated lattice with nb nodes.
38 *
39 * @param nb Number of nodes in the randomly generated lattice
40 *
41 * @return a randomly generated lattice with nb nodes
42 */
43 public static Lattice<Integer, ?> random(int nb) {
44 boolean done = false;
45 Lattice l = new Lattice();
46 while (!done) {
47 DAGraph dag = DAGraphFactory.getInstance().random(nb - 2); // what an ugly strategy :-(
48 Lattice<Integer, ?> tmp = new Lattice(dag);
49 Node<Integer> top = new Node(nb - 1);
50 tmp.addNode(top);
51 for (Node<Integer> node : tmp.max()) {
52 if (!node.equals(top)) {
53 tmp.addEdge(node, top);
54 }
55 }
56 Node<Integer> bot = new Node(nb);
57 tmp.addNode(bot);
58 for (Node<Integer> node : tmp.min()) {
59 if (!node.equals(bot)) {
60 tmp.addEdge(bot, node);
61 }
62 }
63 if (tmp.isLattice()) {
64 done = true;
65 l = tmp;
66 }
67 }
68 return l;
69 }
70
71 /**
72 * Returns the boolean algebra of cardinal 2^n.
73 *
74 * @param n cardinal of the boolean algebra return by this method is 2^n
75 *
76 * @return the boolean algebra of cardinal 2^n
77 */
78 public static Lattice booleanAlgebra(int n) {
79 Lattice<BitSet, ?> l = new Lattice();
80 BitSet b = new BitSet(n);
81 Node<BitSet> bot = new Node(b);
82 l.addNode(bot);
83 for (int i = 0; i < n; i++) {
84 BitSet bs = new BitSet(n);
85 bs.set(i, true);
86 Node<BitSet> next = new Node(bs);
87 l.addNode(next);
88 l.addEdge(bot, next);
89 recursiveBooleanAlgebra(next, l, n);
90 }
91 return l;
92 }
93
94 /**
95 * Returns the lattice of permutations of 1..n.
96 *
97 * Permutation are ordered as follows : A permutation s2 is a succesor of a
98 * permutation s1, if s2 is obtained from s1 by inverting two consecutive
99 * elements i and j such that before inversion j > i.
100 *
101 * Example : 124356 has following successors 214356, 142356, 124536 and
102 * 124365.
103 *
104 * The bottom of this lattice is identity (for exemple 123456) and the top
105 * is for instance 654321.
106 *
107 * @param n the lattice of permutations of the set 1..n
108 *
109 * @return the lattice of permutations of 1..n.
110 */
111 public static Lattice permutationLattice(int n) {
112 Lattice<Permutation, ?> l = new Lattice();
113 int[] content = new int[n];
114 for (int i = 0; i < n; i++) {
115 content[i] = i;
116 }
117 Permutation s = new Permutation(n);
118 s.setContent(content);
119 Node<Permutation> bot = new Node(s);
120 l.addNode(bot);
121 for (int i = 0; i < n - 1; i++) {
122 int[] newC = content.clone();
123 newC[i] = content[i + 1];
124 newC[i + 1] = content[i];
125 Permutation newS = new Permutation(n);
126 newS.setContent(newC);
127 Node<Permutation> succ = new Node(newS);
128 l.addNode(succ);
129 l.addEdge(bot, succ);
130 recursivePermutationLattice(succ, l, n);
131 }
132 return l;
133 }
134
135 /**
136 * Returns the lattice cartesian product of l and r.
137 *
138 * A node in the product is a cartesian product of two nodes
139 *
140 * There is an edge (n1, m1) -> (n2, m2) if and only if there are edges n1
141 * -> n2 and m1 -> m2
142 *
143 * @param l Lattice of the left hand side of the product
144 * @param r Lattice of the right hand side of the product
145 *
146 * @return the lattice cartesian product of l and r
147 */
148 public static Lattice product(Lattice l, Lattice r) {
149 Lattice prod = new Lattice();
150 // Create nodes
151 for (Object nL : l.getNodes()) {
152 for (Object nR : r.getNodes()) {
153 prod.addNode(new Node(new Couple(((Node) nL).getContent(), ((Node) nR).getContent())));
154 }
155 }
156 // Create edges
157 for (Object source : prod.getNodes()) {
158 for (Object target : prod.getNodes()) {
159 if (l.containsEdge(l.getNodeByContent(((Couple) ((Node) source).getContent()).getLeft()),
160 l.getNodeByContent(((Couple) ((Node) target).getContent()).getLeft()))
161 && r.containsEdge(r.getNodeByContent(((Couple) ((Node) source).getContent()).getRight()),
162 r.getNodeByContent(((Couple) ((Node) target).getContent()).getRight()))) {
163 prod.addEdge((Node) source, (Node) target);
164 }
165 }
166 }
167 return prod;
168 }
169
170 /**
171 * Returns lattice l in which convex c has been doubled.
172 *
173 * @param l a lattice
174 * @param c a convex subset of l, to be doubled.
175 *
176 * @return a lattice construct from l by doubling the convex subset c.
177 */
178 public static Lattice doublingConvex(Lattice l, DAGraph c) {
179 Lattice doubled = new Lattice();
180 // Copy nodes by Content
181 for (Object node : l.getNodes()) {
182 if (c.containsNode((Node) node)) {
183 // These nodes are doubled
184 Couple cpl0 = new Couple(((Node) node).getContent(), 0);
185 Node n0 = new Node(cpl0);
186 Couple cpl1 = new Couple(((Node) node).getContent(), 1);
187 Node n1 = new Node(cpl1);
188 doubled.addNode(n0);
189 doubled.addNode(n1);
190 } else {
191 // These nodes are just copied
192 doubled.addNode(new Node(((Node) node).getContent()));
193 }
194 }
195 // Construct edges of doubled
196 Couple test = new Couple(0, 0); // used to test class of contents
197 for (Object x : doubled.getNodes()) {
198 for (Object y : doubled.getNodes()) {
199 // Add an edge if x < y
200 if (((Node) x).getContent().getClass() == test.getClass()) { // x was in convex c
201 if (((Node) y).getContent().getClass() == test.getClass()) { // y was also in convex c
202 // x & y were in convex c
203 Couple cX = (Couple) ((Node) x).getContent();
204 Couple cY = (Couple) ((Node) y).getContent();
205 if ((cX.getLeft() == cY.getLeft()) && (((Integer) cX.getRight()) == 0)
206 && (((Integer) cY.getRight()) == 1)) {
207 // Same content means same node. x is of the form (cX, 0) and y is of the for (cX, 1) so x < y in doubled.
208 doubled.addEdge((Node) x, (Node) y);
209 } else if (l.majorants(l.getNodeByContent(cX.getLeft())).contains(l.getNodeByContent(cY.getLeft()))
210 && (cX.getRight() == cY.getRight())) {
211 // x < y in l and x & y have the same second component si x < y in doubled.
212 doubled.addEdge((Node) x, (Node) y);
213 }
214 } else { // y wasn't in convex c
215 // x was in c & y wasn't
216 Couple cX = (Couple) ((Node) x).getContent();
217 if (l.majorants(l.getNodeByContent(cX.getLeft())).contains(l.getNodeByContent(((Node) y).getContent()))
218 && (((Integer) cX.getRight()) == 1)) {
219 // x < y in l and second component of x is 1.
220 doubled.addEdge((Node) x, (Node) y);
221 }
222 }
223 } else // x wasn't in convex c
224 if (((Node) y).getContent().getClass() == test.getClass()) { // y was in convex c
225 // x wasn't in c but y was
226 Couple cY = (Couple) ((Node) y).getContent();
227 if (l.majorants(l.getNodeByContent(((Node) x).getContent())).contains(l.getNodeByContent(cY.getLeft()))
228 && (((Integer) cY.getRight()) == 0)) {
229 // x < y in l and x & second component of y is 0.
230 doubled.addEdge((Node) x, (Node) y);
231 }
232 } else // y wasn't in convex c
233 // x wasn't in c nor y
234 if (l.majorants(l.getNodeByContent(((Node) x).getContent())).contains(l.getNodeByContent(((Node) y).getContent()))) {
235 // x < y in l and x & second component of y is 0.
236 doubled.addEdge((Node) x, (Node) y);
237 }
238 }
239 }
240 doubled.transitiveReduction();
241 return doubled;
242 }
243
244 /**
245 * Computes successors of node n in the boolean algebra currently generated.
246 *
247 * @param node this method compute successors of this node
248 * @param l boolean algebra currently generated
249 * @param n the number of node of l will be 2^n at the end of computation
250 */
251 private static void recursiveBooleanAlgebra(Node node, Lattice l, int n) {
252 for (int i = 0; i < n; i++) {
253 BitSet b = (BitSet) node.getContent();
254 if (!b.get(i)) {
255 BitSet bs = (BitSet) b.clone();
256 bs.set(i, true);
257 if (l.getNodeByContent(bs) == null) {
258 Node next = new Node(bs);
259 l.addNode(next);
260 l.addEdge(node, next);
261 recursiveBooleanAlgebra(next, l, n);
262 } else {
263 l.addEdge(node, l.getNodeByContent(bs));
264 }
265 }
266 }
267 }
268
269 /**
270 * Computes successors of node n in the lattice l.
271 *
272 * @param node successors of this node are computed by this method
273 * @param l lattice of permutations currently generated
274 * @param n lattice of permutation of the set 1..n is currently generated
275 */
276 private static void recursivePermutationLattice(Node node, Lattice l, int n) {
277 Permutation s = (Permutation) node.getContent();
278 for (int i = 0; i < s.getLength() - 1; i++) {
279 if (s.getContent()[i] < s.getContent()[i + 1]) {
280 int[] newC = s.getContent().clone();
281 Node currentNode = new Node();
282 newC[i] = s.getContent()[i + 1];
283 newC[i + 1] = s.getContent()[i];
284 Permutation newP = new Permutation(n);
285 newP.setContent(newC);
286 boolean newNode = true;
287 Iterator<Node> it = l.getNodes().iterator();
288 while (it.hasNext() && newNode) {
289 currentNode = it.next();
290 Permutation currentContent = (Permutation) currentNode.getContent();
291 newNode = !(currentContent.equals(newP));
292 }
293 if (newNode) {
294 Permutation newS = new Permutation(n);
295 newS.setContent(newC);
296 Node next = new Node(newS);
297 l.addNode(next);
298 l.addEdge(node, next);
299 recursivePermutationLattice(next, l, n);
300 } else {
301 l.addEdge(node, currentNode);
302 }
303 }
304 }
305 }
306
307 /**
308 * Empty constructor.
309 */
310 protected LatticeFactory() {
311 super();
312 }
313
314 /**
315 * This class provides a representation of permutations.
316 *
317 * If this component transforms : 0 -> 1, 1 -> 0 & 2 -> 2. Then its length
318 * is 3 and
319 *
320 * The content contains :
321 *
322 * ~~~
323 * content[0]=1 content[1]=0 content[2]=2
324 * ~~~
325 */
326 private static class Permutation {
327
328 /**
329 * This component is a permutation of 0..length-1.
330 */
331 private int length;
332
333 /**
334 * The transformation represented by this component.
335 *
336 * If this component transforms : 0 -> 1, 1 -> 0 & 2 -> 2. The field
337 * content contains :
338 *
339 * ~~~
340 * content[0]=1 content[1]=0 content[2]=2
341 * ~~~
342 */
343 private int[] content;
344
345 /**
346 * Constructs identity of the set 0..n-1.
347 *
348 * @param n permutation of the set 0..n-1.
349 */
350 Permutation(int n) {
351 this.length = n;
352 this.content = new int[n];
353 for (int i = 0; i < n; i++) {
354 this.content[i] = i;
355 }
356 }
357
358 /**
359 * Returns the transformation coded by this component.
360 *
361 * @return the transformation coded by this component.
362 */
363 public int[] getContent() {
364 return this.content;
365 }
366
367 /**
368 * Set the transformation coded by this component.
369 *
370 * Length of this component is update by this method.
371 *
372 * @param c the transformation coded in this component.
373 *
374 * @return this for chaining
375 */
376 public Permutation setContent(int[] c) {
377 this.content = c;
378 this.length = c.length;
379 return this;
380 }
381
382 /**
383 * Return length of this component.
384 *
385 * @return length of this component.
386 */
387 public int getLength() {
388 return this.length;
389 }
390
391 /**
392 * Set length of this componenet.
393 *
394 * @param l length of this component.
395 *
396 * @return true if update is successful.
397 */
398 public boolean setLength(int l) {
399 if ((this.content.length == l) && (l <= this.getLength())) {
400 this.length = l;
401 return true;
402 } else {
403 return false;
404 }
405 }
406
407 /**
408 * Returns a string representation of this component.
409 *
410 * @return a string representation of this component.
411 */
412 @Override
413 public String toString() {
414 String str = "";
415 for (int i = 0; i < this.length; i++) {
416 str = str + this.content[i];
417 }
418 return str;
419 }
420
421 /**
422 * Returns true if this component is equal to s.
423 *
424 * @param s test if this component is equal to s
425 *
426 * @return true if this component is equal to s
427 */
428 public boolean equals(Permutation s) {
429 if (!(s.getLength() == this.length)) {
430 return false;
431 } else {
432 boolean tmp = true;
433 for (int i = 0; i < this.length; i++) {
434 tmp = tmp && (this.content[i] == s.getContent()[i]);
435 }
436 return tmp;
437 }
438 }
439
440 /**
441 * Compute the hash code.
442 *
443 * @return an integer representing the object
444 */
445 @Override
446 public int hashCode() {
447 return super.hashCode();
448 }
449 }
450 }