LatticeFactory.java

  1. package org.thegalactic.lattice;

  2. /*
  3.  * LatticeFactory.java
  4.  *
  5.  * Copyright: 2010-2015 Karell Bertet, France
  6.  * Copyright: 2015-2016 The Galactic Organization, France
  7.  *
  8.  * License: http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html CeCILL-B license
  9.  *
  10.  * This file is part of java-lattices.
  11.  * You can redistribute it and/or modify it under the terms of the CeCILL-B license.
  12.  */
  13. import java.util.BitSet;
  14. import java.util.Iterator;

  15. import org.thegalactic.dgraph.DAGraph;
  16. import org.thegalactic.dgraph.DAGraphFactory;
  17. import org.thegalactic.dgraph.Node;
  18. import org.thegalactic.util.Couple;

  19. /**
  20.  * This class provides a few methods to constructs lattice examples.
  21.  *
  22.  * ![LatticeFactory](LatticeFactory.png)
  23.  *
  24.  * @uml LatticeFactory.png
  25.  * !include resources/org/thegalactic/lattice/LatticeFactory.iuml
  26.  *
  27.  * class LatticeFactory #LightCyan
  28.  * title LatticeFactory UML graph
  29.  * @author jeff
  30.  */
  31. public class LatticeFactory {

  32.     /**
  33.      * Returns a randomly generated lattice with nb nodes.
  34.      *
  35.      * @param nb Number of nodes in the randomly generated lattice
  36.      *
  37.      * @return a randomly generated lattice with nb nodes
  38.      */
  39.     public static Lattice<Integer, ?> random(int nb) {
  40.         boolean done = false;
  41.         Lattice l = new Lattice();
  42.         while (!done) {
  43.             DAGraph dag = DAGraphFactory.getInstance().random(nb - 2); // what an ugly strategy :-(
  44.             Lattice<Integer, ?> tmp = new Lattice(dag);
  45.             Node<Integer> top = new Node(nb - 1);
  46.             tmp.addNode(top);
  47.             for (Node<Integer> node : tmp.max()) {
  48.                 if (!node.equals(top)) {
  49.                     tmp.addEdge(node, top);
  50.                 }
  51.             }
  52.             Node<Integer> bot = new Node(nb);
  53.             tmp.addNode(bot);
  54.             for (Node<Integer> node : tmp.min()) {
  55.                 if (!node.equals(bot)) {
  56.                     tmp.addEdge(bot, node);
  57.                 }
  58.             }
  59.             if (tmp.isLattice()) {
  60.                 done = true;
  61.                 l = tmp;
  62.             }
  63.         }
  64.         return l;
  65.     }

  66.     /**
  67.      * Returns the boolean algebra of cardinal 2^n.
  68.      *
  69.      * @param n cardinal of the boolean algebra return by this method is 2^n
  70.      *
  71.      * @return the boolean algebra of cardinal 2^n
  72.      */
  73.     public static Lattice booleanAlgebra(int n) {
  74.         Lattice<BitSet, ?> l = new Lattice();
  75.         BitSet b = new BitSet(n);
  76.         Node<BitSet> bot = new Node(b);
  77.         l.addNode(bot);
  78.         for (int i = 0; i < n; i++) {
  79.             BitSet bs = new BitSet(n);
  80.             bs.set(i, true);
  81.             Node<BitSet> next = new Node(bs);
  82.             l.addNode(next);
  83.             l.addEdge(bot, next);
  84.             recursiveBooleanAlgebra(next, l, n);
  85.         }
  86.         return l;
  87.     }

  88.     /**
  89.      * Returns the lattice of permutations of 1..n.
  90.      *
  91.      * Permutation are ordered as follows : A permutation s2 is a succesor of a
  92.      * permutation s1, if s2 is obtained from s1 by inverting two consecutive
  93.      * elements i and j such that before inversion j > i.
  94.      *
  95.      * Example : 124356 has following successors 214356, 142356, 124536 and
  96.      * 124365.
  97.      *
  98.      * The bottom of this lattice is identity (for exemple 123456) and the top
  99.      * is for instance 654321.
  100.      *
  101.      * @param n the lattice of permutations of the set 1..n
  102.      *
  103.      * @return the lattice of permutations of 1..n.
  104.      */
  105.     public static Lattice permutationLattice(int n) {
  106.         Lattice<Permutation, ?> l = new Lattice();
  107.         int[] content = new int[n];
  108.         for (int i = 0; i < n; i++) {
  109.             content[i] = i;
  110.         }
  111.         Permutation s = new Permutation(n);
  112.         s.setContent(content);
  113.         Node<Permutation> bot = new Node(s);
  114.         l.addNode(bot);
  115.         for (int i = 0; i < n - 1; i++) {
  116.             int[] newC = content.clone();
  117.             newC[i] = content[i + 1];
  118.             newC[i + 1] = content[i];
  119.             Permutation newS = new Permutation(n);
  120.             newS.setContent(newC);
  121.             Node<Permutation> succ = new Node(newS);
  122.             l.addNode(succ);
  123.             l.addEdge(bot, succ);
  124.             recursivePermutationLattice(succ, l, n);
  125.         }
  126.         return l;
  127.     }

  128.     /**
  129.      * Returns the lattice cartesian product of l and r.
  130.      *
  131.      * A node in the product is a cartesian product of two nodes
  132.      *
  133.      * There is an edge (n1, m1) -> (n2, m2) if and only if there are edges n1
  134.      * -> n2 and m1 -> m2
  135.      *
  136.      * @param l Lattice of the left hand side of the product
  137.      * @param r Lattice of the right hand side of the product
  138.      *
  139.      * @return the lattice cartesian product of l and r
  140.      */
  141.     public static Lattice product(Lattice l, Lattice r) {
  142.         Lattice prod = new Lattice();
  143.         // Create nodes
  144.         for (Object nL : l.getNodes()) {
  145.             for (Object nR : r.getNodes()) {
  146.                 prod.addNode(new Node(new Couple(((Node) nL).getContent(), ((Node) nR).getContent())));
  147.             }
  148.         }
  149.         // Create edges
  150.         for (Object source : prod.getNodes()) {
  151.             for (Object target : prod.getNodes()) {
  152.                 if (l.containsEdge(l.getNodeByContent(((Couple) ((Node) source).getContent()).getLeft()),
  153.                         l.getNodeByContent(((Couple) ((Node) target).getContent()).getLeft()))
  154.                         && r.containsEdge(r.getNodeByContent(((Couple) ((Node) source).getContent()).getRight()),
  155.                                 r.getNodeByContent(((Couple) ((Node) target).getContent()).getRight()))) {
  156.                     prod.addEdge((Node) source, (Node) target);
  157.                 }
  158.             }
  159.         }
  160.         return prod;
  161.     }

  162.     /**
  163.      * Returns lattice l in which convex c has been doubled.
  164.      *
  165.      * @param l a lattice
  166.      * @param c a convex subset of l, to be doubled.
  167.      *
  168.      * @return a lattice construct from l by doubling the convex subset c.
  169.      */
  170.     public static Lattice doublingConvex(Lattice l, DAGraph c) {
  171.         Lattice doubled = new Lattice();
  172.         // Copy nodes by Content
  173.         for (Object node : l.getNodes()) {
  174.             if (c.containsNode((Node) node)) {
  175.                 // These nodes are doubled
  176.                 Couple cpl0 = new Couple(((Node) node).getContent(), 0);
  177.                 Node n0 = new Node(cpl0);
  178.                 Couple cpl1 = new Couple(((Node) node).getContent(), 1);
  179.                 Node n1 = new Node(cpl1);
  180.                 doubled.addNode(n0);
  181.                 doubled.addNode(n1);
  182.             } else {
  183.                 // These nodes are just copied
  184.                 doubled.addNode(new Node(((Node) node).getContent()));
  185.             }
  186.         }
  187.         // Construct edges of doubled
  188.         Couple test = new Couple(0, 0); // used to test class of contents
  189.         for (Object x : doubled.getNodes()) {
  190.             for (Object y : doubled.getNodes()) {
  191.                 // Add an edge if x < y
  192.                 if (((Node) x).getContent().getClass() == test.getClass()) { // x was in convex c
  193.                     if (((Node) y).getContent().getClass() == test.getClass()) { // y was also in convex c
  194.                         // x & y were in convex c
  195.                         Couple cX = (Couple) ((Node) x).getContent();
  196.                         Couple cY = (Couple) ((Node) y).getContent();
  197.                         if ((cX.getLeft() == cY.getLeft()) && (((Integer) cX.getRight()) == 0)
  198.                                 && (((Integer) cY.getRight()) == 1)) {
  199.                             // 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.
  200.                             doubled.addEdge((Node) x, (Node) y);
  201.                         } else if (l.majorants(l.getNodeByContent(cX.getLeft())).contains(l.getNodeByContent(cY.getLeft()))
  202.                                 && (cX.getRight() == cY.getRight())) {
  203.                             // x < y in l and x & y have the same second component si x < y in doubled.
  204.                             doubled.addEdge((Node) x, (Node) y);
  205.                         }
  206.                     } else { // y wasn't in convex c
  207.                         // x was in c & y wasn't
  208.                         Couple cX = (Couple) ((Node) x).getContent();
  209.                         if (l.majorants(l.getNodeByContent(cX.getLeft())).contains(l.getNodeByContent(((Node) y).getContent()))
  210.                                 && (((Integer) cX.getRight()) == 1)) {
  211.                             // x < y in l and second component of x is 1.
  212.                             doubled.addEdge((Node) x, (Node) y);
  213.                         }
  214.                     }
  215.                 } else // x wasn't in convex c
  216.                  if (((Node) y).getContent().getClass() == test.getClass()) { // y was in convex c
  217.                         // x wasn't in c but y was
  218.                         Couple cY = (Couple) ((Node) y).getContent();
  219.                         if (l.majorants(l.getNodeByContent(((Node) x).getContent())).contains(l.getNodeByContent(cY.getLeft()))
  220.                                 && (((Integer) cY.getRight()) == 0)) {
  221.                             // x < y in l and x & second component of y is 0.
  222.                             doubled.addEdge((Node) x, (Node) y);
  223.                         }
  224.                     } else // y wasn't in convex c
  225.                     // x wasn't in c nor y
  226.                      if (l.majorants(l.getNodeByContent(((Node) x).getContent())).contains(l.getNodeByContent(((Node) y).getContent()))) {
  227.                             // x < y in l and x & second component of y is 0.
  228.                             doubled.addEdge((Node) x, (Node) y);
  229.                         }
  230.             }
  231.         }
  232.         doubled.transitiveReduction();
  233.         return doubled;
  234.     }

  235.     /**
  236.      * Computes successors of node n in the boolean algebra currently generated.
  237.      *
  238.      * @param node this method compute successors of this node
  239.      * @param l    boolean algebra currently generated
  240.      * @param n    the number of node of l will be 2^n at the end of computation
  241.      */
  242.     private static void recursiveBooleanAlgebra(Node node, Lattice l, int n) {
  243.         for (int i = 0; i < n; i++) {
  244.             BitSet b = (BitSet) node.getContent();
  245.             if (!b.get(i)) {
  246.                 BitSet bs = (BitSet) b.clone();
  247.                 bs.set(i, true);
  248.                 if (l.getNodeByContent(bs) == null) {
  249.                     Node next = new Node(bs);
  250.                     l.addNode(next);
  251.                     l.addEdge(node, next);
  252.                     recursiveBooleanAlgebra(next, l, n);
  253.                 } else {
  254.                     l.addEdge(node, l.getNodeByContent(bs));
  255.                 }
  256.             }
  257.         }
  258.     }

  259.     /**
  260.      * Computes successors of node n in the lattice l.
  261.      *
  262.      * @param node successors of this node are computed by this method
  263.      * @param l    lattice of permutations currently generated
  264.      * @param n    lattice of permutation of the set 1..n is currently generated
  265.      */
  266.     private static void recursivePermutationLattice(Node node, Lattice l, int n) {
  267.         Permutation s = (Permutation) node.getContent();
  268.         for (int i = 0; i < s.getLength() - 1; i++) {
  269.             if (s.getContent()[i] < s.getContent()[i + 1]) {
  270.                 int[] newC = s.getContent().clone();
  271.                 Node currentNode = new Node();
  272.                 newC[i] = s.getContent()[i + 1];
  273.                 newC[i + 1] = s.getContent()[i];
  274.                 Permutation newP = new Permutation(n);
  275.                 newP.setContent(newC);
  276.                 boolean newNode = true;
  277.                 Iterator<Node> it = l.getNodes().iterator();
  278.                 while (it.hasNext() && newNode) {
  279.                     currentNode = it.next();
  280.                     Permutation currentContent = (Permutation) currentNode.getContent();
  281.                     newNode = !(currentContent.equals(newP));
  282.                 }
  283.                 if (newNode) {
  284.                     Permutation newS = new Permutation(n);
  285.                     newS.setContent(newC);
  286.                     Node next = new Node(newS);
  287.                     l.addNode(next);
  288.                     l.addEdge(node, next);
  289.                     recursivePermutationLattice(next, l, n);
  290.                 } else {
  291.                     l.addEdge(node, currentNode);
  292.                 }
  293.             }
  294.         }
  295.     }

  296.     /**
  297.      * Empty constructor.
  298.      */
  299.     protected LatticeFactory() {
  300.         super();
  301.     }

  302.     /**
  303.      * This class provides a representation of permutations.
  304.      *
  305.      * If this component transforms : 0 -> 1, 1 -> 0 & 2 -> 2. Then its length
  306.      * is 3 and
  307.      *
  308.      * The content contains :
  309.      *
  310.      * ~~~
  311.      * content[0]=1 content[1]=0 content[2]=2
  312.      * ~~~
  313.      */
  314.     private static class Permutation {

  315.         /**
  316.          * This component is a permutation of 0..length-1.
  317.          */
  318.         private int length;

  319.         /**
  320.          * The transformation represented by this component.
  321.          *
  322.          * If this component transforms : 0 -> 1, 1 -> 0 & 2 -> 2. The field
  323.          * content contains :
  324.          *
  325.          * ~~~
  326.          * content[0]=1 content[1]=0 content[2]=2
  327.          * ~~~
  328.          */
  329.         private int[] content;

  330.         /**
  331.          * Constructs identity of the set 0..n-1.
  332.          *
  333.          * @param n permutation of the set 0..n-1.
  334.          */
  335.         Permutation(int n) {
  336.             this.length = n;
  337.             this.content = new int[n];
  338.             for (int i = 0; i < n; i++) {
  339.                 this.content[i] = i;
  340.             }
  341.         }

  342.         /**
  343.          * Returns the transformation coded by this component.
  344.          *
  345.          * @return the transformation coded by this component.
  346.          */
  347.         public int[] getContent() {
  348.             return this.content;
  349.         }

  350.         /**
  351.          * Set the transformation coded by this component.
  352.          *
  353.          * Length of this component is update by this method.
  354.          *
  355.          * @param c the transformation coded in this component.
  356.          *
  357.          * @return this for chaining
  358.          */
  359.         public Permutation setContent(int[] c) {
  360.             this.content = c;
  361.             this.length = c.length;
  362.             return this;
  363.         }

  364.         /**
  365.          * Return length of this component.
  366.          *
  367.          * @return length of this component.
  368.          */
  369.         public int getLength() {
  370.             return this.length;
  371.         }

  372.         /**
  373.          * Set length of this componenet.
  374.          *
  375.          * @param l length of this component.
  376.          *
  377.          * @return true if update is successful.
  378.          */
  379.         public boolean setLength(int l) {
  380.             if ((this.content.length == l) && (l <= this.getLength())) {
  381.                 this.length = l;
  382.                 return true;
  383.             } else {
  384.                 return false;
  385.             }
  386.         }

  387.         /**
  388.          * Returns a string representation of this component.
  389.          *
  390.          * @return a string representation of this component.
  391.          */
  392.         @Override
  393.         public String toString() {
  394.             String str = "";
  395.             for (int i = 0; i < this.length; i++) {
  396.                 str = str + this.content[i];
  397.             }
  398.             return str;
  399.         }

  400.         /**
  401.          * Returns true if this component is equal to s.
  402.          *
  403.          * @param s test if this component is equal to s
  404.          *
  405.          * @return true if this component is equal to s
  406.          */
  407.         public boolean equals(Permutation s) {
  408.             if (!(s.getLength() == this.length)) {
  409.                 return false;
  410.             } else {
  411.                 boolean tmp = true;
  412.                 for (int i = 0; i < this.length; i++) {
  413.                     tmp = tmp && (this.content[i] == s.getContent()[i]);
  414.                 }
  415.                 return tmp;
  416.             }
  417.         }

  418.         /**
  419.          * Compute the hash code.
  420.          *
  421.          * @return an integer representing the object
  422.          */
  423.         @Override
  424.         public int hashCode() {
  425.             return super.hashCode();
  426.         }
  427.     }
  428. }