/*************************************************************************
* *
* This file is part of the 20n/act project. *
* 20n/act enables DNA prediction for synthetic biology/bioengineering. *
* Copyright (C) 2017 20n Labs, Inc. *
* *
* Please direct all queries to act@20n.com. *
* *
* This program 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. *
* *
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>. *
* *
*************************************************************************/
package com.act.reachables;
import act.shared.helpers.P;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class OutdatedWavefrontExpansion extends SteppedTask {
Set<Long> R;
HashMap<Long, List<Long>> rxn_needs;
HashMap<Integer, Set<Long>> R_by_layers;
int currentLayer;
public OutdatedWavefrontExpansion() {
this.R = new HashSet<Long>();
this.R_by_layers = new HashMap<Integer, Set<Long>>();
this.rxn_needs = computeRxnNeeds();
this.currentLayer = 0;
}
private HashMap<Long, List<Long>> computeRxnNeeds() {
HashMap<Long, List<Long>> needs = new HashMap<Long, List<Long>>();
for (Long r : ActData.instance().rxnSubstrates.keySet()) {
needs.put(r, new ArrayList<Long>(ActData.instance().rxnSubstrates.get(r)));
}
return needs;
}
protected Set<Long> productsOf(Set<Long> enabledRxns) {
Set<Long> P = new HashSet<Long>();
for (Long r : enabledRxns) {
P.addAll(ActData.instance().rxnProducts.get(r));
}
return P;
}
@Override
public double percentDone() {
return anyEnabledReactions(null) ? 0 : 100;
}
@Override
public void doMoreWork() {
pushWaveFront(null, true /* do increment layer counter */);
}
private void addAllHostMetabolites(long hostID) {
pushWaveFront(hostID, false /* do not increment layer counter */);
}
private static String _fileloc = "com.act.reachables.ConditionalReachable";
private static void logProgress(String format, Object... args) {
if (!GlobalParams.LOG_PROGRESS)
return;
System.err.format(_fileloc + ": " + format, args);
}
private static void logProgress(String msg) {
if (!GlobalParams.LOG_PROGRESS)
return;
System.err.println(_fileloc + ": " + msg);
}
private void pushWaveFront(Long orgID, boolean incrementLayer) {
Set<Long> enabledRxns = extractEnabledRxns(orgID);
if (orgID != null)
logProgress("Org: %d, num enabled rxns: %d\n", orgID, enabledRxns.size());
Set<Long> newReachables = productsOf(enabledRxns);
{
// this is work done for layout, i.e., setting the layers, and first reach reactions
Set<Long> uniqNew = new HashSet<Long>(newReachables);
uniqNew.removeAll(R);
if (uniqNew.size() > 0) {
addToLayers(uniqNew, this.currentLayer, true /* add to existing layer */);
if (incrementLayer)
this.currentLayer++;
}
tagActivatingRxns(enabledRxns, uniqNew);
}
R.addAll(newReachables);
if (orgID != null)
logProgress("Org: %d, num newReachables in layer %d: %d\n", orgID, this.currentLayer-1, newReachables.size());
updateEnabled(newReachables);
}
private void tagActivatingRxns(Set<Long> rxns, Set<Long> newChems) {
for (Long rxn : rxns) {
Set<Long> activated_products = new HashSet<Long>();
for (Long p : ActData.instance().rxnProducts.get(rxn))
if (newChems.contains(p))
activated_products.add(p);
if (activated_products.size() > 0) {
// tag it as such
for (Long s : ActData.instance().rxnSubstrates.get(rxn)) {
for (Long p : activated_products) {
Edge e = ActData.instance().rxnsInAct.get(new P<Long, Long>(s, p));
Edge.setAttribute(e, "activates_product", true);
}
}
}
}
}
protected boolean anyEnabledReactions(Long orgID) {
for (Long r : this.rxn_needs.keySet()) {
if (orgID == null || ActData.instance().rxnOrganisms.get(r).contains(orgID))
if (this.rxn_needs.get(r).isEmpty())
return true;
}
return false;
}
protected Set<Long> extractEnabledRxns(Long orgID) {
Set<Long> enabled = new HashSet<Long>();
for (Long r : this.rxn_needs.keySet())
if (this.rxn_needs.get(r).isEmpty()) {
// if no orgID specified: add all rxns from any organism,
// if orgID is specified: only if the reaction happens in the org
if (orgID == null || ActData.instance().rxnOrganisms.get(r).contains(orgID))
enabled.add(r);
}
for (Long r : enabled)
this.rxn_needs.remove(r);
return enabled;
}
protected void updateEnabled(Set<Long> newReachables) {
for (Long r : this.rxn_needs.keySet()) {
List<Long> needs = new ArrayList<Long>();
for (Long l : this.rxn_needs.get(r)) {
if (!newReachables.contains(l))
needs.add(l);
}
this.rxn_needs.put(r, needs);
}
}
@Override
public void init() {
for (Long c : ActData.instance().cofactors)
R.add(c);
for (Long n : ActData.instance().natives)
R.add(n);
addToLayers(R, this.currentLayer++, false /* add to new layer */);
updateEnabled(R);
// add all host organism reachables
while (anyEnabledReactions(GlobalParams.gethostOrganismID()))
addAllHostMetabolites(GlobalParams.gethostOrganismID());
}
private void addToLayers(Set<Long> nodes, int layer, boolean addToExisting) {
Set<Long> addNodes = new HashSet<Long>(nodes);
if (this.R_by_layers.containsKey(layer)) {
if (addToExisting)
addNodes.addAll(this.R_by_layers.get(layer));
else
logProgress("ERR: Layer nodeMapping already installed and addToExisting not requested. How did new nodeMapping appear at the same later!?");
}
for (Long c : nodes) {
Node n = ActData.instance().chemsInAct.get(c);
if (n != null)
Node.setAttribute(n.getIdentifier(), "reachable_layer", layer);
}
this.R_by_layers.put(layer, addNodes);
}
@Override
public void finalize(TaskMonitor tm) {
int N = R.size();
int i = 0;
tm.setStatus("Reachable: " + N + " nodeMapping. Setting isReachable, and selecting nodeMapping");
Set<Node> reach1 = new HashSet<Node>();
for (Long r : R) {
tm.setPercentCompleted((int)(100 * ((double)(i++)/N)));
if (!ActData.instance().chemsInAct.containsKey(r))
continue; // in cases where the native is also a cofactor, it would not have a node.
// set the attributes in the act network
Long n1 = ActData.instance().chemsInAct.get(r).getIdentifier();
Node.setAttribute(n1, "isReachable", true);
reach1.add(ActData.instance().chemsInAct.get(r));
}
ActData.instance().Act.unselectAllNodes();
ActData.instance().Act.setSelectedNodeState(reach1, true);
}
}