/** * Copy the list of nodes that need copying when adding a new split into a network. * * @param nodesToCopy ArrayList of nodes in the network that need to be copied * @param network Network we are working in * @param incompatibleEdges Edges that are in the path that joins up the nodes that are being * copied * @param splitToAdd Split that we are currently adding in by copying these nodes */ public void CopyNode( ArrayList<CNetworkNode> nodesToCopy, CNetworkSplit splitToAdd, CNetwork network, ArrayList<CNetworkEdge> incompatibleEdges) { // Copy Node: for (CNetworkNode nodeToCopy : nodesToCopy) { CNetworkNode newNode = new CNetworkNode(); // create a new node with a name that indicates it has been added (we can output node names by // modifying later code) newNode.Taxaname = "added0" + Integer.toString(network.nodes.size()); // below should NEVER happen... but will leave in just in case as was at one time an issue: if (nodeToCopy == null || newNode == null) { System.out.println("Null pointer in terms of node that we want to copy to..."); } // Reference the new node on the old one nodeToCopy.CopiedToNode = newNode; // Add new node to network network.nodes.add(newNode); // Add an edge between old and new node CNetworkEdge edgeToAdd = new CNetworkEdge(); edgeToAdd.networkNodeA = newNode; edgeToAdd.networkNodeB = nodeToCopy; edgeToAdd.split = splitToAdd; splitToAdd.edges.add(edgeToAdd); } // Go through and move links over depending on which side the splits are a subset of. for (CNetworkNode nodeToCopy : nodesToCopy) { // look at each join on each old node for (int i = 0; i < nodeToCopy.joins.size(); i++) { CNetworkEdge edgeToConsider = nodeToCopy.joins.get(i); // if it joins another copied node then we will duplicate the edge later... if (edgeToConsider.networkNodeA.CopiedToNode == null || edgeToConsider.networkNodeB.CopiedToNode == null) { // if on "0" side of new split then keep it, otherwise move it to the new node. if (splitToAdd.OnZeroSide(edgeToConsider.split, noOfTaxa) == false) { // Replace the appropriate edge reference... if (edgeToConsider.networkNodeA == nodeToCopy) { edgeToConsider.networkNodeA = nodeToCopy.CopiedToNode; // System.out.println("moved link to "+edgeToConsider.networkNodeB.Taxaname+" from // "+nodeToCopy.Taxaname+" to "+nodeToCopy.CopiedToNode.Taxaname); } else if (edgeToConsider.networkNodeB == nodeToCopy) { edgeToConsider.networkNodeB = nodeToCopy.CopiedToNode; // System.out.println("moved link to "+edgeToConsider.networkNodeA.Taxaname+" from // "+nodeToCopy.Taxaname+" to "+nodeToCopy.CopiedToNode.Taxaname); } // Add it to the new node list nodeToCopy.CopiedToNode.joins.add(edgeToConsider); // delete it from the list of the old nodes: nodeToCopy.joins.remove(i); // go back one in the list! i--; } } } } // Add in the edges between copied nodes to the old nodes to their node join lists now we have // done all the moving about! for (CNetworkEdge edgeToLink : splitToAdd.edges) { edgeToLink.networkNodeA.joins.add(edgeToLink); edgeToLink.networkNodeB.joins.add(edgeToLink); } // Add in the edges to the copied nodes that are in the list of incompatible splits. for (CNetworkEdge incompatibleEdge : incompatibleEdges) { // Check to see if we have an edge that is incompatible (this SHOULD always be the case... ) if (incompatibleEdge.networkNodeA.CopiedToNode != null && incompatibleEdge.networkNodeB.CopiedToNode != null) { // Create new edge CNetworkEdge newEdge = new CNetworkEdge(); // Update node info. newEdge.networkNodeA = incompatibleEdge.networkNodeA.CopiedToNode; newEdge.networkNodeB = incompatibleEdge.networkNodeB.CopiedToNode; newEdge.networkNodeA.joins.add(newEdge); newEdge.networkNodeB.joins.add(newEdge); // Update split info. newEdge.split = incompatibleEdge.split; incompatibleEdge.split.edges.add(newEdge); } } // Now remove the CopiedToNode link now we are done... for (CNetworkNode nodeToCopy : nodesToCopy) { nodeToCopy.CopiedToNode = null; } }
/** * Constructs the network beginning with the consensus tree and then calls the network drawing * function to calculate positions * * @param tree Consensus tree already calculated */ public CNetwork constructNetwork(CTree tree) { // Create a new network... CNetwork network = new CNetwork(noOfTaxa); // Let's copy over all of the splits from the tree into the network format. // Until noted, the node lists in tree and network MUST match and the first lot of nodes (after // the root) in the tree are assumed to be the taxa. for (int i = 0; i < tree.nodeList.size(); i++) { TreeNode treeNode = tree.nodeList.get(i); // create a new node CNetworkNode networkNode = new CNetworkNode(); // copy over the required data and add it... networkNode.Taxaname = treeNode.name; network.nodes.add(networkNode); } // Now add in the splits... (ignore 1st cluster as is for star tree) for (int i = 1; i < tree.clusters.size(); i++) { Cluster cluster = tree.clusters.get(i); if (cluster.isMajority == true) { CNetworkSplit networkSplit = new CNetworkSplit(); CNetworkEdge networkEdge = new CNetworkEdge(); networkEdge.split = networkSplit; networkEdge.networkNodeA = network.nodes.get(cluster.nodeRefA); networkEdge.networkNodeB = network.nodes.get(cluster.nodeRefB); networkSplit.edges.add(networkEdge); // Maybe we shouldn't be copying this over... but it at least clarifies things in code. networkSplit.edgelength = cluster.edgeLength; networkSplit.noOfOccurences = cluster.noOfOccurrences; networkSplit.split = cluster.aboveSplit; network.nodes.get(cluster.nodeRefA).joins.add(networkEdge); network.nodes.get(cluster.nodeRefB).joins.add(networkEdge); network.splits.add(networkSplit); cluster.added = true; } } // Now add in the taxa length splits.... NOTE i=0 is root?! Tried and tested anyway... for (int i = 1; i <= noOfTaxa; i++) { CNetworkSplit networkSplit = new CNetworkSplit(); CNetworkEdge networkEdge = new CNetworkEdge(); networkEdge.split = networkSplit; int taxonParent = tree.parentList.get(tree.nodeList.get(i).name); networkEdge.networkNodeA = network.nodes.get(taxonParent); networkEdge.networkNodeB = network.nodes.get(i); networkSplit.edges.add(networkEdge); networkSplit.edgelength = tree.nodeList.get(i).edgeLength; networkSplit.noOfOccurences = noOfTrees; BitSet trivialSplit = new BitSet(noOfTaxa); trivialSplit.set(i - 1); networkSplit.split = trivialSplit; network.nodes.get(taxonParent).joins.add(networkEdge); network.nodes.get(i).joins.add(networkEdge); network.splits.add(networkSplit); } // NOTE: From now on the indices on Network & Tree may no longer match!! // Remove the root if it is simply disecting an edge (only 2 edges on either side). // NOTE: root is assumed to be the first position in the node list in CNetwork and CTree if (network.nodes.get(0).joins.size() == 2) { // find the nodes on either side of the root... CNetworkNode[] redundant = new CNetworkNode[2]; for (int h = 0; h < 2; h++) { if (network.nodes.get(0).joins.get(h).networkNodeA == network.nodes.get(0)) { redundant[h] = network.nodes.get(0).joins.get(h).networkNodeB; } else { redundant[h] = network.nodes.get(0).joins.get(h).networkNodeA; } } // correct the edge in the one list to go to the zero node. if (network.nodes.get(0).joins.get(1).networkNodeA == network.nodes.get(0)) { network.nodes.get(0).joins.get(1).networkNodeA = redundant[0]; } else { network.nodes.get(0).joins.get(1).networkNodeB = redundant[0]; } // find the edge in the list in zero and remove it.. for (int h = 0; h < redundant[0].joins.size(); h++) { if (redundant[0].joins.get(h).networkNodeA == network.nodes.get(0) || redundant[0].joins.get(h).networkNodeB == network.nodes.get(0)) { redundant[0].joins.remove(h); h--; } } // remove the edge from the split list for (int h = 0; h < network.nodes.get(0).joins.get(0).split.edges.size(); h++) { if (network.nodes.get(0).joins.get(0).split.edges.get(h) == network.nodes.get(0).joins.get(0)) { network.nodes.get(0).joins.get(0).split.edges.remove(h); h--; } } // add the other edge in the zero list redundant[0].joins.add(network.nodes.get(0).joins.get(1)); // remove the node at last, and any reference to the removed edge also goes! network.nodes.remove(0); } // TODO: Optional: sort the list in terms of frequency of occurrence to select only most // frequent if less than 33.34% occurences....! // IGNORE the first one as it is the star network... // Now let's go through the remaining splits and try and add them into the network. for (int i = 0; i < tree.clusters.size(); i++) { Cluster cluster = tree.clusters.get(i); // for clusters that haven't been added yet, let's add them... if (cluster.added == false) { // define new split and copy over info. CNetworkSplit addSplit = new CNetworkSplit(); addSplit.split = cluster.aboveSplit; addSplit.edgelength = cluster.edgeLength; // now findout if is incompatible with any existing splits in the network ArrayList<CNetworkSplit> incompatibleSplits = new ArrayList<CNetworkSplit>(); for (CNetworkSplit compSplit : network.splits) { if (compSplit.isCompatible(addSplit, noOfTaxa) == false) { incompatibleSplits.add(compSplit); } } // Now we need to find the nodes we need to copy, so create a list of them ArrayList<CNetworkNode> nodesToCopy = new ArrayList<CNetworkNode>(); // go through the incompatible splits one by one and add them to chains. ArrayList<CNetworkPath> chains = new ArrayList<CNetworkPath>(); // note all nodes that will be stored in paths for more efficient path claering up ArrayList<CNetworkNode> nodesToClearUp = new ArrayList<CNetworkNode>(); // Loop through incompatible splits for (CNetworkSplit currentSplit : incompatibleSplits) { // Loop through all the edges in this split for (CNetworkEdge currentEdge : currentSplit.edges) { // create a new path and add it to the list... CNetworkPath newPath = new CNetworkPath(); newPath.pathOfEdges.add(currentEdge); newPath.pathOfNodes.add(currentEdge.networkNodeA); newPath.pathOfNodes.add(currentEdge.networkNodeB); currentEdge.networkNodeA.AddToPaths(newPath, nodesToClearUp); currentEdge.networkNodeB.AddToPaths(newPath, nodesToClearUp); chains.add(newPath); // Now extend any existing paths... // create a list of paths to extend found paths with... ArrayList<CNetworkPath> extendPathsWith = new ArrayList<CNetworkPath>(); extendPathsWith.add(newPath); // Hack to go from NodeA & NodeB to a for loop... CNetworkNode[] edgeNodes = new CNetworkNode[] {currentEdge.networkNodeA, currentEdge.networkNodeB}; // For the first node, add the standard for (int l = 0; l <= 1; l++) { // get ready to make this part of the nodes with paths to clear up... (should be // already done?) if (edgeNodes[l].paths.isEmpty() == true) { nodesToClearUp.add(edgeNodes[l]); } // Look at each path that the node is involved in... int pathCount = edgeNodes[l].paths.size(); for (int g = 0; g < pathCount; g++) { CNetworkPath currentPath = edgeNodes[l].paths.get(g); // for the case that we may want to add the edge to the start/end of a path on the // node... if (currentPath.endNode() == edgeNodes[l] || currentPath.startNode() == edgeNodes[l]) { // check we haven't already added this split yet... if (currentPath.checkForSplit(currentEdge) == false) { // create a new combined path with all paths to extend with... // Don't forget to make this add the new path to all the nodes as well as // combining over the correct node & removing one instance of it... for (CNetworkPath pathToAdd : extendPathsWith) { chains.add(currentPath.combineWith(pathToAdd, edgeNodes[l])); } } } } } } } for (CNetworkNode nodeToClearUp : nodesToClearUp) { nodeToClearUp.paths.clear(); } ArrayList<CNetworkEdge> incompatibleEdges = new ArrayList<CNetworkEdge>(); // Case that there are no incompatible splits... just add in the split! // Note that SOME splits appear to contain the whole tree (perhaps due to a hack earlier), // so lets just ignore these.... This could be described as a hack induced hack... if (incompatibleSplits.isEmpty() == true && (addSplit.split.cardinality() != noOfTaxa && addSplit.split.cardinality() != 0)) { // we have no idea which taxon is actually on the side we want, but we will use some cool // functions of BitSet to help reduce the time it takes... CNetworkNode beginNode; // Start searching from the adding side of the split containing zeros? boolean zeroSide; if (addSplit.split.cardinality() <= (noOfTaxa) / 2) { // if there are more set to 0 than 1 go from a taxon on the 1 side: // Search through the nodes for this using predefined function... beginNode = TaxonRefToNode(addSplit.split.nextSetBit(0), network); zeroSide = false; } else { // if there are more set to 1 than 0, then go from a taxon on the 0 side: beginNode = TaxonRefToNode(addSplit.split.nextClearBit(0), network); zeroSide = true; } // recursively go along the edges until a node is found that has an edge that satisfies. ArrayList<CNetworkNode> consideredNodes = new ArrayList<CNetworkNode>(); CNetworkNode CopyNode2 = beginNode.findFirstNonSubset(addSplit, consideredNodes, zeroSide, noOfTaxa); nodesToCopy.add(CopyNode2); } else { // Copy over the list of nodes from the longest path...ERROR if we have a too big path... if (chains.size() > 0) { // Store the max paths... ArrayList<CNetworkPath> currentMaxPaths = new ArrayList<CNetworkPath>(); // initialise with first one, which only serves as to store length...: currentMaxPaths.add(chains.get(0)); for (CNetworkPath chain : chains) { if (chain.pathOfNodes.size() > currentMaxPaths.get(0).pathOfNodes.size()) { currentMaxPaths.clear(); currentMaxPaths.add(chain); } // Yes, still add it if we already added it! if (chain.pathOfNodes.size() == currentMaxPaths.get(0).pathOfNodes.size()) { currentMaxPaths.add(chain); } } // now remove any max path that requires all edges to be copied or none at all... for (int m = 1; m < currentMaxPaths.size(); m++) { if (currentMaxPaths.get(m).isSplitSide(addSplit, noOfTaxa) == false) { currentMaxPaths.remove(m); m--; } } if (currentMaxPaths.size() > 2) { // ERROR!!! Now in >2d....! System.out.println("Potential Error: Network now in > 2 dimensions....!"); } // Now create the copyNode list: // Store those that have been copied.... err // Go through all the paths // DOES START AT 1 as first just stored length! for (int m = 1; m < currentMaxPaths.size(); m++) { incompatibleEdges.addAll(currentMaxPaths.get(m).pathOfEdges); CNetworkPath currentMaxPath = currentMaxPaths.get(m); // Go through all the nodes for (CNetworkNode currentNodeCopy : currentMaxPath.pathOfNodes) { if (currentNodeCopy.consideration == false) { currentNodeCopy.consideration = true; nodesToCopy.add(currentNodeCopy); } } } // remove the considered flag from the node: for (CNetworkNode currentNodeClean : nodesToCopy) { currentNodeClean.consideration = false; } } } // actually call the function that copies the nodes CopyNode(nodesToCopy, addSplit, network, incompatibleEdges); // and add the new split at last to the network. network.splits.add(addSplit); } } // fill in the network positions (hopefully)... network.FindPositions(noOfTaxa); // printDetails(tree,network); return network; }