package org.cellocad.MIT.dnacompiler;
/**
* Created by Bryan Der on 3/26/14.
*/
import lombok.Getter;
import lombok.Setter;
import org.cellocad.BU.dom.DWire;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import java.util.ArrayList;
import java.util.HashMap;
/**
* Connected Gates form a LogicCircuit
*
* Gate is a node in a Directed Acyclic Graph.
*
*/
/**
* these properties are ignored in order to convert a DAG to a JSON object. Otherwise,
* the Gson conversion encounters an infinite loop because Gates point to Wires and Wires point to Gates.
*/
@JsonIgnoreProperties({"Outgoing", "outW", "children"})
public class Gate {
//a list of allowed gate types.
public enum GateType{
INPUT,
OUTPUT,
OUTPUT_OR,
OR,
AND,
NOR,
NOT;
}
/**
*
* Wires just connect gates, there are not data associated with Wire objects.
* Gate objects have all the data, such as RPUs, etc.
*
* Potential point of confusion: RPUs are properties of promoters, and promoters are 'wires',
* but by associating RPUs with gates, the idea is that all fan-out promoters have the same RPU values
* for the gate.
*
*/
/**
* Explanation of the DAG data structure.*
* g1.Outgoing refers to the first input wire for g1
* g1.Outgoing.Next refers to the second input wire for g1 (if any)
* g1.Outgoing.Next.Next refers to the third input wire for g1 (if any)
*
* g1.Outgoing.To is the gate on the other end of the Outgoing wire
* g1.Outgoing.Next.To is the gate on the other end of the Outgoing.Next wire
*
* The .From property is not really used because the graphs are typically traversed from output to input
*
* Input gates have no Outgoing wire.
*/
//DAG
public DWire outW = new DWire();
public int Index = -1;
public int RIndex= -1; //a renumbered index so that the first logic gate has index 1.
public String Name = "";
public String Group = "";
public String Regulator = "";
public String Inducer = ""; //added for an IWBDA demo, not really used in Cello.
public String ColorHex = "";//six character hexidecimal color.
public String System = ""; //currently only used to check for CRIPSRi system to design NOR gates with separate txn units instead of tandem promoters
public GateType Type = null;
public Wire Outgoing = null; //toward INPUTS. note that a gate is not aware of its wire(s) going toward OUTPUT
public int Outgoing_wire_index = -1;
public int stage = 0; //longest path, depth of gate
public Gate(){}
//constructor used in NetSynth
//When creating a DAGW object, NetSynth uses the MIT/dnacompiler Gate and Wire objects.
public Gate(int ind, GateType dType)
{
Index = ind;
RIndex = ind;
Type = dType;
stage = 0;
if(dType == GateType.NOR)
{
Name = "~|";
}
else if(dType == GateType.NOT)
{
Name = "~";
}
else if(dType == GateType.AND)
{
Name = "&";
}
else if(dType == GateType.OR)
{
Name = "|";
}
else
{
Name = "";
}
outW = new DWire();
this.Outgoing = null;
}
//constructor used in NetSynth
public Gate(int ind, GateType dType,Wire de)
{
Index = ind;
RIndex = ind;
Type = dType;
stage = 0;
if(dType == GateType.NOR)
{
Name = "~|";
}
else if(dType == GateType.NOT)
{
Name = "~";
}
else if(dType == GateType.AND)
{
Name = "&";
}
else if(dType == GateType.OR)
{
Name = "|";
}
else
{
Name = "";
}
this.Outgoing = de;
outW = new DWire();
}
//constructor used in NetSynth
public Gate(int ind, String dType)
{
Index = ind;
RIndex = ind;
Type = GateType.valueOf(dType);
stage = 0;
if(Type == GateType.NOR)
{
Name = "~|";
}
else if(Type == GateType.NOT)
{
Name = "~";
}
else if(Type == GateType.AND)
{
Name = "&";
}
else if(Type == GateType.OR)
{
Name = "|";
}
else
{
Name = "";
}
outW = new DWire();
this.Outgoing = null;
}
//constructor used in NetSynth
public Gate(int ind, String dType,Wire de)
{
Index = ind;
RIndex = ind;
Type = GateType.valueOf(dType);
stage = 0;
if(Type == GateType.NOR)
{
Name = "~|";
}
else if(Type == GateType.NOT)
{
Name = "~";
}
else if(Type == GateType.AND)
{
Name = "&";
}
else if(Type == GateType.OR)
{
Name = "|";
}
else
{
Name = "";
}
this.Outgoing = de;
outW = new DWire();
}
/**
*
* Copy constructor.
*
*/
public Gate(Gate gate){
_unvisited = gate._unvisited;
_scores = new Scores(gate.get_scores());
_distance_to_input = gate._distance_to_input;
_params = gate._params;
_variable_names = new ArrayList<String>(gate._variable_names);
_variable_thresholds = gate._variable_thresholds;
_variable_wires = gate._variable_wires;
_equation = gate._equation;
_downstream_parts = gate._downstream_parts;
_regulable_promoter = gate._regulable_promoter;
_toxtable = gate._toxtable;
_toxicity = gate._toxicity;
_logics = gate._logics;
_histogram_rpus = gate._histogram_rpus;
_histogram_bins = gate._histogram_bins;
_xfer_hist = gate._xfer_hist;
_unit_conversion = gate._unit_conversion;
// Deep copy of rpus. Other data are not deep-copied to save memory.
//_outrpus = gate._outrpus; //this would be the shallow copy of _outrpus
if(!gate._outrpus.isEmpty()) {
_outrpus = new ArrayList<Double>();
for(Double d: gate._outrpus) {
_outrpus.add(new Double(d));
}
}
_inrpus = gate._inrpus;
stage = gate.stage;
outW = gate.outW;
Index = gate.Index;
RIndex = gate.RIndex;
Name = gate.Name;
Group = gate.Group;
Regulator = gate.Regulator;
ColorHex = gate.ColorHex;
System = gate.System;
Type = gate.Type;
Outgoing = gate.Outgoing;
Outgoing_wire_index = gate.Outgoing_wire_index;
}
@Override
public String toString(){
return Index + " " + Type + " " + Name;
}
/**
*
* Returns array of child gates
*
*/
public ArrayList<Gate> getChildren(){
/**
* It's called 'Outgoing' because the DAG is traversed from the output(s) toward the input(s).
* This can cause confusion because most people think about circuits from the inputs toward the outputs.
*
* Inputs have no Outgoing wires.
* Logic/Output gates have at least one Outgoing wire.
* If a gate has more than one input, these would be accessed using:
* Outgoing.Next (second input), Outgoing.Next.Next (third input).
*/
ArrayList<Gate> children = new ArrayList<Gate>();
if ( (this.Outgoing != null) && (this.Outgoing.To != null)){
children.add(this.Outgoing.To);
Wire w = this.Outgoing;
while(w.Next != null && w.Next.To != null) {
children.add(w.Next.To);
w = w.Next;
}
}
return children;
}
/////////////////////////
//
// Private member data
//
/////////////////////////
// @Getter @Setter private boolean _tp_exists = false;
@Getter @Setter private int _distance_to_input = -1;
//TODO get rid of this one
@Getter @Setter private int _farthest_dist2in = 1;
//computed values
//arraylist represents rows of truth table, Integer is either 0 or 1
@Getter @Setter private ArrayList<Integer> _logics = new ArrayList<Integer>();
//arraylist represents rows of truth table, Double is the RPU value.
//The RPU value should be low if the logic value is 0, the RPU value should be high if the logic value is 1.
@Getter @Setter private ArrayList<Double> _outrpus = new ArrayList<Double>();
//map input RPUs to variable name, "x"
@Getter @Setter private HashMap<String, ArrayList<Double>> _inrpus = new HashMap<>();
/**
* if the output module is on a different plasmid than the circuit module,
* the RPU units must be adjusted for the change in plasmid copy number.
* In our work, gates were characterized on p15A, but the output module was on pSC101.
* The conversion factor is specified in the 'genetic_locations' collection of the UCF.
*/
@Getter @Setter private Double _unit_conversion = 1.0;
//predicted growth scores: arraylist is rows of truth table, Double is predicted relative growth value
//based on the RPU value in that row for this gate.
@Getter @Setter private ArrayList<Double> _toxicity = new ArrayList<Double>();
//arraylist represents the rows in the truth table, the double[] represents the histogram
//the length of the double[] is the same length as HistogramBin._LOG_BIN_CENTERS[]
@Getter @Setter private ArrayList< double[] > _histogram_rpus = new ArrayList< double[] >();
@Getter @Setter private ArrayList< double[] > _in_histogram_rpus = new ArrayList< double[] >();
//min, max, bin width, bin centers
@Getter @Setter private HistogramBins _histogram_bins = new HistogramBins();
/////////// response function //////////
//for example, ymax:5.0, ymin:0.02, K:0.8, n:2.5
@Getter @Setter private HashMap<String, Double> _params = new HashMap<>();
//for example, "x" would be the variable name in "ymin+(ymax-ymin)/(1.0+(x/K)^n)"
@Getter @Setter private ArrayList<String> _variable_names = new ArrayList<>();
//threshold analysis defines a forbidden zone of input values for a gate
/**
* "x": [0.4, 3.0]
* "x" is the independent variable in the hill function, for example.
* index 0 is the low threshold
* index 1 is the high threshold
*/
@Getter @Setter private HashMap<String, Double[]> _variable_thresholds = new HashMap<>();
/**
* Mapping a variable name to wires.
*
* for a 2-input gate such as AND, it matters which wire maps to which variable name in the response function equation.
* for a 1-input gate such as NOT, which can actually be implemented as a NOR via tandem promoters,
* multiple wires will map to the same variable name in the response function equation.
* This is what allows a 1-dimensional hill equation to serve as as the response function for a 2-input NOR gate.
* RPU values from both wires in a NOR gate will contribute to the input RPU value that is applied to the Hill equation.
*/
@Getter @Setter private HashMap<String, ArrayList<Wire>> _variable_wires = new HashMap<>();
//for example, "ymin+(ymax-ymin)/(1.0+(x/K)^n)"
@Getter @Setter private String _equation;
//from the UCF
/**
* HistogramXfer is just a container for _xfer_interp,
* which is the interpolated square matrix representing a probabilistic transfer function.
*/
@Getter @Setter private HistogramXfer _xfer_hist = new HistogramXfer();
//from the UCF
/**
* List of x,y value pairs. x is the input RPU, y is the normalized growth value
*/
@Getter @Setter private ArrayList<Pair> _toxtable = new ArrayList<Pair>();
//parts
/**
* gates have one or more expression cassettes: ribozyme, rbs, cds, terminator.
* an AND gate will have two expression cassettes, for example.
*/
@Getter @Setter private HashMap<String, ArrayList<Part>> _downstream_parts = new HashMap<>();
//primitive gates have a single output, thus a single regulable promoter
@Getter @Setter private Part _regulable_promoter;
//a transcription unit is an array of Parts.
//the set of transcriptional units for a circuit is an array of an array of Parts.
@Getter @Setter private ArrayList<ArrayList<Part>> _txn_units = new ArrayList<ArrayList<Part>>();
//score
/**
* it's an object instead of a simple value because there are a few different types of scores to choose from.
* the default is the ON/OFF ratio, where ON is the lowest ON and OFF is the highest OFF.
*/
@Getter @Setter private Scores _scores = new Scores();
//used to visit each gate once during recursive traversal of a graph data structure
@Getter @Setter private boolean _unvisited = true;
}