001package org.clafer.ast.analysis;
002
003import gnu.trove.list.array.TIntArrayList;
004import org.clafer.common.Util;
005
006/**
007 *
008 * @author jimmy
009 */
010public class PartialSolution {
011
012    // solution[i] = true <=> i exists
013    // solution[i] = false <=> i unknown
014    private final boolean[] solution;
015    // parent[i] = the list of possible parents
016    private final int[][] parent;
017    // siblings[i] = the list of possible siblings
018    private final int[][] siblings;
019
020    public PartialSolution(boolean[] solution, int[][] parent) {
021        this.solution = solution;
022        this.parent = parent;
023        this.siblings = new int[parent.length][];
024        TIntArrayList array = new TIntArrayList(parent.length);
025        for (int i = 0; i < siblings.length; i++) {
026            array.clear();
027            for (int j = 1; j < siblings.length; j++) {
028                if (i != j) {
029                    // TODO: shouldn't be null.
030                    if (parent[i] != null && parent[j] != null) {
031                        if (overlaps(parent[i], parent[j])) {
032                            array.add(j);
033                        }
034                    }
035                }
036            }
037            siblings[i] = array.toArray();
038        }
039    }
040
041    private static boolean overlaps(int[] a, int[] b) {
042        for (int i : a) {
043            if (Util.in(i, b)) {
044                return true;
045            }
046        }
047        return false;
048    }
049
050    /**
051     * @param id
052     * @return true if id exists, false if unknown.
053     */
054    public boolean hasClafer(int id) {
055        return solution[id];
056    }
057
058    public boolean[] getSolution() {
059        return solution;
060    }
061
062    public int[] getKnownClafers() {
063        return Util.trues(solution);
064    }
065
066    public int[] getUnknownClafers() {
067        return Util.falses(solution);
068    }
069
070    /**
071     * @param id
072     * @return possible parents of {@code id}
073     */
074    public int[] getPossibleParents(int id) {
075        return parent[id];
076    }
077
078    /**
079     * @return {@code true} if and only if all parents are known, {@code false}
080     * otherwise
081     */
082    public boolean parentSolutionKnown() {
083        for (int[] p : parent) {
084            if (p.length != 1) {
085                return false;
086            }
087        }
088        return true;
089    }
090
091    /**
092     * @param id
093     * @return possible siblings of {@code id}
094     */
095    public int[] getPossiblesSiblings(int id) {
096        return siblings[id];
097    }
098
099    public int size() {
100        return solution.length;
101    }
102}