Skip to content

Commit

Permalink
Merge ea92671 into fdc324f
Browse files Browse the repository at this point in the history
  • Loading branch information
vidyaap committed Nov 13, 2020
2 parents fdc324f + ea92671 commit 5eae1e4
Show file tree
Hide file tree
Showing 16 changed files with 158 additions and 118 deletions.
3 changes: 3 additions & 0 deletions demos/static/js/client.js
Expand Up @@ -587,6 +587,9 @@ $(document).ready(function() {
if ('hasMerge' in data.messages) {
$("#exportSBOLBtn").attr('disabled', true);
$("#sbolIcon").attr('data-original-title', data.messages.hasMerge);
} else if ('hasAnd' in data.messages) {
$("#exportSBOLBtn").attr('disabled', true);
$("#sbolIcon").attr('data-original-title', data.messages.hasAnd);
} else {
$("#exportSBOLBtn").attr('disabled', false);
$("#sbolIcon").attr('data-original-title', 'Export design as SBOL');
Expand Down
9 changes: 5 additions & 4 deletions lib/andOperator.js
Expand Up @@ -34,7 +34,7 @@ function andOperator(newGraph, graph1, graph2, categories1, categories2, finalCa
let newSrc = [edge1.src, edge2.src];
let newDest = [edge1.dest, edge2.dest];
// addToFinalCategories also returns what the new text of this edge should be
let newText = addToFinalCategories(finalCategories, inCommon, edge1.text, edge2.text);
let newText = addToFinalCategories(finalCategories, inCommon, edge1.text, edge2.text, tolerance);
let newEdge = {
src: newSrc,
dest: newDest,
Expand Down Expand Up @@ -176,17 +176,18 @@ function compareCategoriesTwo(cat1, cat2) {
* @param inCommon
* @param text1 String: text from first edge
* @param text2 String: text from second edge
* @param tolerance String: tolerance level of AND
* @return {string|*} text to use in resulting edge
*/
function addToFinalCategories(finalCategories, inCommon, text1, text2) {
function addToFinalCategories(finalCategories, inCommon, text1, text2, tolerance) {
let ret;
if (text1 === text2) {
finalCategories[text1] = inCommon;
return text1;
} else {
// try the edges' text fields combined in both orders to see if it is already in finalCategories
let orderOne = text1 + '_' + text2;
let orderTwo = text2 + '_' + text1;
let orderOne = `${text1}_and${tolerance}_${text2}`; // (e.g. cds1_and0_cds2)
let orderTwo = `${text2}_and${tolerance}_${text1}`;
if (orderOne in finalCategories) {
Object.assign(finalCategories[orderOne], inCommon);
ret = orderOne;
Expand Down
3 changes: 3 additions & 0 deletions lib/constellation.js
Expand Up @@ -95,6 +95,9 @@ async function goldbar(langText, categories,
if (gra.mergeFlag[0]) {
messages.hasMerge = `SBOL generation does not support the MERGE operator.`;
sbolDoc = null;
} else if (gra.andFlag[0]) {
messages.hasAnd = `SBOL generation does not support the AND operator.`;
sbolDoc = null;
} else {
sbolDoc = edgeSBOL(gra.stateGraph, categories, designName, numDesigns, maxCycles);
}
Expand Down
9 changes: 6 additions & 3 deletions lib/edgeGraph.js
Expand Up @@ -147,7 +147,8 @@ class EdgeGraph extends StateGraph {
// find partial stateGraphs for each half of the And
for (let i = 0; i < populateArgs.parsed.length; i++) {
let partialBoundary = [];
handleOp.populateGraph(populateArgs.parsed[i], this, partialBoundary, representation, populateArgs.categories, populateArgs.maxCycles, populateArgs.mergeFlag);
handleOp.populateGraph(populateArgs.parsed[i], this, partialBoundary, representation, populateArgs.categories,
populateArgs.maxCycles, populateArgs.andFlag, populateArgs.mergeFlag);
partialBoundaryStack = partialBoundaryStack.concat(partialBoundary);
}

Expand Down Expand Up @@ -198,7 +199,8 @@ class EdgeGraph extends StateGraph {
for (let i = 0; i < populateArgs.parsed.length; i++) {
let partialGraph = new EdgeGraph();
let partialBoundary = [];
handleOp.populateGraph(populateArgs.parsed[i], partialGraph, partialBoundary, representation, populateArgs.categories, populateArgs.maxCycles, populateArgs.mergeFlag);
handleOp.populateGraph(populateArgs.parsed[i], partialGraph, partialBoundary, representation, populateArgs.categories,
populateArgs.maxCycles, populateArgs.andFlag, populateArgs.mergeFlag);
partialStateGraphs[i] = partialGraph;
partialBoundaryStacks.push(partialBoundary);
artificialCategories[i] = populateArgs.categories;
Expand Down Expand Up @@ -246,7 +248,8 @@ class EdgeGraph extends StateGraph {
// let partialGraph = {};
let partialGraph = new EdgeGraph();
let partialBoundary = [];
handleOp.populateGraph(populateArgs.parsed[i], partialGraph, partialBoundary, representation, populateArgs.categories, populateArgs.maxCycles, populateArgs.mergeFlag);
handleOp.populateGraph(populateArgs.parsed[i], partialGraph, partialBoundary, representation, populateArgs.categories,
populateArgs.maxCycles, populateArgs.andFlag, populateArgs.mergeFlag);
partialStateGraphs[i] = partialGraph;
partialBoundaryStacks.push(partialBoundary);
artificialCategories[i] = populateArgs.categories;
Expand Down
73 changes: 39 additions & 34 deletions lib/edgeSBOL.js
Expand Up @@ -23,7 +23,11 @@ function makeStackFromStateGraph(stateGraph, stateStack, id, edgeUsed){
if (node.visited){
let ops = stateGraph.getOperators(id);
if (edgeUsed.type === constants.ATOM) {
stateStack.push({[constants.ATOM]: edgeUsed.text});
if (edgeUsed.orientation === constants.INLINE) {
stateStack.push({[constants.ATOM]: edgeUsed.text, orientation: constants.INLINE_URI});
} else {
stateStack.push({[constants.ATOM]: edgeUsed.text, orientation: constants.REV_COMP_URI});
}
}
if (ops.includes(constants.ZERO_MORE) || ops.includes(constants.ONE_MORE)) {
if (!endIds.includes(id)) {
Expand All @@ -49,15 +53,23 @@ function makeStackFromStateGraph(stateGraph, stateStack, id, edgeUsed){
}
// if we used an atom to get to stateGraph[id], push atom to stack
if (edgeUsed.type === constants.ATOM){
stateStack.push({[constants.ATOM]: edgeUsed.text});
if (edgeUsed.orientation === constants.INLINE) {
stateStack.push({[constants.ATOM]: edgeUsed.text, orientation: constants.INLINE_URI});
} else {
stateStack.push({[constants.ATOM]: edgeUsed.text, orientation: constants.REV_COMP_URI});
}
}

// handle immediate cycles first (node 1 to node 2 and back)
let immediateCycles = stateGraph.getEdges(id).filter(e => e.dest === edgeUsed.src);
if (immediateCycles.length > 0) {
for (let edge of immediateCycles) {
if (edge.type === constants.ATOM) {
stateStack.push({[constants.ATOM]: edge.text});
if (edge.orientation === constants.INLINE) {
stateStack.push({[constants.ATOM]: edge.text, orientation: constants.INLINE_URI});
} else {
stateStack.push({[constants.ATOM]: edge.text, orientation: constants.REV_COMP_URI});
}
}
if (stateStack[stateStack.length - 1].end !== edge.dest) {
stateStack.push({end: edge.dest});
Expand Down Expand Up @@ -182,7 +194,7 @@ function traverseOr(stateGraph, stateStack, id, endIds, edgeUsed, pMap) {
return lastEdge;
}

function traverseOrEdges(stateGraph, stack, subStack, id, edgeUsed, endIds, prevEdgeUsed, pMap, moreStartId) {
function traverseOrEdges(stateGraph, stack, subStack, id, edgeUsed, endIds, prevEdgeUsed, pMap, moreStartId, ZOStart, ZOEnd) {
let ops = stateGraph.getOperators(id);
if (stateGraph.get(id).visited) {
// if the MORE started within the OR, then end it on this stack
Expand All @@ -198,35 +210,39 @@ function traverseOrEdges(stateGraph, stack, subStack, id, edgeUsed, endIds, prev
endIds.push(id);
}
}

} else if (id in pMap) {
let ZOParent = parentWithOp(stateGraph, Array.from(pMap[id]), constants.ZERO_ONE); // check if parent has zero-or-one
if (ZOParent === moreStartId) { // if it is the moreStartId end it within the sub stack
subStack.push({end: id});
endIds.push(id);
} else if (ZOParent !== null) { // if it is not the moreStartId end it on the main stack
if (!enoughEnds(ZOParent, endIds, stateGraph.getOperators(ZOParent), [constants.ZERO_ONE])) {
stack.push({end: ZOParent});
endIds.push(ZOParent);
}
}
} else if (edgeUsed.type === constants.ATOM) { // in case of zero-or-one
subStack.push({[constants.ATOM]: edgeUsed.text});
subStack.push({[constants.ATOM]: edgeUsed.text, orientation: constants.orientation});
}
return null;
}

if (edgeUsed.type === constants.ATOM) {
subStack.push({[constants.ATOM]: edgeUsed.text});
if (edgeUsed.orientation === constants.INLINE) {
subStack.push({[constants.ATOM]: edgeUsed.text, orientation: constants.INLINE_URI});
} else {
subStack.push({[constants.ATOM]: edgeUsed.text, orientation: constants.REV_COMP_URI});
}
}

if (id === ZOEnd) {
subStack.push({end: ZOStart});
endIds.push(ZOStart);
}

if (ops.length === 1 &&
(ops[0] === constants.ONE_MORE ||
ops[0] === constants.ZERO_MORE ||
ops[0] === constants.ZERO_ONE)) {
ops[0] === constants.ZERO_MORE)) {
moreStartId = id;
}

if (ops.includes(constants.ZERO_ONE)) {
let epsEdges = stateGraph.getEdges(id).filter(e => e.component === constants.EPSILON);
if (epsEdges.length === 1) {
ZOEnd = epsEdges[0].dest;
ZOStart = id;
}
}

if (edgeUsed.type === constants.EPSILON && ops.includes(constants.THEN)) {
stateGraph.get(id).visited = false; //reset
return id; //a 'then' that's not on the atom is not part of the OR
Expand All @@ -247,7 +263,7 @@ function traverseOrEdges(stateGraph, stack, subStack, id, edgeUsed, endIds, prev
handleOperations(stateGraph, subStack, id, endIds, prevEdgeUsed, pMap);
}
for (let edge of stateGraph.getEdges(id)) {
lastEdge = traverseOrEdges(stateGraph, stack, subStack, edge.dest, edge, endIds, prevEdgeUsed, pMap, moreStartId);
lastEdge = traverseOrEdges(stateGraph, stack, subStack, edge.dest, edge, endIds, prevEdgeUsed, pMap, moreStartId, ZOStart, ZOEnd);
}
return lastEdge; //the last node of the OR chain
}
Expand Down Expand Up @@ -278,16 +294,6 @@ function generateCombinatorialSBOL(stateGraph, categories, designName, numDesign
}
/** @type {Collection} */
let collection = sbolDoc.makeCollection(atomText);

// add orientation and operator (for OR handling in sbol.js) to atomMap
if (edge.orientation === constants.REV_COMP) {
sbolDoc.atomMap[atomText].locURI = constants.REV_COMP_URI;
sbolDoc.atomMap[atomText].operator = constants.REV_COMP;
} else {
sbolDoc.atomMap[atomText].locURI = constants.INLINE_URI;
sbolDoc.atomMap[atomText].operator = constants.ONE;
}

// if no IDs in a role, create member for the role instead
for (let role in categories[atomText]) {
// if abstract part
Expand All @@ -297,7 +303,6 @@ function generateCombinatorialSBOL(stateGraph, categories, designName, numDesign
if (!sbolDoc.atomMap[atomText].collections){
sbolDoc.atomMap[atomText].collections = [];
}
sbolDoc.atomMap[atomText].collections.push(collection);
sbolDoc.atomMap[atomText].abstract = true;
// for abstract parts, store the CD in the atom map to reference later
sbolDoc.atomMap[atomText].compDef = abstractCD;
Expand All @@ -309,10 +314,10 @@ function generateCombinatorialSBOL(stateGraph, categories, designName, numDesign
if (!sbolDoc.atomMap[atomText].collections){
sbolDoc.atomMap[atomText].collections = [];
}
sbolDoc.atomMap[atomText].collections.push(collection);
sbolDoc.atomMap[atomText].abstract = false;
}
sbolDoc.atomMap[atomText].abstract = false;
}
sbolDoc.atomMap[atomText].collections.push(collection);
}
}

Expand Down
5 changes: 3 additions & 2 deletions lib/graphGOLDBAR.js
Expand Up @@ -16,6 +16,7 @@ function createGraphFromGOLDBAR(parsedObject, maxCycles, representation, categor
throw new Error('Cycle depth is too high');
}

let andFlag = [false]; // to pass by reference
let mergeFlag = [false]; // to pass by reference
let stateGraph; // Stores currently generated edges
if (representation === constants.NODE) {
Expand All @@ -27,7 +28,7 @@ function createGraphFromGOLDBAR(parsedObject, maxCycles, representation, categor
let boundaryStack = []; // Stores connected nodes in an object. Leaf nodes are stored in object.leaves
parsedObject = balance(parsedObject);

handleOp.populateGraph(parsedObject, stateGraph, boundaryStack, representation, categories, maxCycles, mergeFlag);
handleOp.populateGraph(parsedObject, stateGraph, boundaryStack, representation, categories, maxCycles, andFlag, mergeFlag);

if (stateGraph.nodes.length === 0) {
let epsGraph = new EdgeGraph();
Expand All @@ -38,7 +39,7 @@ function createGraphFromGOLDBAR(parsedObject, maxCycles, representation, categor
const root = handleOp.handleOp(constants.ROOT, stateGraph, boundaryStack, representation);
let result = stateGraph.enumeratePaths(root, maxCycles);

return {stateGraph: result.graph, paths: result.paths, collapsed: result.collapsed, mergeFlag};
return {stateGraph: result.graph, paths: result.paths, collapsed: result.collapsed, andFlag, mergeFlag};
}

/**
Expand Down
16 changes: 12 additions & 4 deletions lib/handleOperators.js
Expand Up @@ -10,9 +10,10 @@ constants = require('./constants');
* @param representation String: which representation of the graph
* @param categories Object: categories that the user input
* @param maxCycles int: maximum number of cycles
* @param mergeFlag boolean: whether there is a merge in the design
* @param andFlag boolean: whether there is an AND in the design
* @param mergeFlag boolean: whether there is a MERGE in the design
*/
function populateGraph(parsed, stateGraph, boundaryStack, representation, categories, maxCycles, mergeFlag) {
function populateGraph(parsed, stateGraph, boundaryStack, representation, categories, maxCycles, andFlag, mergeFlag) {
// Handle if input is an atom
if (parsed.Atom) {
handleAtom(parsed.Atom, stateGraph, boundaryStack, categories, representation);
Expand All @@ -27,7 +28,7 @@ function populateGraph(parsed, stateGraph, boundaryStack, representation, catego
// Handle if input is an or
if (Array.isArray(parsed)) {
for (let i = 0; i < parsed.length; i++) {
populateGraph(parsed[i], stateGraph, boundaryStack, representation, categories, maxCycles, mergeFlag);
populateGraph(parsed[i], stateGraph, boundaryStack, representation, categories, maxCycles, andFlag, mergeFlag);
}
return;
}
Expand All @@ -39,15 +40,22 @@ function populateGraph(parsed, stateGraph, boundaryStack, representation, catego
parsed: parsed[operation],
categories,
maxCycles,
andFlag,
mergeFlag
};
if (operation === constants.AND0) {
andFlag.pop();
andFlag.push(true);
handleOp(constants.AND, stateGraph, boundaryStack, representation, populateArgs, 0);
return;
} else if (operation === constants.AND1) {
andFlag.pop();
andFlag.push(true);
handleOp(constants.AND, stateGraph, boundaryStack, representation, populateArgs, 1);
return;
} else if (operation === constants.AND2) {
andFlag.pop();
andFlag.push(true);
handleOp(constants.AND, stateGraph, boundaryStack, representation, populateArgs, 2);
return;
} else if (operation === constants.OR && representation === constants.EDGE) {
Expand All @@ -59,7 +67,7 @@ function populateGraph(parsed, stateGraph, boundaryStack, representation, catego
handleOp(constants.MERGE, stateGraph, boundaryStack, representation, populateArgs);
return;
} else {
populateGraph(parsed[operation], stateGraph, boundaryStack, representation, categories, maxCycles, mergeFlag);
populateGraph(parsed[operation], stateGraph, boundaryStack, representation, categories, maxCycles, andFlag, mergeFlag);
handleOp(operation, stateGraph, boundaryStack, representation, populateArgs);
}
}
Expand Down
4 changes: 2 additions & 2 deletions lib/mergeOperator.js
Expand Up @@ -122,8 +122,8 @@ function addToFinalCategories(finalCategories, inCommon, text1, text2) {
return text1;
} else {
// try the edges' text fields combined in both orders to see if it is already in finalCategories
let orderOne = text1 + '_' + text2;
let orderTwo = text2 + '_' + text1;
let orderOne = text1 + '_merge_' + text2; // (e.g. cds1_merge_cds2)
let orderTwo = text2 + '_merge_' + text1;
if (orderOne in finalCategories) {
Object.assign(finalCategories[orderOne], inCommon);
ret = orderOne;
Expand Down
23 changes: 12 additions & 11 deletions lib/nodeSBOL.js
Expand Up @@ -28,7 +28,11 @@ function makeStackFromStateGraph(stateGraph, stateStack, id){
continue;
}
if (node.type === constants.ATOM) {
stateStack.push({[constants.ATOM]: node.text});
if (node.orientation === constants.INLINE) {
stateStack.push({[constants.ATOM]: node.text, orientation: constants.INLINE_URI});
} else {
stateStack.push({[constants.ATOM]: node.text, orientation: constants.REV_COMP_URI});
}
}

// handle immediate cycles first (node 1 to node 2 and back)
Expand Down Expand Up @@ -112,7 +116,11 @@ function traverseOrEdges(stateGraph, stack, subStack, id, endIds, moreStartId){
return null;
}
if (node.type === constants.ATOM){
subStack.push({[constants.ATOM]: node.text});
if (node.orientation === constants.INLINE) {
subStack.push({[constants.ATOM]: node.text, orientation: constants.INLINE_URI});
} else {
subStack.push({[constants.ATOM]: node.text, orientation: constants.REV_COMP_URI});
}
}

if (ops.length === 1 &&
Expand Down Expand Up @@ -173,13 +181,6 @@ function generateCombinatorialSBOL(stateGraph, categories, designName, numDesign
}
/** @type {Collection} */
let collection = sbolDoc.makeCollection(atomText);
if (currentNode.orientation === constants.REV_COMP) {
sbolDoc.atomMap[atomText].locURI = constants.REV_COMP_URI;
sbolDoc.atomMap[atomText].operator = constants.REV_COMP;
} else {
sbolDoc.atomMap[atomText].locURI = constants.INLINE_URI;
sbolDoc.atomMap[atomText].operator = constants.ONE;
}
for (let role in categories[atomText]) {
// if no IDs in a role, create member for the role instead (abstract)
if (categories[atomText][role].length === 0) {
Expand All @@ -188,7 +189,6 @@ function generateCombinatorialSBOL(stateGraph, categories, designName, numDesign
if (!sbolDoc.atomMap[atomText].collections){
sbolDoc.atomMap[atomText].collections = [];
}
sbolDoc.atomMap[atomText].collections.push(collection);
sbolDoc.atomMap[atomText].abstract = true;
// for abstract parts, store the CD in the atom map to reference later
sbolDoc.atomMap[atomText].compDef = abstractCD;
Expand All @@ -200,10 +200,11 @@ function generateCombinatorialSBOL(stateGraph, categories, designName, numDesign
if (!sbolDoc.atomMap[atomText].collections){
sbolDoc.atomMap[atomText].collections = [];
}
sbolDoc.atomMap[atomText].collections.push(collection);

sbolDoc.atomMap[atomText].abstract = false;
}
}
sbolDoc.atomMap[atomText].collections.push(collection);
}
});

Expand Down

0 comments on commit 5eae1e4

Please sign in to comment.