package com.juliasoft.beedeedee.examples.circuits;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import com.juliasoft.beedeedee.bdd.BDD;
import com.juliasoft.beedeedee.examples.circuits.jccgen.CircuitParser;
import com.juliasoft.beedeedee.examples.circuits.jccgen.ParseException;
import com.juliasoft.beedeedee.factories.Factory;
import com.juliasoft.beedeedee.factories.Factory.GarbageCollectionListener;
import com.juliasoft.beedeedee.factories.Factory.ResizeListener;
/**
* Parses .bench files of ITC99 benchmark circuits, and builds the transition
* relation. See Jerry R. Burch, Edmund M. Clarke, and David E. Long.
* Representing circuits more efficiently in symbolic model checking. In DAC,
* pages 403–407, 1991.
*
* In order to resolve compilation errors, please process the file circuit.jj
* with JavaCC.
*/
public class CircuitConstructor {
private static final class PartialCalculator implements Callable<BDD> {
private int id;
private int numberOfThreads;
private String[] dffsArray;
public PartialCalculator(int id, int numberOfThreads, String[] dffsArray) {
this.id = id;
this.numberOfThreads = numberOfThreads;
this.dffsArray = dffsArray;
}
@Override
public BDD call() throws Exception {
BDD partialTransitionRelation = fact.makeOne();
for (int i = id; i < dffsArray.length; i += numberOfThreads) {
String key = dffsArray[i];
BDD biimp = bdds.get(key).biimp(dffs.get(key));
partialTransitionRelation.andWith(biimp);
}
return partialTransitionRelation;
}
}
// name -> bdd map
private static HashMap<String, BDD> bdds = new HashMap<String, BDD>();
// name -> operation map
private static HashMap<String, Operation> opMap;
private static Factory fact;
private static int varNumber = 0;
// name -> dffs map (a dff, d flip flop, is a memory)
private static HashMap<String, BDD> dffs = new HashMap<>();
public static void main(String[] args)
throws FileNotFoundException, ParseException, InterruptedException, ExecutionException {
/*
* parse file args[0]
*/
File f = new File(args[0]);
FileReader fr = new FileReader(f);
CircuitParser cp = new CircuitParser(fr);
cp.Start();
int numberOfThreads = 1;
/*
* pass number of threads in args[1] for parallel computation
*/
if (args.length > 1) {
numberOfThreads = Integer.parseInt(args[1]);
}
/*
* create bdd factory, set listeners
*/
fact = Factory.mk(50_000_000, 100_000);
fact.setMaxIncrease(1_000_000);
fact.setGarbageCollectionListener(new GarbageCollectionListener() {
@Override
public void onStop(int num, int size, int free, long time, long totalTime) {
System.out.println(" done. " + size + " " + free + " " + totalTime);
}
@Override
public void onStart(int num, int size, int free, long totalTime) {
System.out.print("\nGC... " + num);
}
});
fact.setResizeListener(new ResizeListener() {
@Override
public void onStop(int num, int oldSize, int newSize, long time, long totalTime) {
System.out.println(" done. " + oldSize + " " + newSize + " " + time + "/" + totalTime);
}
@Override
public void onStart(int num, int size, int free, long totalTime) {
System.out.print("\nResize... " + num);
}
});
/*
* create bdds for input vars
*/
for (String input : cp.getInputs()) {
bdds.put(input, fact.makeVar(varNumber++));
}
opMap = cp.getOpMap();
/*
* calculate saved operations
*/
for (String op : opMap.keySet()) {
calc(op);
}
/*
* build transition relation
* (v0' <-> f_0(V)) & (v1' <-> f_1(V)) & ... & (v_{n-1}' <-> f__{n-1}(V))
*/
ExecutorService executorService = Executors.newFixedThreadPool(numberOfThreads);
String[] dffsArray = dffs.keySet().toArray(new String[0]);
ArrayList<Future<BDD>> futures = new ArrayList<>();
for (int i = 0; i < numberOfThreads; i++) {
PartialCalculator partialCalculator = new PartialCalculator(i, numberOfThreads, dffsArray);
futures.add(executorService.submit(partialCalculator));
}
BDD transitionRelation = fact.makeOne();
for (Future<BDD> future : futures) {
transitionRelation.andWith(future.get());
}
executorService.shutdown();
fact.done();
}
private static BDD calc(String name) {
if (bdds.containsKey(name)) {
return bdds.get(name);
}
Operation o = opMap.get(name);
BDD bdd = null;
String op;
switch (o.getOp()) {
case "DFF":
op = o.getArgs().get(0);
String dffName = name + "DFF";
bdds.put(dffName, fact.makeVar(varNumber++)); // 'next state' variable
bdds.put(name, fact.makeVar(varNumber++)); // 'current state' variable
bdd = calc(op);
dffs.put(dffName, bdd);
break;
case "NOT":
op = o.getArgs().get(0);
bdd = calc(op).not();
break;
case "AND":
bdd = fact.makeOne();
for (String subOp : o.getArgs()) {
bdd = bdd.and(calc(subOp));
}
break;
case "NAND":
bdd = fact.makeZero();
for (String subOp : o.getArgs()) {
bdd = bdd.nand(calc(subOp));
}
break;
case "OR":
bdd = fact.makeZero();
for (String subOp : o.getArgs()) {
bdd = bdd.or(calc(subOp));
}
break;
case "NOR":
bdd = fact.makeZero();
for (String subOp : o.getArgs()) {
bdd = bdd.or(calc(subOp)).not();
}
break;
default:
throw new UnsupportedOperationException("Unsupported op: " + o.getOp());
}
bdds.put(name, bdd);
return bdd;
}
}