From 639d0c42da59a37824c5fd99e0fd0aba8b0a8feb Mon Sep 17 00:00:00 2001 From: Marco Foscato Date: Sun, 21 Apr 2024 22:07:58 +0200 Subject: [PATCH] just testing a mixture of fixes --- doc/user_manual.md | 2 +- pom.xml | 2 +- src/main/java/denoptim/graph/DGraph.java | 278 ++++++++++++++------ test/functional_tests/t32/data/init_pop.txt | 2 + test/functional_tests/t32/t32.params | 2 +- 5 files changed, 206 insertions(+), 80 deletions(-) diff --git a/doc/user_manual.md b/doc/user_manual.md index 9f3558303..4658781bc 100644 --- a/doc/user_manual.md +++ b/doc/user_manual.md @@ -1,7 +1,7 @@ # DENOPTIM _De novo_ Optimization of In/organic Molecules -_Version 4.2.0, Jan 2024_ +_Version 4.2.1, Apr 2024_ [TOC] diff --git a/pom.xml b/pom.xml index 19914ed76..b53d0e143 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ denoptim - 4.2.0 + 4.2.1 denoptim diff --git a/src/main/java/denoptim/graph/DGraph.java b/src/main/java/denoptim/graph/DGraph.java index d526327a1..262e5d1c2 100644 --- a/src/main/java/denoptim/graph/DGraph.java +++ b/src/main/java/denoptim/graph/DGraph.java @@ -354,7 +354,7 @@ public List getSymVerticesForVertex(Vertex v) * vertexes that are compatible with each other) * or that are downstream (i.e., according to edge * direction) w.r.t {@link Vertex}es that are using symmetric - * {@link AttachmentPoint}s.The compatibility of the vertexes is determined + * {@link AttachmentPoint}s. The compatibility of the vertexes is determined * by these criteria: * @return true if some symmetric set of vertex has been found. * @throws DENOPTIMException */ public boolean detectSymVertexSets() throws DENOPTIMException { + //TODO-gg del + DenoptimIO.writeGraphToJSON(new File("/tmp/g.json"), this); + int initialSize = symVertices.size(); // This is to hold vertexes in a staging area (symVrtxsFromAnyBranch) @@ -403,28 +408,76 @@ public boolean detectSymVertexSets() throws DENOPTIMException findSymmetrySetsOfChildVertexes(symToVrtx, alreadyAssignedVrtxs); - for (SymmetricAPs key : symChildenSetsOnSymToVrtxs.keySet()) + for (SymmetricAPs candSymAP + : symChildenSetsOnSymToVrtxs.keySet()) { - // Find any mapping with previously recorded SymmetricAPs + // Search for any mapping with previously recorded sym sets + // of vertexes... boolean foundSymmetricBranch = false; - for (SymmetricAPs keyOnMaster : key.getAllSameAs( - symVrtxsFromAnyBranch.keySet())) + Set candidatePreviousSAPsIDs = + candSymAP.getAllSameAs( + symVrtxsFromAnyBranch.keySet()); + // ...but exclude those that identify location in the parent + // tree. + Set toExclude = new HashSet(); + for (SymmetricAPs candPreviousSymAPID + : candidatePreviousSAPsIDs) + { + List potentialParents = + symVrtxsFromAnyBranch.get(candPreviousSymAPID); + if (potentialParents!=null) + { + for (Vertex candParent : potentialParents) + { + if (symToVrtx==candParent) + { + // The previous sym set already contains + // symToVrtx + toExclude.add(candPreviousSymAPID); + break; + } + List children = new ArrayList<>(); + getChildrenTree(candParent, children); + if (children.contains(symToVrtx)) + { + // symToVrtx would be grand^N-children on a + // vertex already in the sym set. + toExclude.add(candPreviousSymAPID); + break; + } + } + } + } + candidatePreviousSAPsIDs.removeAll(toExclude); + + // Evaluate whether the candidate AP (i.e., possible root + // of a symmetric branch) holds a users that is symmetric + // to the one we have on the candSymAP + for (SymmetricAPs keyOnMaster : candidatePreviousSAPsIDs) { - foundSymmetricBranch = true; - // Here we must NOT consider the already assigned ones! - if (areApsUsedBySymmetricUsers(key.get(0), + if (areApsUsedBySymmetricUsers(candSymAP.get(0), keyOnMaster.get(0), new HashSet())) { // the previously recorded branch and - // this one are consistent - symVrtxsFromAnyBranch.get(keyOnMaster).addAll( - symChildenSetsOnSymToVrtxs.get(key)); + // this one are consistent, so add this sym children + // to previously known set. + + //TODO-gg del + System.out.println("appending to "+candSymAP+" -> "+symChildenSetsOnSymToVrtxs.get(candSymAP)); + for (Vertex v : + symChildenSetsOnSymToVrtxs.get(candSymAP)) + { + List targetSymLst = + symVrtxsFromAnyBranch.get(keyOnMaster); + if (!targetSymLst.contains(v)) + targetSymLst.add(v); + } + foundSymmetricBranch = true; } else { // branches correspond to two different sets of // symmetric vertexes. So, we treat the new branch // independently - foundSymmetricBranch = false; } } if (!foundSymmetricBranch) @@ -432,68 +485,117 @@ public boolean detectSymVertexSets() throws DENOPTIMException // Effectively, in the first iteration of the loop // we will always end up here List lst = new ArrayList(); - lst.addAll(symChildenSetsOnSymToVrtxs.get(key)); - symVrtxsFromAnyBranch.put(key, lst); + lst.addAll(symChildenSetsOnSymToVrtxs.get(candSymAP)); + //TODO-gg del + System.out.println("ADDING "+candSymAP+" -> "+lst); + symVrtxsFromAnyBranch.put(candSymAP, lst); } } } } - - for (Map.Entry> entry : symVrtxsFromAnyBranch.entrySet()) + // Remove unused place holders + Set keysToRemove = new HashSet(); + for (SymmetricAPs key : symVrtxsFromAnyBranch.keySet()) { - - List symVertexes = entry.getValue(); - SymmetricAPs key = entry.getKey(); - if (symVertexes.size() < 2) { - // We get rid of placeholders for vertexes that use APs that + if (symVrtxsFromAnyBranch.get(key).size() < 2) { + // We get rid of place holders for vertexes that use APs that // are not part of a symmetriAPs, but could have been part - // of symmetric subgraphs - continue; - } else { - - Map> vertexChildrenMap = new HashMap<>(); - // Get children tree for each vertex in the symmetric set - for (Vertex vertex : symVertexes) { - List children = new ArrayList<>(); - getChildrenTree(vertex, children); - vertexChildrenMap.put(vertex, children); - } - - boolean allInOneBranch = false; - Set toRemove = new HashSet<>(); - for (Vertex parent : vertexChildrenMap.keySet()) { - List children = vertexChildrenMap.get(parent); - boolean allChildren = true; - for (Vertex other : symVertexes) { - if (other != parent && !children.contains(other)) { - allChildren = false; - break; - } + // of symmetric subgraphs + keysToRemove.add(key); + } + } + for (SymmetricAPs key : keysToRemove) + symVrtxsFromAnyBranch.remove(key); + + // Resolve sets that consider at least one same vertex + keysToRemove.clear(); + List orderedKeys = new ArrayList( + symVrtxsFromAnyBranch.keySet()); + for (int i=0; i listSymVrtxsI = symVrtxsFromAnyBranch.get(keyI); + for (int j=i+1; j listSymVrtxsJ = symVrtxsFromAnyBranch.get(keyJ); + if (!Collections.disjoint(listSymVrtxsI,listSymVrtxsJ)) + { + // The two lists share one or more vertexes: cannot coexist! + // Choose the largest... + if (listSymVrtxsI.size()>listSymVrtxsJ.size()) + { + keysToRemove.add(keyJ); + } else if (listSymVrtxsI.size()sumOfLevelsJ) + { + keysToRemove.add(keyI); + } else { + // If the sum of levels is the same, it should not + // matter which one we choose. + keysToRemove.add(keyJ); + } } - if (allChildren) { - allInOneBranch = true; + } + } + } + for (SymmetricAPs key : keysToRemove) + symVrtxsFromAnyBranch.remove(key); + + // Final clean + for (List symVertexes : symVrtxsFromAnyBranch.values()) + { + Map> vertexChildrenMap = new HashMap<>(); + // Get children tree for each vertex in the symmetric set + for (Vertex vertex : symVertexes) { + List children = new ArrayList<>(); + getChildrenTree(vertex, children); + vertexChildrenMap.put(vertex, children); + } + + boolean allInOneBranch = false; + Set toRemove = new HashSet<>(); + for (Vertex parent : vertexChildrenMap.keySet()) { + List children = vertexChildrenMap.get(parent); + boolean allChildren = true; + for (Vertex other : symVertexes) { + if (other != parent && !children.contains(other)) { + allChildren = false; break; } - // Mark children for removal if they are contained in any - // parent's children tree - for (Vertex child : children) { - if (symVertexes.contains(child) && child != parent) { - toRemove.add(child); - } - } } - if (allInOneBranch) { - // All vertices are in the same branch, skip the set - continue; - - } else if (!toRemove.isEmpty()) { - // Remove only the child vertices. - symVertexes.removeAll(toRemove); + if (allChildren) { + allInOneBranch = true; + break; } + // Mark children for removal if they are contained in any + // parent's children tree + for (Vertex child : children) { + if (symVertexes.contains(child) && child != parent) { + toRemove.add(child); + } + } + } + if (allInOneBranch) { + // All vertices are in the same branch, skip the set + continue; + } else if (!toRemove.isEmpty()) { + // Remove only the child vertices. + symVertexes.removeAll(toRemove); } - alreadyAssignedVrtxs.addAll(symVertexes); + addSymmetricSetOfVertices(new SymmetricVertexes(symVertexes)); } @@ -502,26 +604,44 @@ public boolean detectSymVertexSets() throws DENOPTIMException //------------------------------------------------------------------------------ - Map> findSymmetrySetsOfChildVertexes( + protected Map> findSymmetrySetsOfChildVertexes( Vertex vrtx, Set alreadyAssignedVrtxs) { Map> symSetsOfChildVrtxs = new HashMap>(); + Set addedBySymAP = new HashSet(); + Set doneAPs = new HashSet(); for (SymmetricAPs symAPs : vrtx.getSymmetricAPSets()) { - // First condition: all symmetric APs must be in use - boolean addSymAPsAreUsed = true; + // First condition: all symmetric APs must be in use... + boolean symAPsAreUsedConsistently = true; + boolean first = true; + boolean usedAsSrc = false; for (AttachmentPoint ap : symAPs) { if (ap.isAvailableThroughout()) { - addSymAPsAreUsed = false; + symAPsAreUsedConsistently = false; break; + } else { + // ...and used in the same way (i.e., as head/tail of edge) + if (first) + { + usedAsSrc = ap.isSrcInUserThroughout(); + first = false; + } else { + if ((usedAsSrc && !ap.isSrcInUserThroughout()) + || (!usedAsSrc && ap.isSrcInUserThroughout())) + { + symAPsAreUsedConsistently = false; + break; + } + } } } - if (!addSymAPsAreUsed) + if (!symAPsAreUsedConsistently) continue; // Now consider what vertex is attached to the symmetric APs @@ -532,8 +652,6 @@ Map> findSymmetrySetsOfChildVertexes( symVertexes.add(firstAp.getLinkedAPThroughout().getOwner()); for (AttachmentPoint ap : symAPs) { - doneAPs.add(ap); - if (firstAp==ap) continue; @@ -544,28 +662,34 @@ Map> findSymmetrySetsOfChildVertexes( // OK: this user of AP is symmetric to the user on firstAP symVertexes.add(ap.getLinkedAPThroughout().getOwner()); + doneAPs.add(ap); } if (setSymmetryRelation) { symSetsOfChildVrtxs.put(symAPs,symVertexes); - alreadyAssignedVrtxs.addAll(symVertexes); + //TODO-ff alreadyAssignedVrtxs.addAll(symVertexes); + addedBySymAP.addAll(symVertexes); } } - // Here we account for the possibility that vertex without sym APs - // is part of a subgraph the is symmetrically reproduced elsewhere. + // Here we account for the possibility that vertex without sym APs + // is part of a subgraph that is symmetrically reproduced elsewhere. // This is a common pattern in chemistry. // To this end we create dummy symmetric sets of APs that contain // only one APs, and use them as placeholder in case the same AP-user // is found on symmetric branches. for (AttachmentPoint ap : vrtx.getAttachmentPoints()) { - if (doneAPs.contains(ap) || ap.isAvailableThroughout()) + if (doneAPs.contains(ap) || ap.isAvailableThroughout() + || !ap.isSrcInUserThroughout()) continue; Vertex user = ap.getLinkedAPThroughout().getOwner(); - if (alreadyAssignedVrtxs.contains(user)) + //TODO-ff if (alreadyAssignedVrtxs.contains(user)) + // continue; + + if (addedBySymAP.contains(user)) continue; // Create an artifact of SymmetricAPs that contains one entry @@ -578,11 +702,11 @@ Map> findSymmetrySetsOfChildVertexes( symVertexes.add(user); symSetsOfChildVrtxs.put(soloSymAps,symVertexes); - alreadyAssignedVrtxs.addAll(symVertexes); + //TODO-ff alreadyAssignedVrtxs.addAll(symVertexes); } return symSetsOfChildVrtxs; } - + //------------------------------------------------------------------------------ /** @@ -593,7 +717,7 @@ Map> findSymmetrySetsOfChildVertexes( * {@link AttachmentPoint#sameAs(AttachmentPoint)} *
  • the {@link Vertex} owner of apB is not contained in the set of * already-assigned vertexes (the 3rd argument)
  • - *
  • the {@link Vertex}a attached to apA andapB must be return satisfy + *
  • the {@link Vertex}s attached to apA and apB must be return satisfy * {@link Vertex#sameAs(Vertex)}
  • *
  • if such vertexes are instances of {@link Fragment}, then they must * satisfy {@link Fragment#isIsomorphicTo(Vertex)}.
  • @@ -628,7 +752,7 @@ public static boolean areApsUsedBySymmetricUsers(AttachmentPoint apA, Vertex userOfApB = apUserOfApB.getOwner(); if (alreadyAssignedVrtxs.contains(userOfApB)) { - return false; + //TODO-consider return false; } // 3rd condition: (not fast, not too slow) the linked diff --git a/test/functional_tests/t32/data/init_pop.txt b/test/functional_tests/t32/data/init_pop.txt index 4f4b84db8..5995af35d 100644 --- a/test/functional_tests/t32/data/init_pop.txt +++ b/test/functional_tests/t32/data/init_pop.txt @@ -1 +1,3 @@ C1(=C(C2=C(C(=C1N([H])[H])C([H])([H])[H])C(COCC1=CC=[C]C=C1)(C(O2)(C([H])([H])[H])C([H])([H])OC([H])([H])C3=C(C(=C(C(=C3[H])[H])[H])[H])[H])([H])[H])C([H])([H])[H])COC([H])([H])[H] +C(OCOCOC)(OCOCOC)OCOCOC +C(OCOCOC)(SCOCOC)OCOCOC diff --git a/test/functional_tests/t32/t32.params b/test/functional_tests/t32/t32.params index 8f5690616..6002bbe00 100644 --- a/test/functional_tests/t32/t32.params +++ b/test/functional_tests/t32/t32.params @@ -1,6 +1,6 @@ # Genetic Algorithm - parameters GA-Verbosity=2 -GA-PopulationSize=1 +GA-PopulationSize=3 GA-InitMolsToFragmentFile=init_pop.txt #Fragmentation FRG-CUTTINGRULESFILE=cutting_rules.txt