package org.cellocad.MIT.dnacompiler;
/**
* Created by Bryan Der on 3/26/14.
*/
import org.cellocad.MIT.dnacompiler.Gate.GateType;
import java.util.*;
/**
*
* Miscellaneous functions that were in LogicCircuit.java being moved here.
*
*/
public class LogicCircuitUtil{
/**
*
* Returns partially-abstract logic circuit(s) where the input gates and output gate(s) are assigned
*
* Default: input1 = pTac, input2 = pTet, input3 = pBAD
* return a single LogicCircuit
*
* if Args.permute_inputs:
* permute all possible assignments of inducible promoters to input gates
* and return ArrayList of LogicCircuits
*
*/
public static ArrayList<LogicCircuit> getInputAssignments(LogicCircuit lc, GateLibrary gate_library, boolean permute_inputs) {
ArrayList<LogicCircuit> partially_abstract_lcs = new ArrayList<LogicCircuit>();
ArrayList<int[]> indexes_set = new ArrayList<int[]>();
//permute input assignments, order doesn't matter
if(permute_inputs) {
int n_input_gates = lc.get_input_gates().size();
int n_bioinputs = gate_library.get_INPUT_NAMES().length;
int[] n = new int[n_input_gates];
int[] Nr = new int[n_bioinputs];
for (int i = 0; i<n_bioinputs; ++i){
Nr[i] = n_bioinputs-1;
}
Permute.getIndexProduct(indexes_set, n, Nr, 0); //indexes_set gets populated here
}
//order matters, 1 fixed assignment (this is the default behavior)
else {
int[] fixed_inputs = new int[lc.get_input_gates().size()];
for(int i=0; i<lc.get_input_gates().size(); ++i) {
fixed_inputs[i] = i; // [ 3, 2, 1, 0 ] for a 4-input circuit
}
indexes_set.add(fixed_inputs); //size == 1
}
for(int a[]: indexes_set) {
LogicCircuit input_lc = new LogicCircuit(lc);
for(int i=0; i<input_lc.get_output_gates().size(); ++i) {
input_lc.get_output_gates().get(i).Name = gate_library.get_OUTPUT_NAMES()[i];
}
for(int i=0; i<input_lc.get_input_gates().size(); ++i) {
input_lc.get_input_gates().get(i).Name = gate_library.get_INPUT_NAMES()[a[i]]; //change the name, which will allow RPU values to change when calling setInputRPU
}
setInputRPU(input_lc, gate_library);
partially_abstract_lcs.add(input_lc); //unassigned_lcs from DNAC
}
// TODO hard-coded for Jonghyeon
boolean p_BAD_as_fisrt_input = false;
if(p_BAD_as_fisrt_input) {
ArrayList<LogicCircuit> specified_lc = new ArrayList<LogicCircuit>();
for(LogicCircuit specified_input_lc: partially_abstract_lcs) {
if (specified_input_lc.get_input_gates().get(0).Name.equals("pBAD")) {
specified_lc.add(specified_input_lc);
}
}
return specified_lc;
}
//
else {
return partially_abstract_lcs; //size == 1 if Args.permute_inputs == false
}
}
/**
*
* For a 3-input circuit, the input gates have these logics:
* gate_0 = 00001111
* gate_1 = 00110011
* gate_2 = 01010101
*
*/
public static void setInputLogics(LogicCircuit lc){
int n_inputs = lc.get_input_gates().size();
int[] n = new int[n_inputs];
int[] Nr = new int[n_inputs];
for (int i = 0; i<n_inputs; ++i){
Nr[i] = 1;
}
ArrayList<int[]> input_logics_set = new ArrayList<int[]>();
Permute.getLogicPermutation(input_logics_set, n, Nr, 0);
//8 rows, int[] size == 3
// 000
// 001
// 010
// 011
// 100
// 101
// 110
// 111
for(int i=0; i<lc.get_input_gates().size(); ++i) {
Gate gate_i = lc.get_input_gates().get(i);
ArrayList<Integer> logics = new ArrayList<Integer>();
//gate_0 = 00001111
//gate_1 = 00110011
//gate_2 = 01010101
for(int[] input_logics: input_logics_set){ // rows in truth table
logics.add(new Integer(input_logics[i])); // input_logics.length == n_inputs
gate_i.set_unvisited( false );
}
/*for(int row=0; row<logics.size(); ++row) {
if(Args.dontcare_rows.contains(row)) {
logics.set(row, 2);
}
}*/
gate_i.set_logics(logics);
}
}
/**
*
* RPU = relative expression units
* Once names are assigned to input gates (getInputAssignments), add high RPU if logic is 1, add low RPU if logic is 0
*
* For normal scoring or histogram scoring
*
*/
public static void setInputRPU(LogicCircuit lc, GateLibrary gate_library) {
for(Gate input_gate: lc.get_input_gates()) {
if(input_gate.get_logics() == null || input_gate.get_logics().size() == 0) {
throw new IllegalStateException("trying to initialize rpus before initializing logics. exiting.");
}
ArrayList<Double> rpus = new ArrayList<Double>();
ArrayList<double[]> convrpus = new ArrayList<double[]>();
for(Integer i: input_gate.get_logics()) {
if(i == 0) {
rpus.add(gate_library.get_INPUTS_OFF().get(input_gate.Name)); //low
convrpus.add(gate_library.get_INPUTS_HIST_OFF().get(input_gate.Name)); //low
}
else if(i == 1) {
rpus.add(gate_library.get_INPUTS_ON().get(input_gate.Name)); //high
convrpus.add(gate_library.get_INPUTS_HIST_ON().get(input_gate.Name)); //high
}
else if(i == 2) {
rpus.add(0.0);
convrpus.add(new double[input_gate.get_histogram_bins().get_NBINS()]);
}
}
input_gate.set_unvisited( false );
input_gate.set_unvisited( false );
input_gate.set_outrpus(rpus);
input_gate.set_histogram_rpus(convrpus);
}
}
/**
*
* Alec's priorities. The only firm requirement for promoter order is no roadblocking.
* However, roadblocking is not actually boolean in a cell, Alec established these priorities
* based measured roadblocking values.
*
* Lower number means further upstream, higher number means further downstream
*
*/
/*public static HashMap<String, Integer> getPromoterPriorities() {
HashMap<String, Integer> priorities = new HashMap<String, Integer>();
priorities.put("pTac", -6);
priorities.put("pBAD", -5);
priorities.put("SrpR", -4);
priorities.put("PhlF", -3);
priorities.put("BM3R1", -2);
priorities.put("QacR", -1);
priorities.put("pLuxStar", 1);
priorities.put("pTet", 2);
priorities.put("AmtR", 3);
priorities.put("BetI", 4);
priorities.put("IcaRA", 5);
priorities.put("HlyIIR", 6);
priorities.put("LitR", 7);
priorities.put("AmeR", 8);
priorities.put("PsrA", 9);
priorities.put("LmrA", 10);
priorities.put("pSal", 11);
return priorities;
}*/
/**
*
* Alec's cloning method puts repressors in slots for legacy and practical reasons.
* For example, PhlF is almost always used, so it is given a slot connected to the backbone.
* The infrequently used repressors fall somewhere in the middle.
*
* This is the order of those slots.
*
*/
/*public static HashMap<String, Integer> getCloningSlotPriorities() {
HashMap<String, Integer> priorities = new HashMap<String, Integer>();
priorities.put("PhlF", 1);
priorities.put("SrpR", 2);
priorities.put("BM3R1", 3);
priorities.put("BetI", 4);
priorities.put("AmeR", 5);
priorities.put("LitR", 6);
priorities.put("IcaRA", 7);
priorities.put("QacR", 8);
priorities.put("PsrA", 9);
priorities.put("LmrA", 10);
priorities.put("HlyIIR", 11);
priorities.put("AmtR", 12);
return priorities;
}*/
/**
*
* An assembly scar separates each txn unit. Scars are one-time use only.
*
* Some scars / scar combinations are better than others. These are the scar priorities that Alec uses.
*
*/
/*public static HashMap<String, Integer> getScarPriorities() {
HashMap<String, Integer> priorities = new HashMap<String, Integer>();
priorities.put("E-scar", 0); //first module start
priorities.put("D-scar", 1);
priorities.put("B-scar", 2);
priorities.put("A-scar", 3);
priorities.put("F-scar", 4);
priorities.put("G-scar", 5);
priorities.put("X-scar", 6);
priorities.put("V-scar", 7);
priorities.put("U-scar", 8);
priorities.put("R-scar", 9);
//not in use by Alec
priorities.put("Q-scar", 11);
priorities.put("P-scar", 12);
priorities.put("O-scar", 13);
priorities.put("N-scar", 14);
priorities.put("M-scar", 15);
priorities.put("L-scar", 16);
priorities.put("Y-scar", 17);
priorities.put("S-scar", 998); //ribo prefix, used internally in gates
priorities.put("C-scar", 999); //last module end
return priorities;
}*/
public static void sortGatesByStage(LogicCircuit lc){
for (Gate g : lc.get_logic_gates()) {
GateUtil.calculateDistanceToFarthestInput(g);
}
LogicCircuitUtil.sortLogicGatesByDist2In(lc);
Collections.reverse(lc.get_logic_gates());
}
public static void sortLogicGatesByDist2In(LogicCircuit lc) {
Collections.sort(lc.get_logic_gates(),
new Comparator<Gate>() {
public int compare(Gate g1, Gate g2) {
int result = 0;
if ( (g1.get_distance_to_input() - g2.get_distance_to_input()) > 1e-10 ){
result = -1;
} else if ( (g1.get_distance_to_input() - g2.get_distance_to_input()) < -1.0e-10){
result = 1;
}
else if ( (g1.get_distance_to_input() - g2.get_distance_to_input() == 0) ) {
if(g1.Index < g2.Index) {
return -1;
}
else {
return 1;
}
}
return result;
}
}
);
}
public static void sortGatesByIndex(LogicCircuit lc) {
Collections.sort(lc.get_Gates(),
new Comparator<Gate>() {
public int compare(Gate g1, Gate g2) {
int result = 0;
if ( g1.Index < g2.Index ){
result = -1;
}
else {
result = 1;
}
return result;
}
}
);
}
public static boolean libraryGatesCoverCircuitGates(LogicCircuit lc, GateLibrary gate_library) {
HashSet<String> used_groups = new HashSet<String>();
HashMap<GateType, Integer> assigned_groups = new HashMap<GateType, Integer>();
for (Gate.GateType gtype : lc.get_logic_gate_types().keySet()) {
if (!assigned_groups.containsKey(gtype)) {
assigned_groups.put(gtype, 0);
}
if(!gate_library.get_GATES_BY_GROUP().containsKey(gtype)) {
return false;
}
for (String group_name : gate_library.get_GATES_BY_GROUP().get(gtype).keySet()) {
if (assigned_groups.get(gtype) < lc.get_gate_types().get(gtype).size()) {
if (!used_groups.contains(group_name)) {
used_groups.add(group_name);
Integer n = assigned_groups.get(gtype);
assigned_groups.put(gtype, (n + 1));
}
}
}
}
for(Gate.GateType gtype: assigned_groups.keySet()) {
if(assigned_groups.get(gtype) < lc.get_gate_types().get(gtype).size()) {
return false;
}
}
return true;
}
public static void setInputOutputGroups(LogicCircuit lc) {
for(Gate g: lc.get_input_gates()) {
g.Group = g.Name;
g.Regulator = g.Name;
}
for(Gate g: lc.get_output_gates()) {
g.Group = g.Name;
g.Regulator = g.Name;
}
}
public static ArrayList<LogicCircuit> uniqueRepressorAssignments(ArrayList<LogicCircuit> assigned_lcs) {
HashMap<String, LogicCircuit> unique_repressor_assignments = new HashMap<>();
for(int i=0; i<assigned_lcs.size(); ++i) {
LogicCircuit lc = assigned_lcs.get(i);
ArrayList<String> tus = new ArrayList<String>();
String asn = "";
for(Gate g: lc.get_logic_gates()) {
asn += g.Regulator;
ArrayList<String> promoter_names = new ArrayList<>();
String cds = "";
for(Part p: g.get_txn_units().get(0)) {
if(p.get_type().equalsIgnoreCase("promoter")) {
promoter_names.add( p.get_name() );
}
if(p.get_type().equalsIgnoreCase("cds")) {
cds = p.get_name();
}
}
Collections.sort(promoter_names);
String tu = "";
for(String s: promoter_names) {
tu += s;
}
tu += cds;
tus.add(tu);
}
Collections.sort(tus);
asn = "";
for(String s: tus) {
asn += s + "_";
}
if(!unique_repressor_assignments.containsKey(asn)) {
unique_repressor_assignments.put(asn, lc);
}
}
return new ArrayList<LogicCircuit>(unique_repressor_assignments.values());
}
public static void renameGatesWires(LogicCircuit lc) {
for(Gate g: lc.get_Gates()) {
if(g.Type != GateType.INPUT && g.Type != GateType.OUTPUT && g.Type != GateType.OUTPUT_OR) {
g.Name = "g"+g.RIndex;
}
}
for(Wire w: lc.get_Wires()) {
if(w.To != null) {
if(w.To.Type == GateType.INPUT) {
w.Name = w.To.Name;
}
else {
w.Name = "w" + w.To.RIndex;
}
}
}
}
public static boolean dataFoundForAllTandemPromoters(GateLibrary gate_library, LogicCircuit lc) {
ArrayList<Gate> logic_and_output_gates = new ArrayList<>();
logic_and_output_gates.addAll(lc.get_logic_gates());
logic_and_output_gates.addAll(lc.get_output_gates());
for(Gate g: logic_and_output_gates) {
String var = "x"; //hard-coded
if(g.get_variable_names().size() == 1) {
var = g.get_variable_names().get(0);
}
if (g.get_variable_wires().get(var).size() == 2) { //hard-coded
ArrayList<String> fanin_gate_names = new ArrayList<>();
Gate child1 = g.getChildren().get(0);
Gate child2 = g.getChildren().get(1);
if (child1.Type == Gate.GateType.INPUT) {
fanin_gate_names.add("input_" + child1.Name);
} else {
fanin_gate_names.add(child1.Name);
}
if (child2.Type == Gate.GateType.INPUT) {
fanin_gate_names.add("input_" + child2.Name);
} else {
fanin_gate_names.add(child2.Name);
}
String tandem_promoter_name_1 = fanin_gate_names.get(0) + "_" + fanin_gate_names.get(1);
String tandem_promoter_name_2 = fanin_gate_names.get(1) + "_" + fanin_gate_names.get(0);
boolean tp_exists = false;
if (gate_library.get_TANDEM_PROMOTERS().containsKey(tandem_promoter_name_1)) {
tp_exists = true;
} else if (gate_library.get_TANDEM_PROMOTERS().containsKey(tandem_promoter_name_2)) {
tp_exists = true;
}
if(!tp_exists) {
return false;
}
}
}
return true;
}
}