package org.cellocad.MIT.logic_motif_synthesis;
import java.util.*;
public class Optimize{
public static HashMap<String,ArrayList<Circuit>> optimizer1(){
HashSet<String> allowedOps = ConstantProperties.allowedOps;
double maxCost = ConstantProperties.maxCost;
String truthValueToFind = ConstantProperties.truthValueToFind;
String dir = ConstantProperties.dir;
System.out.println(allowedOps);
// Starts the timer
double startTime = System.currentTimeMillis();
//Stops the program if it is run with anything but 2 or 3 inputs.
if (ConstantProperties.numInputs!=3 && ConstantProperties.numInputs!=2){
System.out.println("This only works for two or three inputs.");
return null;
}
//Makes sure that you included a at least the minimum number of gates to be able to find all the truth values.
boolean isPoss = true;
if (allowedOps.size()<4){
isPoss = false;
//The allowed operations must include each operator from at least one of the HashSets in combo.
HashSet<HashSet<String>> combos = new HashSet<HashSet<String>>();
HashSet<String> allowed = new HashSet<String>(Arrays.asList("@"));
combos.add(allowed);
allowed = new HashSet<String>(Arrays.asList("."));
combos.add(allowed);
allowed = new HashSet<String>(Arrays.asList("+","~"));
combos.add(allowed);
allowed = new HashSet<String>(Arrays.asList("&","~"));
combos.add(allowed);
allowed = new HashSet<String>(Arrays.asList(">"));
combos.add(allowed);
allowed = new HashSet<String>(Arrays.asList("$"));
combos.add(allowed);
allowed = new HashSet<String>(Arrays.asList("+","="));
combos.add(allowed);
allowed = new HashSet<String>(Arrays.asList("+","^"));
combos.add(allowed);
allowed = new HashSet<String>(Arrays.asList("&","="));
combos.add(allowed);
allowed = new HashSet<String>(Arrays.asList("&","^"));
combos.add(allowed);
//Determines that there is a problem if it goes through each HashSet in combos and cannot find a Set for which each of
//its operators are contained in the allowed operators.
for (HashSet<String> acc:combos){
boolean problem = false;
for(String s : acc){
if (!allowedOps.contains(s)){
problem = true;
break;
}
}
if (!problem){
isPoss = true;
break;
}
}
}
//Stops the program if there it is not possible to find all truth values with the given operations.
if (!isPoss){
System.out.println("This combination of allowed circuits will not work.");
return null;
}
//Adjusts the name of the output file if it is not a text file.
Date d = new Date();
boolean alterName = false;
if (dir.endsWith("/") || !dir.contains(".json")){
alterName = true;
if (!dir.endsWith("/")){
dir += "/";
}
String fileName = "MaxCost"+maxCost;
for (String op:allowedOps){
fileName += op;
}
fileName = fileName + d.toString().replace(' ', '_').replace(':', '_');
dir = dir + fileName + ".json";
}
System.out.println(dir);
//Calculates the expected number of truth values based on the number of inputs.
int val = 1;
for (int i=0;i<ConstantProperties.numInputs;i++){
val *= 2;
}
int expectedNumTruths = 1;
for (int i=0;i<val;i++){
expectedNumTruths *= 2;
}
System.out.println("We expect to see "+expectedNumTruths+" possible truth values");
//Sorts the allowed operators into three categories: symmetric (a OR b == b OR a), asymmetric (a IMPLIES b != b IMPLIES a),
//and special (NOT a).
HashSet<String> symmetricOps = new HashSet<String> ();
HashSet<String> asymmetricOps = new HashSet<String> ();
HashSet<String> specialOps = new HashSet<String> ();
for (String operator:allowedOps){
if (operator.equals("&")||operator.equals("@")
||operator.equals("+")||operator.equals("^")
||operator.equals(".")||operator.equals("=")){
symmetricOps.add(operator);
}
else if(operator.equals(">")||operator.equals("$")){
asymmetricOps.add(operator);
}
else if (operator.equals("~")){
specialOps.add(operator);
}
}
//Make sure there are no negative costs and defaults any unspecified truth value to 1.
//Also changes any operator with a cost of 0 that is not NOT to 1.
ConstantProperties.setCostPerOp();
for (String op:ConstantProperties.approvedOperators){
if (!(ConstantProperties.costPerOp.containsKey(op))|| (ConstantProperties.costPerOp.get(op)<0) || (!op.equalsIgnoreCase("~") && ConstantProperties.costPerOp.get(op)==0)){
ConstantProperties.costPerOp.put(op,1.0);
System.out.println("Changing the cost of "+op+" to 1.");
}
}
//Removes unrecognized operators
ArrayList<String> inAllowed = new ArrayList<String> ();
ArrayList<String> inCost = new ArrayList<String> ();
for (String operator:ConstantProperties.costPerOp.keySet()){
if (!ConstantProperties.approvedOperators.contains(operator)){
inCost.add(operator);
}
}
for (String operator:inCost){
ConstantProperties.costPerOp.remove(operator);
}
for (String operator:allowedOps){
if (!ConstantProperties.approvedOperators.contains(operator)){
inAllowed.add(operator);
}
}
for (String operator:inAllowed){
allowedOps.remove(operator);
}
//Operators not used
for (String operator:ConstantProperties.approvedOperators){
if (!allowedOps.contains(operator) && ConstantProperties.costPerOp.containsKey(operator)){
ConstantProperties.costPerOp.remove(operator);
}
}
//Initialize the object that stores all the found truth values and the circuits associated with them.
HashMap<String,ArrayList<Circuit>> foundTruthValues = new HashMap<String,ArrayList<Circuit>> ();
//Adds the inputs, one, and zero to foundTruth values, adjusting their truth values based on the number of inputs.
ArrayList<Circuit> temp = new ArrayList<Circuit> ();
Circuit a = new Circuit ("","");
Circuit b = new Circuit ("","");
Circuit c = new Circuit ("","");
Circuit one = new Circuit ("","");
Circuit zero = new Circuit ("","");
if (ConstantProperties.numInputs==2){
one = new Circuit("1","1111");
temp.add(one);
foundTruthValues.put("1111",temp);
temp = new ArrayList<Circuit> ();
zero = new Circuit("0","0000");
temp.add(zero);
foundTruthValues.put("0000",temp);
temp = new ArrayList<Circuit> ();
a = new Circuit("a","0011");
temp.add(a);
foundTruthValues.put("0011",temp);
temp = new ArrayList<Circuit> ();
b = new Circuit("b","0101");
temp.add(b);
foundTruthValues.put("0101",temp);
}
else if (ConstantProperties.numInputs==3){
one = new Circuit("1","11111111");
temp.add(one);
foundTruthValues.put("11111111",temp);
temp = new ArrayList<Circuit> ();
zero = new Circuit("0","00000000");
temp.add(zero);
foundTruthValues.put("00000000",temp);
temp = new ArrayList<Circuit> ();
a = new Circuit("a","00001111");
temp.add(a);
foundTruthValues.put("00001111",temp);
temp = new ArrayList<Circuit> ();
b = new Circuit("b","00110011");
temp.add(b);
foundTruthValues.put("00110011",temp);
temp = new ArrayList<Circuit> ();
c = new Circuit("c","01010101");
temp.add(c);
foundTruthValues.put("01010101",temp);
}
temp = new ArrayList<Circuit> ();
//Creates a HashMap that maps cost to all the circuits with that cost and adds the inputs to cost 0.
HashMap<Double, ArrayList<Circuit>> sortedByCost = new HashMap<Double,ArrayList<Circuit>> ();
if (ConstantProperties.numInputs==2 || ConstantProperties.numInputs==3){
temp.add(a);
temp.add(b);
}
if (ConstantProperties.numInputs==3){
temp.add(c);
}
sortedByCost.put(0.0, temp);
//If there is an operation that with a cost of 0, we must check the found truth values at the end
//because we might build a circuit that would have the same cost as the ones we are iterating through.
boolean has0Cost = ConstantProperties.costPerOp.containsValue(0.0);
//initialize the cost of the first set of circuits.
double alphaCost = 0;
//This is a filtering mechanism to speed up the program. We do not want to save circuits
//that contain truth values that are in this list. Circuits with 0 and the minimum non-zero
//gate cost have their truth values added to the list.
HashSet<String> notAllowed = new HashSet<String> ();
int count = 0;
while(alphaCost <= maxCost && foundTruthValues.size()<expectedNumTruths){
//Go through each cost in sortedByCost from 0 to the max. Set the group of alpha circuits.
ArrayList<Circuit> alphaCircuits = sortedByCost.get(alphaCost);
//If there is no operator with a cost of 0 we can check the alpha circuits for truth values now. Otherwise, we must
//check at the end
if (!has0Cost){
//Add to the list of not allowed truth values things that have a 0 smallest non-zero cost.
if(count<=1){
for (Circuit circ:alphaCircuits){
notAllowed.add(circ.getTruthValue());
}
count++;
}
//Keeps track of the truth values found this round. We want to save all circuits who give these truth values (because
//these will have the same cost as the minimum circuit found for that truth value) or whose truth values we have not
//yet found a circuit for.
ArrayList<String> foundThisRound = new ArrayList<String> ();
for (Circuit circ: alphaCircuits){
String tv = circ.getTruthValue();
if (!foundTruthValues.containsKey(tv)){
ArrayList<Circuit> unique = new ArrayList<Circuit> ();
unique.add(circ);
foundTruthValues.put(tv, unique);
foundThisRound.add(tv);
}
else if(foundTruthValues.containsKey(tv) && foundThisRound.contains(tv)){
foundTruthValues.get(tv).add(circ);
}
}
double currTime = System.currentTimeMillis();
double timeSoFar = (currTime - startTime)/1000;
//Give some status updates.
System.out.println(timeSoFar+" seconds");
System.out.println("Number of truth values found so far: "+foundTruthValues.size());
System.out.println("Dealing with circuits that cost "+alphaCost);
System.out.println(alphaCircuits.size()+" circuits in this level");
//System.out.println(foundTruthValues);
//Write the contents to a file.
System.out.println("Saving to a file. Please do not cancel at this point.");
String tempdir = dir;
if (alterName){
tempdir = tempdir.replace(Double.toString(maxCost), Double.toString(alphaCost));
}
JsonWriter.writeToJson(foundTruthValues, tempdir, timeSoFar, d, alphaCost, allowedOps);
System.out.println("Done Saving.");
if (truthValueToFind != null){
if(foundTruthValues.containsKey(truthValueToFind)){
System.out.println("\nFound "+truthValueToFind+":");
System.out.println(foundTruthValues.get(truthValueToFind));
System.out.println("---------------------------------------");
return foundTruthValues;
}
}
if (foundTruthValues.size() == expectedNumTruths || alphaCost == maxCost){
System.out.println("\nFinished");
System.out.println("---------------------------------------");
return foundTruthValues;
}
System.out.println("---------------------------------------");
}
//In case anything has the same cost as the current level
//Create the special circuits that only require 1 input and give the not of the input. (e.g. (~a), (a^1), (a.0))
int indexAlpha=0;
while (true){
Circuit alpha = alphaCircuits.get(indexAlpha);
for (String operator:specialOps){
//Create the circuit
Circuit newCircuit = new Circuit(operator,alpha);
double newCircuitCost = newCircuit.getCost();
//If it is an acceptable circuits
if(newCircuit.canBeUsed() && !notAllowed.contains(newCircuit.getTruthValue()) && newCircuitCost<=maxCost){
//if we have circuits with that cost already, add this to the list at that cost
if(sortedByCost.containsKey(newCircuitCost) && !sortedByCost.get(newCircuitCost).contains(newCircuit)){
sortedByCost.get(newCircuitCost).add(newCircuit);
}
//If we have not seen this cost before, make a new list with this circuit.
else if(!sortedByCost.containsKey(newCircuitCost)){
ArrayList<Circuit> tempArray = new ArrayList<Circuit>();
tempArray.add(newCircuit);
sortedByCost.put(newCircuitCost,tempArray);
}
}
}
for (String operator:symmetricOps){
if (operator.equals(".") || operator.equals("=")){
Circuit newCircuit = new Circuit(alpha,operator,zero);
double newCircuitCost = newCircuit.getCost();
if(newCircuit.canBeUsed() && !notAllowed.contains(newCircuit.getTruthValue()) && newCircuitCost<=maxCost){
if(sortedByCost.containsKey(newCircuitCost) && !sortedByCost.get(newCircuitCost).contains(newCircuit)){
sortedByCost.get(newCircuitCost).add(newCircuit);
}
else if(!sortedByCost.containsKey(newCircuitCost)){
ArrayList<Circuit> tempArray = new ArrayList<Circuit>();
tempArray.add(newCircuit);
sortedByCost.put(newCircuitCost,tempArray);
}
}
}
else if (operator.equals("@")){
Circuit newCircuit = new Circuit(alpha,operator,alpha);
double newCircuitCost = newCircuit.getCost();
if(newCircuit.canBeUsed() && !notAllowed.contains(newCircuit.getTruthValue()) && newCircuitCost<=maxCost){
if(sortedByCost.containsKey(newCircuitCost) && !sortedByCost.get(newCircuitCost).contains(newCircuit)){
sortedByCost.get(newCircuitCost).add(newCircuit);
}
else if(!sortedByCost.containsKey(newCircuitCost)){
ArrayList<Circuit> tempArray = new ArrayList<Circuit>();
tempArray.add(newCircuit);
sortedByCost.put(newCircuitCost,tempArray);
}
}
}
else if (operator.equals("^")){
Circuit newCircuit = new Circuit(alpha,operator,one);
double newCircuitCost = newCircuit.getCost();
if(newCircuit.canBeUsed() && !notAllowed.contains(newCircuit.getTruthValue()) && newCircuitCost<=maxCost){
if(sortedByCost.containsKey(newCircuitCost) && !sortedByCost.get(newCircuitCost).contains(newCircuit)){
sortedByCost.get(newCircuitCost).add(newCircuit);
}
else if(!sortedByCost.containsKey(newCircuitCost)){
ArrayList<Circuit> tempArray = new ArrayList<Circuit>();
tempArray.add(newCircuit);
sortedByCost.put(newCircuitCost,tempArray);
}
}
}
}
for (String operator:asymmetricOps){
if (operator.equals(">")){
Circuit newCircuit = new Circuit(alpha,operator,zero);
double newCircuitCost = newCircuit.getCost();
if(newCircuit.canBeUsed() && !notAllowed.contains(newCircuit.getTruthValue()) && newCircuitCost<=maxCost){
if(sortedByCost.containsKey(newCircuitCost) && !sortedByCost.get(newCircuitCost).contains(newCircuit)){
sortedByCost.get(newCircuitCost).add(newCircuit);
}
else if(!sortedByCost.containsKey(newCircuitCost)){
ArrayList<Circuit> tempArray = new ArrayList<Circuit>();
tempArray.add(newCircuit);
sortedByCost.put(newCircuitCost,tempArray);
}
}
}
else if (operator.equals("$")){
Circuit newCircuit = new Circuit(one,operator,alpha);
double newCircuitCost = newCircuit.getCost();
if(newCircuit.canBeUsed() && !notAllowed.contains(newCircuit.getTruthValue()) && newCircuitCost<=maxCost){
if(sortedByCost.containsKey(newCircuitCost) && !sortedByCost.get(newCircuitCost).contains(newCircuit)){
sortedByCost.get(newCircuitCost).add(newCircuit);
}
else if(!sortedByCost.containsKey(newCircuitCost)){
ArrayList<Circuit> tempArray = new ArrayList<Circuit>();
tempArray.add(newCircuit);
sortedByCost.put(newCircuitCost,tempArray);
}
}
}
}
//Perform these operations for each circuit in alpha. Note we iterate through alphaCircuits as we potentially change it,
//but since we only get not of alpha and circuits are designed to reject itself if it contains an equal subcircuit,
//we will not get stuck in an infinite loop like (~(~a)) inverted again.
indexAlpha++;
if (indexAlpha==alphaCircuits.size()){
break;
}
}
//Now we want to use the operators that involve another circuit to create more circuits and put them in their
//appropriate place in sortedByCost.
indexAlpha=0;
while (true){
//Go through each circuit in a given cost
Circuit alpha = alphaCircuits.get(indexAlpha);
//Compare it to all circuits with costs that are less than or equal to it
double betaCost = 0;
while(betaCost<=alphaCost){
ArrayList<Circuit> betaCircuits = sortedByCost.get(betaCost);
//if betaCost is still less than alphaCost, we want to combine alpha cost with everything in the circuits
//with betaCost using the allowable operations
if (betaCost != alphaCost){
for (Circuit beta : betaCircuits){
for (String operator:symmetricOps){
Circuit newCircuit = new Circuit(alpha,operator,beta);
double newCircuitCost = newCircuit.getCost();
if(newCircuit.canBeUsed() && !notAllowed.contains(newCircuit.getTruthValue()) && newCircuitCost<=maxCost){
if(sortedByCost.containsKey(newCircuitCost) && !sortedByCost.get(newCircuitCost).contains(newCircuit)){
sortedByCost.get(newCircuitCost).add(newCircuit);
}
else if(!sortedByCost.containsKey(newCircuitCost)){
ArrayList<Circuit> tempArray = new ArrayList<Circuit>();
tempArray.add(newCircuit);
sortedByCost.put(newCircuitCost,tempArray);
}
}
}
//Covers the asymmetric operators. (e.g. does both a>b and b>a)
for (String operator:asymmetricOps){
Circuit newCircuit1 = new Circuit(alpha,operator,beta);
Circuit newCircuit2 = new Circuit(beta,operator,alpha);
double newCircuitCost1 = newCircuit1.getCost();
double newCircuitCost2 = newCircuit2.getCost();
if(newCircuit1.canBeUsed() && !notAllowed.contains(newCircuit1.getTruthValue()) && newCircuitCost1<=maxCost){
if(sortedByCost.containsKey(newCircuitCost1) && !sortedByCost.get(newCircuitCost1).contains(newCircuit1)){
sortedByCost.get(newCircuitCost1).add(newCircuit1);
}
else if(!sortedByCost.containsKey(newCircuitCost1)){
ArrayList<Circuit> tempArray = new ArrayList<Circuit>();
tempArray.add(newCircuit1);
sortedByCost.put(newCircuitCost1,tempArray);
}
}
if(newCircuit2.canBeUsed() && !notAllowed.contains(newCircuit2.getTruthValue()) && newCircuitCost2<=maxCost){
if(sortedByCost.containsKey(newCircuitCost2) && !sortedByCost.get(newCircuitCost2).contains(newCircuit2)){
sortedByCost.get(newCircuitCost2).add(newCircuit2);
}
else if(!sortedByCost.containsKey(newCircuitCost2)){
ArrayList<Circuit> tempArray = new ArrayList<Circuit>();
tempArray.add(newCircuit2);
sortedByCost.put(newCircuitCost2,tempArray);
}
}
}
}
}
//if betaCost == alphaCost then we are combining alpha circuits with other alpha circuits from left to right. We
// want to stop when we reach the alpha circuit.
else if (betaCost == alphaCost){
int indexBeta = 0;
while (true){
Circuit beta = betaCircuits.get(indexBeta);
if(beta.equals(alpha)){
break;
}
for (String operator:symmetricOps){
//Note beta and alpha are switched here to make (a&b) appear rather than (b&a)
Circuit newCircuit = new Circuit(beta,operator,alpha);
double newCircuitCost = newCircuit.getCost();
if(newCircuit.canBeUsed() && !notAllowed.contains(newCircuit.getTruthValue()) && newCircuitCost<=maxCost){
if(sortedByCost.containsKey(newCircuitCost) && !sortedByCost.get(newCircuitCost).contains(newCircuit)){
sortedByCost.get(newCircuitCost).add(newCircuit);
}
else if(!sortedByCost.containsKey(newCircuitCost)){
ArrayList<Circuit> tempArray = new ArrayList<Circuit>();
tempArray.add(newCircuit);
sortedByCost.put(newCircuitCost,tempArray);
}
}
}
for (String operator:asymmetricOps){
Circuit newCircuit1 = new Circuit(alpha,operator,beta);
Circuit newCircuit2 = new Circuit(beta,operator,alpha);
double newCircuitCost1 = newCircuit1.getCost();
double newCircuitCost2 = newCircuit2.getCost();
if(newCircuit1.canBeUsed() && !notAllowed.contains(newCircuit1.getTruthValue()) && newCircuitCost1<=maxCost){
if(sortedByCost.containsKey(newCircuitCost1) && !sortedByCost.get(newCircuitCost1).contains(newCircuit1)){
sortedByCost.get(newCircuitCost1).add(newCircuit1);
}
else if(!sortedByCost.containsKey(newCircuitCost1)){
ArrayList<Circuit> tempArray = new ArrayList<Circuit>();
tempArray.add(newCircuit1);
sortedByCost.put(newCircuitCost1,tempArray);
}
}
if(newCircuit2.canBeUsed() && !notAllowed.contains(newCircuit2.getTruthValue()) && newCircuitCost2<=maxCost){
if(sortedByCost.containsKey(newCircuitCost2) && !sortedByCost.get(newCircuitCost2).contains(newCircuit2)){
sortedByCost.get(newCircuitCost2).add(newCircuit2);
}
else if(!sortedByCost.containsKey(newCircuitCost2)){
ArrayList<Circuit> tempArray = new ArrayList<Circuit>();
tempArray.add(newCircuit2);
sortedByCost.put(newCircuitCost2,tempArray);
}
}
}
indexBeta++;
if (indexBeta==betaCircuits.size()){
break;
}
}
}
//Finds the next cost of the beta circuits
ArrayList<Double> allCosts2 =new ArrayList<Double> (sortedByCost.keySet());
Collections.sort(allCosts2);
if (betaCost != alphaCost){
betaCost = allCosts2.get(allCosts2.indexOf(betaCost)+1);
}
else if (betaCost == alphaCost){
break;
}
}
indexAlpha++;
if (indexAlpha==alphaCircuits.size()){
break;
}
}
if (has0Cost){
//Add to the list of not allowed truth values things that have a 0 smallest non-zero cost.
if(count<=1){
for (Circuit circ:alphaCircuits){
notAllowed.add(circ.getTruthValue());
}
count++;
}
//Keeps track of the truth values found this round. We want to save all circuits who give these truth values (because
//these will have the same cost as the minimum circuit found for that truth value) or whose truth values we have not
//yet found a circuit for.
ArrayList<String> foundThisRound = new ArrayList<String> ();
for (Circuit circ: alphaCircuits){
String tv = circ.getTruthValue();
if (!foundTruthValues.containsKey(tv)){
ArrayList<Circuit> unique = new ArrayList<Circuit> ();
unique.add(circ);
foundTruthValues.put(tv, unique);
foundThisRound.add(tv);
}
else if(foundTruthValues.containsKey(tv) && foundThisRound.contains(tv)){
foundTruthValues.get(tv).add(circ);
}
}
double currTime = System.currentTimeMillis();
double timeSoFar = (currTime - startTime)/1000;
//Give some status updates.
System.out.println(timeSoFar+" seconds");
System.out.println("Number of truth values found so far: "+foundTruthValues.size());
System.out.println("Dealing with circuits that cost "+alphaCost);
System.out.println(alphaCircuits.size()+" circuits in this level");
//System.out.println(foundTruthValues);
System.out.println("Saving to a file. Please do not cancel at this point.");
String tempdir = dir;
if (alterName){
tempdir = tempdir.replace(Double.toString(maxCost), Double.toString(alphaCost));
}
JsonWriter.writeToJson(foundTruthValues, tempdir, timeSoFar, d, alphaCost, allowedOps);
System.out.println("Done Saving.");
if (truthValueToFind != null){
if(foundTruthValues.containsKey(truthValueToFind)){
System.out.println("\nFound "+truthValueToFind+":");
System.out.println(foundTruthValues.get(truthValueToFind));
System.out.println("---------------------------------------");
return foundTruthValues;
}
}
if (foundTruthValues.size() == expectedNumTruths || alphaCost == maxCost){
System.out.println("\nFinished");
System.out.println("---------------------------------------");
return foundTruthValues;
}
System.out.println("---------------------------------------");
}
//Gets the next cost for the alpha circuits.
ArrayList<Double> allCosts =new ArrayList<Double> (sortedByCost.keySet());
Collections.sort(allCosts);
alphaCost = allCosts.get(allCosts.indexOf(alphaCost)+1);
}
System.out.println("Finished");
return foundTruthValues;
}
}