/* Copyright 2014 Julia s.r.l. This file is part of BeeDeeDee. BeeDeeDee is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. BeeDeeDee is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BeeDeeDee. If not, see <http://www.gnu.org/licenses/>. */ package com.juliasoft.beedeedee.factories; import static com.juliasoft.julia.checkers.nullness.assertions.NullnessAssertions.assertNonNull; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import net.sf.javabdd.BDD; import net.sf.javabdd.BDDBitVector; import net.sf.javabdd.BDDDomain; import net.sf.javabdd.BDDException; import net.sf.javabdd.BDDFactory; import net.sf.javabdd.BDDPairing; import com.juliasoft.beedeedee.bdd.Assignment; import com.juliasoft.beedeedee.bdd.ReplacementWithExistingVarException; import com.juliasoft.beedeedee.factories.Factory.GarbageCollectionListener; import com.juliasoft.beedeedee.factories.Factory.ResizeListener; import com.juliasoft.julia.checkers.nullness.NonNull; /** * An adapter class to use BeeDeeDee through the JavaBDD interface. */ public class JavaBDDAdapterFactory extends BDDFactory { // this is non-null since it is definitely initialized by the static pseudo-constructor private @NonNull Factory factory; private int bddVarNum; private JavaBDDAdapterFactory() {} public static BDDFactory init(int nodenum, int cachesize) { JavaBDDAdapterFactory f = new JavaBDDAdapterFactory(); f.initialize(nodenum, cachesize); return f; } @Override public BDD zero() { return new JavaBDDAdapterBDD(factory.makeZero()); } @Override public BDD one() { return new JavaBDDAdapterBDD(factory.makeOne()); } @Override protected void initialize(int nodenum, int cachesize) { //factory = Factory.mk(nodenum, cachesize); factory = Factory.mkER(nodenum, cachesize); // we set the default call-backs try { Method m = JavaBDDAdapterFactory.class.getDeclaredMethod ("defaultResizeCallback", new Class[] { int.class, int.class }); registerResizeCallback(this, m); m = JavaBDDAdapterFactory.class.getDeclaredMethod ("defaultGCCallback", new Class[] { int.class, BDDFactory.GCStats.class }); registerGCCallback(this, m); } catch (SecurityException | NoSuchMethodException e) { throw new RuntimeException("Unexpected exception " + e); } } @Override public boolean isInitialized() { return true; } @Override public void done() { factory.done(); factory = null; } /** * Unsupported operation. */ @Override public void setError(int code) { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public void clearError() { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public int setMaxNodeNum(int size) { throw new UnsupportedOperationException(); } @Override public double setMinFreeNodes(double x) { return factory.setMinFreeNodes(x); } @Override public int setMaxIncrease(int maxIncrease) { return factory.setMaxIncrease(maxIncrease); } @Override public double setIncreaseFactor(double increaseFactor) { return factory.setIncreaseFactor(increaseFactor); } @Override public double setCacheRatio(double cacheRatio) { return factory.setCacheRatio(cacheRatio); } /** * Register a callback that is called when garbage collection starts or stops. * * @param o the object whose method is called * @param m the method that gets called */ @Override public void registerGCCallback(final Object o, final Method m) { assertNonNull(m, "garbage collection callback cannot be null"); factory.setGarbageCollectionListener(new GarbageCollectionListener() { @Override public void onStart(int num, int size, int free, long totalTime) { try { m.invoke(o, 1, new GCStats(num, size, free, 0L, totalTime)); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new RuntimeException("Unexpected exception " + e); } } @Override public void onStop(int num, int size, int free, long time, long totalTime) { try { m.invoke(o, 0, new GCStats(num, size, free, time, totalTime)); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new RuntimeException("Unexpected exception " + e); } } }); } /** * Unregister a callback that is called when garbage collection starts or stops. * * @param o the object whose method is called * @param m the method that gets called */ @Override public void unregisterGCCallback(Object o, Method m) { factory.setGarbageCollectionListener(null); } /** * This is the default method that is called every time a garbage collection is performed on the * set of binary decision nodes. * * @param x * 1 if the garbage collection starts, 0 if it completes * @param stats * statistics about the effect of the last garbage collection */ void defaultGCCallback(int x, BDDFactory.GCStats stats) { // we only print something at the end of the garbage collection if (x == 0) System.out.println(stats); } /** * This is the default method that is called every time a resize operation is performed on the * set of binary decision nodes. * * @param oldSize * the old size of the table of nodes * @param newSize * the new size of the table of nodes */ void defaultResizeCallback(int oldSize, int newSize) { System.out.println("Resizing node table from " + oldSize + " to " + newSize); } /** * Register a callback that is called when resize has been performed. * * @param o the object whose method is called * @param m the method that gets called */ @Override public void registerResizeCallback(final Object o, final Method m) { assertNonNull(m, "resize callback cannot be null"); factory.setResizeListener(new ResizeListener() { @Override public void onStart(int num, int oldSize, int newSize, long totalTime) { // nothing } @Override public void onStop(int num, int oldSize, int newSize, long time, long totalTime) { try { m.invoke(o, oldSize, newSize); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new RuntimeException("Unexpected exception " + e); } } }); } /** * Unregister a callback that is called when resize has been performed. * * @param o the object whose method is called * @param m the method that gets called */ @Override public void unregisterResizeCallback(Object o, Method m) { factory.setResizeListener(null); } /** * Register a callback that is called when reorder has been performed. * * @param o the object whose method is called * @param m the method that gets called */ @Override public void registerReorderCallback(Object o, Method m) { // unused } /** * Unregister a callback that is called when reorder has been performed. * * @param o the object whose method is called * @param m the method that gets called */ @Override public void unregisterReorderCallback(Object o, Method m) { // unused } private static class GCStats extends BDDFactory.GCStats { private GCStats(int num, int size, int free, long time, long totalTime) { super(); this.num = num; this.nodes = size; this.freenodes = free; this.time = time; this.sumtime = totalTime; } } /** * Unsupported operation. */ @Override public int setNodeTableSize(int n) { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public int setCacheSize(int n) { throw new UnsupportedOperationException(); } @Override public int varNum() { return bddVarNum; } @Override public int setVarNum(int num) { int oldBddVarNum = bddVarNum; if (num < bddVarNum) throw new BDDException("Trying to decrease the number of variables. It was " + bddVarNum); if (num == bddVarNum) return 0; bddVarNum = num; return oldBddVarNum; } @Override public BDD ithVar(int var) { if (var < 0 || var >= bddVarNum) throw new BDDException("Unknown variable " + var + " max allowed is " + (bddVarNum - 1)); return new JavaBDDAdapterBDD(factory.makeVar(var)); } @Override public BDD nithVar(int var) { if (var < 0 || var >= bddVarNum) throw new BDDException("Unknown variable " + var + " max allowed is " + (bddVarNum - 1)); return new JavaBDDAdapterBDD(factory.makeNotVar(var)); } /** * Unsupported operation. */ @Override public void printAll() { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public void printTable(BDD b) { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public int level2Var(int level) { throw new UnsupportedOperationException(); } @Override public int var2Level(int var) { // TODO this should differ from var only after reordering - and calling duplicateVar return var; } /** * Unsupported operation. */ @Override public void reorder(ReorderMethod m) { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public void autoReorder(ReorderMethod method) { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public void autoReorder(ReorderMethod method, int max) { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public ReorderMethod getReorderMethod() { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public int getReorderTimes() { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public void disableReorder() { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public void enableReorder() { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public int reorderVerbose(int v) { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public void setVarOrder(int[] neworder) { throw new UnsupportedOperationException(); } @Override public BDDPairing makePair() { return new JavaBDDAdapterBDDPairing(); } /** * Unsupported operation. */ @Override public void swapVar(int v1, int v2) { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public int duplicateVar(int var) { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public void addVarBlock(BDD var, boolean fixed) { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public void addVarBlock(int first, int last, boolean fixed) { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public void varBlockAll() { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public void clearVarBlocks() { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public void printOrder() { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public String getVersion() { throw new UnsupportedOperationException(); } @SuppressWarnings("unchecked") @Override public int nodeCount(@SuppressWarnings("rawtypes") Collection r) { return factory.nodeCount(r); } @Override public int getNodeTableSize() { return factory.nodesCount(); } @Override public int getNodeNum() { return factory.nodesCount(); } /** * Unsupported operation. */ @Override public int getCacheSize() { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public int reorderGain() { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public void printStat() { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override protected BDDDomain createDomain(int a, BigInteger b) { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override protected BDDBitVector createBitVector(int a) { throw new UnsupportedOperationException(); } private class JavaBDDAdapterBDD extends BDD { private final com.juliasoft.beedeedee.bdd.BDD bdd; private JavaBDDAdapterBDD(com.juliasoft.beedeedee.bdd.BDD bdd) { this.bdd = bdd; } @Override public BDDFactory getFactory() { return JavaBDDAdapterFactory.this; } @Override public boolean isZero() { return bdd.isZero(); } @Override public boolean isOne() { return bdd.isOne(); } @Override public int var() { return bdd.var(); } @Override public BDD high() { return new JavaBDDAdapterBDD(bdd.high()); } @Override public BDD low() { return new JavaBDDAdapterBDD(bdd.low()); } @Override public BDD id() { return new JavaBDDAdapterBDD(bdd.copy()); } @Override public BDD not() { return new JavaBDDAdapterBDD(bdd.not()); } @Override public BDD ite(BDD thenBDD, BDD elseBDD) { assertNonNull(thenBDD); assertNonNull(elseBDD); return new JavaBDDAdapterBDD(bdd.ite(((JavaBDDAdapterBDD)thenBDD).bdd, ((JavaBDDAdapterBDD)elseBDD).bdd)); } @Override public BDD relprod(BDD that, BDD var) { assertNonNull(that); assertNonNull(var); return new JavaBDDAdapterBDD(bdd.relProd(((JavaBDDAdapterBDD)that).bdd, ((JavaBDDAdapterBDD)var).bdd)); } @Override public BDD compose(BDD g, int var) { assertNonNull(g); if (var < 0 || var >= bddVarNum) throw new BDDException("Unknown variable " + var + " max allowed is " + (bddVarNum - 1)); return new JavaBDDAdapterBDD(bdd.compose(((JavaBDDAdapterBDD)g).bdd, var)); } /** * Unsupported operation. */ @Override public BDD veccompose(BDDPairing pair) { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public BDD constrain(BDD that) { throw new UnsupportedOperationException(); } @Override public BDD exist(BDD var) { assertNonNull(var); return new JavaBDDAdapterBDD(bdd.exist(((JavaBDDAdapterBDD)var).bdd)); } @Override public BDD forAll(BDD var) { assertNonNull(var); return new JavaBDDAdapterBDD(bdd.forAll(((JavaBDDAdapterBDD)var).bdd)); } /** * Unsupported operation. */ @Override public BDD unique(BDD var) { throw new UnsupportedOperationException(); } @Override public BDD restrict(BDD var) { assertNonNull(var); return new JavaBDDAdapterBDD(bdd.restrict(((JavaBDDAdapterBDD)var).bdd)); } @Override public BDD restrictWith(BDD var) { assertNonNull(var); bdd.restrictWith(((JavaBDDAdapterBDD)var).bdd); return this; } @Override public BDD simplify(BDD d) { assertNonNull(d); return new JavaBDDAdapterBDD(bdd.simplify(((JavaBDDAdapterBDD)d).bdd)); } /** * Unsupported operation. */ @Override public BDD support() { throw new UnsupportedOperationException(); } @Override public BDD apply(BDD that, BDDOp opr) { assertNonNull(that); if (opr == and) return and(that); if (opr == xor) return xor(that); if (opr == or) return or(that); if (opr == nand) return new JavaBDDAdapterBDD(bdd.nand(((JavaBDDAdapterBDD)that).bdd)); if (opr == imp) return imp(that); if (opr == biimp) return biimp(that); throw new UnsupportedOperationException("Unsupported operator: " + opr); } @Override public BDD applyWith(BDD that, BDDOp opr) { BDD temp = apply(that, opr); that.free(); return temp; } /** * Unsupported operation. */ @Override public BDD applyAll(BDD that, BDDOp opr, BDD var) { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public BDD applyEx(BDD that, BDDOp opr, BDD var) { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public BDD applyUni(BDD that, BDDOp opr, BDD var) { throw new UnsupportedOperationException(); } @Override public BDD satOne() { return new JavaBDDAdapterBDD(bdd.anySat().toBDD()); } /** * Unsupported operation. */ @Override public BDD fullSatOne() { throw new UnsupportedOperationException(); } /** * Unsupported operation. */ @Override public BDD satOne(BDD var, boolean pol) { throw new UnsupportedOperationException(); } @Override public List<BDD> allsat() { ArrayList<BDD> list = new ArrayList<BDD>(); for (Assignment a : bdd.allSat()) { list.add(new JavaBDDAdapterBDD(a.toBDD())); } return list; } @Override public BDD replace(BDDPairing pair) { try { return new JavaBDDAdapterBDD(bdd.replace(((JavaBDDAdapterBDDPairing)pair).renaming)); } catch (ReplacementWithExistingVarException e) { throw new BDDException("Trying to replace with variable " + e.getVarNum() + " which is already in the bdd"); } } @Override public BDD replaceWith(BDDPairing pair) { try { bdd.replaceWith(((JavaBDDAdapterBDDPairing)pair).renaming); } catch (ReplacementWithExistingVarException e) { throw new BDDException("Trying to replace with variable " + e.getVarNum() + " which is already in the bdd"); } return this; } @Override public int nodeCount() { return bdd.nodeCount(); } /** * Unsupported operation. */ @Override public double pathCount() { return bdd.pathCount(); } @Override public double satCount() { return bdd.satCount(); } @Override public int[] varProfile() { return bdd.varProfile(); } @Override public boolean equals(BDD that) { return that instanceof JavaBDDAdapterBDD && bdd.isEquivalentTo(((JavaBDDAdapterBDD) that).bdd); } @Override public int hashCode() { return bdd.hashCodeAux(); } @Override public void free() { bdd.free(); } /* * Non-abstract methods */ @Override public BDD and(BDD that) { assertNonNull(that); return new JavaBDDAdapterBDD(bdd.and(((JavaBDDAdapterBDD)that).bdd)); } @Override public BDD andWith(BDD that) { assertNonNull(that); bdd.andWith(((JavaBDDAdapterBDD)that).bdd); return this; } @Override public BDD or(BDD that) { assertNonNull(that); return new JavaBDDAdapterBDD(bdd.or(((JavaBDDAdapterBDD)that).bdd)); } @Override public BDD orWith(BDD that) { assertNonNull(that); bdd.orWith(((JavaBDDAdapterBDD)that).bdd); return this; } @Override public BDD xor(BDD that) { assertNonNull(that); return new JavaBDDAdapterBDD(bdd.xor(((JavaBDDAdapterBDD)that).bdd)); } @Override public BDD xorWith(BDD that) { assertNonNull(that); bdd.xorWith(((JavaBDDAdapterBDD)that).bdd); return this; } @Override public BDD imp(BDD that) { assertNonNull(that); return new JavaBDDAdapterBDD(bdd.imp(((JavaBDDAdapterBDD)that).bdd)); } @Override public BDD impWith(BDD that) { assertNonNull(that); bdd.impWith(((JavaBDDAdapterBDD)that).bdd); return this; } @Override public BDD biimp(BDD that) { assertNonNull(that); return new JavaBDDAdapterBDD(bdd.biimp(((JavaBDDAdapterBDD)that).bdd)); } @Override public BDD biimpWith(BDD that) { assertNonNull(that); bdd.biimpWith(((JavaBDDAdapterBDD)that).bdd); return this; } @Override public void printSet() { for (Assignment a : bdd.allSat()) { System.out.println(a); } } } private class JavaBDDAdapterBDDPairing extends BDDPairing { private final Map<Integer, Integer> renaming = new HashMap<Integer, Integer>(); @Override public void set(int oldvar, int newvar) { if (oldvar == newvar) return; if (oldvar < 0 || oldvar >= bddVarNum) throw new BDDException("Unknown variable " + oldvar + " max allowed is " + (bddVarNum - 1)); if (newvar < 0 || newvar >= bddVarNum) throw new BDDException("Unknown variable " + newvar + " max allowed is " + (bddVarNum - 1)); renaming.put(oldvar, newvar); } @Override public void set(int oldvar, BDD newvar) { throw new UnsupportedOperationException(); } @Override public String toString() { return renaming.toString(); } @Override public void reset() { renaming.clear(); } } }