$darkmode
DENOPTIM
DGraph.java
Go to the documentation of this file.
1/*
2 * DENOPTIM
3 * Copyright (C) 2019 Vishwesh Venkatraman <vishwesh.venkatraman@ntnu.no> and
4 * Marco Foscato <marco.foscato@uib.no>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published
8 * by the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20package denoptim.graph;
21
22import java.io.File;
23import java.io.Reader;
24import java.lang.reflect.Type;
25import java.util.ArrayDeque;
26import java.util.ArrayList;
27import java.util.Collection;
28import java.util.Collections;
29import java.util.Comparator;
30import java.util.HashMap;
31import java.util.HashSet;
32import java.util.Iterator;
33import java.util.LinkedHashMap;
34import java.util.List;
35import java.util.Map;
36import java.util.Map.Entry;
37import java.util.Queue;
38import java.util.Set;
39import java.util.concurrent.atomic.AtomicInteger;
40import java.util.function.Function;
41import java.util.logging.Level;
42import java.util.logging.Logger;
43import java.util.stream.Collectors;
44
45import org.jgrapht.alg.isomorphism.VF2GraphIsomorphismInspector;
46import org.jgrapht.graph.DefaultUndirectedGraph;
47import org.openscience.cdk.graph.ConnectivityChecker;
48import org.openscience.cdk.interfaces.IAtom;
49import org.openscience.cdk.interfaces.IAtomContainer;
50
51import com.google.gson.Gson;
52import com.google.gson.GsonBuilder;
53import com.google.gson.JsonArray;
54import com.google.gson.JsonDeserializationContext;
55import com.google.gson.JsonDeserializer;
56import com.google.gson.JsonElement;
57import com.google.gson.JsonObject;
58import com.google.gson.JsonParseException;
59import com.google.gson.JsonSerializationContext;
60import com.google.gson.JsonSerializer;
61
62import denoptim.constants.DENOPTIMConstants;
63import denoptim.exception.DENOPTIMException;
64import denoptim.fragspace.FragmentSpace;
65import denoptim.fragspace.FragmentSpaceParameters;
66import denoptim.graph.APClass.APClassDeserializer;
67import denoptim.graph.Edge.BondType;
68import denoptim.graph.Template.ContractLevel;
69import denoptim.graph.Vertex.BBType;
70import denoptim.graph.Vertex.DENOPTIMVertexDeserializer;
71import denoptim.graph.Vertex.VertexType;
72import denoptim.graph.rings.ClosableChain;
73import denoptim.graph.rings.CyclicGraphHandler;
74import denoptim.graph.rings.PathSubGraph;
75import denoptim.graph.rings.RingClosingAttractor;
76import denoptim.graph.rings.RingClosureParameters;
77import denoptim.graph.simplified.Node;
78import denoptim.graph.simplified.NodeConnection;
79import denoptim.graph.simplified.UndirectedEdge;
80import denoptim.io.DenoptimIO;
81import denoptim.json.DENOPTIMgson;
82import denoptim.json.DENOPTIMgson.DENOPTIMExclusionStrategyNoAPMap;
83import denoptim.molecularmodeling.ThreeDimTreeBuilder;
84import denoptim.programs.RunTimeParameters;
85import denoptim.programs.RunTimeParameters.ParametersType;
86import denoptim.utils.GeneralUtils;
87import denoptim.utils.GraphConversionTool;
88import denoptim.utils.GraphEdit;
89import denoptim.utils.GraphUtils;
90import denoptim.utils.MoleculeUtils;
91import denoptim.utils.MutationType;
92import denoptim.utils.ObjectPair;
93import denoptim.utils.RotationalSpaceUtils;
94
95
101public class DGraph implements Cloneable
102{
106 List<Vertex> gVertices;
107
111 List<Edge> gEdges;
112
116 List<Ring> gRings;
117
121 List<ClosableChain> closableChains;
122
123 /*
124 * Unique graph id
125 */
127
128 /*
129 * store the set of symmetric vertex ids at each level. This is only
130 * applicable for symmetric graphs
131 */
132 private List<SymmetricVertexes> symVertices;
133
139 //TODO: rename to Provenance
140 String localMsg;
141
146
151
155 private DefaultUndirectedGraph<Vertex, UndirectedEdge>
156 jGraph = null;
157
161 private DefaultUndirectedGraph<Node, NodeConnection>
163
167 public enum StringFormat {JSON, GRAPHENC}
168
172 private AtomicInteger apCounter = new AtomicInteger(1);
173
178 private static final String SYM_ID = "symmetryKey";
179
180//------------------------------------------------------------------------------
181
182 public DGraph(List<Vertex> gVertices, List<Edge> gEdges)
183 {
184 this.gVertices = gVertices;
185 for (Vertex v : this.gVertices)
186 v.setGraphOwner(this);
187 this.gEdges = gEdges;
188 gRings = new ArrayList<>();
189 closableChains = new ArrayList<>();
190 symVertices = new ArrayList<>();
191 localMsg = "";
192 }
193
194//------------------------------------------------------------------------------
195
196 public DGraph(List<Vertex> gVertices, List<Edge> gEdges, List<Ring> gRings)
197 {
198 this(gVertices, gEdges);
199 this.gRings = gRings;
200 closableChains = new ArrayList<>();
201 symVertices = new ArrayList<>();
202 localMsg = "";
203 }
204
205//------------------------------------------------------------------------------
206
207 public DGraph(List<Vertex> gVertices, List<Edge> gEdges, List<Ring> gRings,
208 List<SymmetricVertexes> symSets)
209 {
210 this(gVertices, gEdges, gRings);
211 closableChains = new ArrayList<>();
212 this.symVertices = symSets;
213 localMsg = "";
214 }
215
216//------------------------------------------------------------------------------
217
218 public DGraph(List<Vertex> gVertices, List<Edge> gEdges, List<Ring> gRings,
219 List<ClosableChain> closableChains,
220 List<SymmetricVertexes> symVertices)
221 {
223 this.closableChains = closableChains;
224 localMsg = "";
225 }
226
227//------------------------------------------------------------------------------
228
229 public DGraph()
230 {
231 gVertices = new ArrayList<>();
232 gEdges = new ArrayList<>();
233 gRings = new ArrayList<>();
234 closableChains = new ArrayList<>();
235 symVertices = new ArrayList<>();
236 localMsg = "";
237 }
238
239//------------------------------------------------------------------------------
240
246 {
247 this.candidate = candidate;
248 }
249
250//------------------------------------------------------------------------------
251
258 {
259 return candidate;
260 }
261
262//------------------------------------------------------------------------------
263
264 public void setGraphId(int id)
265 {
266 graphId = id;
267 }
268
269//------------------------------------------------------------------------------
270
271 public int getGraphId()
272 {
273 return graphId;
274 }
275
276//------------------------------------------------------------------------------
277
278 //TODO: rename to Provenance
279 public void setLocalMsg(String msg)
280 {
281 localMsg = msg;
282 }
283
284//------------------------------------------------------------------------------
285
286 //TODO: rename to Provenance
287 public String getLocalMsg()
288 {
289 return localMsg;
290 }
291
292//------------------------------------------------------------------------------
293
294 public boolean hasSymmetricAP()
295 {
296 return (!symVertices.isEmpty());
297 }
298
299//------------------------------------------------------------------------------
300
302 {
303 boolean res = false;
305 {
306 if (ss.contains(v))
307 {
308 res = true;
309 break;
310 }
311 }
312 return res;
313 }
314
315//------------------------------------------------------------------------------
316
322 {
323 return symVertices.size();
324 }
325
326//------------------------------------------------------------------------------
327
332 public Iterator<SymmetricVertexes> getSymSetsIterator()
333 {
334 return symVertices.iterator();
335 }
336
337//------------------------------------------------------------------------------
338
343 public List<Vertex> getSymVerticesForVertex(Vertex v)
344 {
345 List<Vertex> lst = new ArrayList<Vertex>();
347 {
348 if (ss.contains(v))
349 {
350 ss.stream().forEach(i -> lst.add((Vertex) i));
351 }
352 }
353 return lst;
354 }
355
356//------------------------------------------------------------------------------
369 {
370 int initialSize = symVertices.size();
371 List<Vertex> uniqueVertices = new ArrayList<>();
372 Map<String, List<Vertex>> pathMap = new HashMap<>();
373 Set<Vertex> visited = new HashSet<>();
374 Vertex scaffold = null;
375
376 AtomicInteger vrtxIdCounter = new AtomicInteger();
377 AtomicInteger apIdCounter = new AtomicInteger();
378
379 for (Vertex vertex : getVertexList())
380 {
381 if (vertex.getBuildingBlockType() == BBType.SCAFFOLD) {
382 if (scaffold == null) scaffold = vertex;
383 }
384 boolean isVertexNew = true;
385 Vertex matchedVertex = null;
386
387 // Check if the vertex is the same as other in the unique vertices
388 for (Vertex uniqueVertex : uniqueVertices)
389 {
390 // Equality condition
391 if (vertex.sameAs(uniqueVertex))
392 {
393 isVertexNew = false;
394 matchedVertex = uniqueVertex;
395 break;
396 }
397 }
398 if (isVertexNew)
399 {
400 // Create unique key for the vertex
401 int vertexKey = vrtxIdCounter.getAndIncrement();
402 vertex.setProperty(SYM_ID, vertexKey);
403 // Create unique key for each AP of the vertex
404 Map<AttachmentPoint, Integer> apKeys = new HashMap<>();
405 for (AttachmentPoint ap : vertex.getAttachmentPoints())
406 {
407 // symAPs share the same symmetry key
408 SymmetricAPs symAPs = vertex.getSymmetricAPs(ap);
409 if (!symAPs.isEmpty())
410 {
411 Integer sharedKey = apKeys.get(symAPs.get(0));
412
413 if (sharedKey == null) {
414 sharedKey = apIdCounter.getAndIncrement();
415 apKeys.put(symAPs.get(0), sharedKey);
416 }
417 for (AttachmentPoint symAp : symAPs) {
418 symAp.setProperty(SYM_ID, sharedKey);
419 }
420
421 } else {
422
423 int apKey = apIdCounter.getAndIncrement();
424 ap.setProperty(SYM_ID, apKey);
425 }
426
427 }
428 // Add the vertex to the list of unique vertices
429 uniqueVertices.add(vertex);
430
431 } else {
432
433 // The vertex is not new, so we copy properties from the
434 // matched vertex
435 vertex.setProperty(SYM_ID, matchedVertex.getProperty(SYM_ID));
436
437 // Ensure APs are synchronized between the current vertex
438 // and the matched vertex
439 for (int i = 0; i < vertex.getAttachmentPoints().size(); i++) {
440 AttachmentPoint currentAP =
441 vertex.getAttachmentPoints().get(i);
442 AttachmentPoint matchedAP =
443 matchedVertex.getAttachmentPoints().get(i);
444 // Since sameAs checks APs order, AP indices align
445 currentAP.setProperty(SYM_ID,matchedAP.getProperty(SYM_ID));
446 }
447 }
448 }
449
450 if (scaffold == null) {
451 throw new DENOPTIMException("No scaffold vertex found in the graph.");
452 }
453
454 // Get all path with Depth First Search (DFS) algorithm
455 dfsEncodePaths(scaffold, "", visited, pathMap);
456
457 // Detect symmetric sets based on path encodings
458 for (Map.Entry<String, List<Vertex>> entry : pathMap.entrySet()) {
459 List<Vertex> symVertices = entry.getValue();
460 if (symVertices.size() > 1)
461 {
463 }
464 }
465
466 return (symVertices.size()-initialSize)>0;
467
468 }
469//------------------------------------------------------------------------------
487 private void dfsEncodePaths(Vertex current,
488 String currentPath,
489 Set<Vertex> visited,
490 Map<String, List<Vertex>> pathMap) throws DENOPTIMException {
491
492 if (visited.contains(current))
493 {
494 return;
495 }
496 visited.add(current);
497
498 Integer vertexKey = (Integer) current.getProperty(SYM_ID);
499 currentPath += vertexKey.toString();
500
501 // Store the current path in pathMap
502 pathMap.computeIfAbsent(currentPath, k -> new ArrayList<>()).add(current);
503
504 // Recursively encode paths for each child vertex
505 for (AttachmentPoint ap : current.getAttachmentPoints()) {
506
507 // Check if the AP is making an edge
508 if (ap.getEdgeUser()!=null &&
509 !visited.contains(ap.getEdgeUser().getTrgAP().getOwner()))
510 {
511 Edge edge = ap.getEdgeUser();
512 // Get target AP
513 AttachmentPoint trAp = edge.getTrgAP();
514 // Get child vertex
515 Vertex child = trAp.getOwner();
516 Integer apKey = (Integer) ap.getProperty(SYM_ID);
517
518 // Ensure the apKey is valid
519 if (apKey != null) {
520 dfsEncodePaths(child,
521 currentPath + apKey.toString(),
522 visited,
523 pathMap);
524 } else {
525 throw new DENOPTIMException("Error: AP encoding not found "
526 + "for " + ap);
527 }
528 }
529 }
530 }
531
532//------------------------------------------------------------------------------
555// public boolean detectSymVertexSets() throws DENOPTIMException
556// {
557// int initialSize = symVertices.size();
558//
559// // This is to hold vertexes in a staging area (symVrtxsFromAnyBranch)
560// // without adding them to a SymmetricVertexes right away.
561// Set<Vertex> alreadyAssignedVrtxs = new HashSet<Vertex>();
562//
563// // The sym vertexes on vrtx can have sym counterpart
564// // that are attached to vertexes sym to vrtx. Prepare a storage to
565// // collect all sym counterparts from any of vertexes sym to vrtx
566// Map<SymmetricAPs,List<Vertex>> symVrtxsFromAnyBranch =
567// new HashMap<SymmetricAPs,List<Vertex>>();
568// for (Vertex vrtx : getVertexList())
569// {
570// // NB: if there is a symmetric relation involving vrtx, then
571// // vrtx is in the set returned by the following lines
572// List<Vertex> vrtxsSymToVrtx = new ArrayList<Vertex>();
573// for (List<Vertex> tmpSymSets : symVrtxsFromAnyBranch.values())
574// {
575// if (tmpSymSets.contains(vrtx))
576// {
577// vrtxsSymToVrtx.addAll(tmpSymSets);
578// }
579// }
580// if (vrtxsSymToVrtx.size()==0)
581// vrtxsSymToVrtx.add(vrtx);
582//
583// for (Vertex symToVrtx : vrtxsSymToVrtx)
584// {
585// Map<SymmetricAPs,List<Vertex>> symChildenSetsOnSymToVrtxs =
586// findSymmetrySetsOfChildVertexes(symToVrtx,
587// alreadyAssignedVrtxs);
588//
589// for (SymmetricAPs key : symChildenSetsOnSymToVrtxs.keySet())
590// {
591// // Find any mapping with previously recorded SymmetricAPs
592// boolean foundSymmetricBranch = false;
593// for (SymmetricAPs keyOnMaster : key.getAllSameAs(
594// symVrtxsFromAnyBranch.keySet()))
595// {
596// foundSymmetricBranch = true;
597//
598// // Here we must NOT consider the already assigned ones!
599// if (areApsUsedBySymmetricUsers(key.get(0),
600// keyOnMaster.get(0), new HashSet<Vertex>()))
601// {
602// // the previously recorded branch and
603// // this one are consistent
604// symVrtxsFromAnyBranch.get(keyOnMaster).addAll(
605// symChildenSetsOnSymToVrtxs.get(key));
606// } else {
607// // branches correspond to two different sets of
608// // symmetric vertexes. So, we treat the new branch
609// // independently
610// foundSymmetricBranch = false;
611// }
612// }
613// if (!foundSymmetricBranch)
614// {
615// // Effectively, in the first iteration of the loop
616// // we will always end up here
617// List<Vertex> lst = new ArrayList<Vertex>();
618// lst.addAll(symChildenSetsOnSymToVrtxs.get(key));
619// symVrtxsFromAnyBranch.put(key, lst);
620// }
621// }
622// }
623// }
624//
625//
626// for (Map.Entry<SymmetricAPs,
627// List<Vertex>> entry : symVrtxsFromAnyBranch.entrySet())
628// {
629//
630// List<Vertex> symVertexes = entry.getValue();
631// SymmetricAPs key = entry.getKey();
632// if (symVertexes.size() < 2) {
633// // We get rid of placeholders for vertexes that use APs that
634// // are not part of a symmetriAPs, but could have been part
635// // of symmetric subgraphs
636// continue;
637// } else {
638//
639// Map<Vertex, List<Vertex>> vertexChildrenMap = new HashMap<>();
640// // Get children tree for each vertex in the symmetric set
641// for (Vertex vertex : symVertexes) {
642// List<Vertex> children = new ArrayList<>();
643// getChildrenTree(vertex, children);
644// vertexChildrenMap.put(vertex, children);
645// }
646//
647// boolean allInOneBranch = false;
648// Set<Vertex> toRemove = new HashSet<>();
649// for (Vertex parent : vertexChildrenMap.keySet()) {
650// List<Vertex> children = vertexChildrenMap.get(parent);
651// boolean allChildren = true;
652// for (Vertex other : symVertexes) {
653// if (other != parent && !children.contains(other)) {
654// allChildren = false;
655// break;
656// }
657// }
658// if (allChildren) {
659// allInOneBranch = true;
660// break;
661// }
662// // Mark children for removal if they are contained in any
663// // parent's children tree
664// for (Vertex child : children) {
665// if (symVertexes.contains(child) && child != parent) {
666// toRemove.add(child);
667// }
668// }
669// }
670// if (allInOneBranch) {
671// // All vertices are in the same branch, skip the set
672// continue;
673//
674// } else if (!toRemove.isEmpty()) {
675// // Remove only the child vertices.
676// symVertexes.removeAll(toRemove);
677// }
678// }
679// alreadyAssignedVrtxs.addAll(symVertexes);
680// addSymmetricSetOfVertices(new SymmetricVertexes(symVertexes));
681// }
682//
683// return (symVertices.size()-initialSize)>0;
684// }
685
686//------------------------------------------------------------------------------
687
689// Vertex vrtx, Set<Vertex> alreadyAssignedVrtxs)
690// {
691// Map<SymmetricAPs,List<Vertex>> symSetsOfChildVrtxs =
692// new HashMap<SymmetricAPs,List<Vertex>>();
693//
694// Set<AttachmentPoint> doneAPs = new HashSet<AttachmentPoint>();
695// for (SymmetricAPs symAPs : vrtx.getSymmetricAPSets())
696// {
697// // First condition: all symmetric APs must be in use
698// boolean addSymAPsAreUsed = true;
699// for (AttachmentPoint ap : symAPs)
700// {
701// if (ap.isAvailableThroughout())
702// {
703// addSymAPsAreUsed = false;
704// break;
705// }
706// }
707// if (!addSymAPsAreUsed)
708// continue;
709//
710// // Now consider what vertex is attached to the symmetric APs
711// AttachmentPoint firstAp = symAPs.get(0);
712//
713// boolean setSymmetryRelation = true;
714// List<Vertex> symVertexes = new ArrayList<Vertex>();
715// symVertexes.add(firstAp.getLinkedAPThroughout().getOwner());
716// for (AttachmentPoint ap : symAPs)
717// {
718// doneAPs.add(ap);
719//
720// if (firstAp==ap)
721// continue;
722//
723// setSymmetryRelation = areApsUsedBySymmetricUsers(firstAp, ap,
724// alreadyAssignedVrtxs);
725// if (!setSymmetryRelation)
726// break;
727//
728// // OK: this user of AP is symmetric to the user on firstAP
729// symVertexes.add(ap.getLinkedAPThroughout().getOwner());
730// }
731//
732// if (setSymmetryRelation)
733// {
734// symSetsOfChildVrtxs.put(symAPs,symVertexes);
735// alreadyAssignedVrtxs.addAll(symVertexes);
736// }
737// }
738//
739// // Here we account for the possibility that vertex without sym APs
740// // is part of a subgraph the is symmetrically reproduced elsewhere.
741// // This is a common pattern in chemistry.
742// // To this end we create dummy symmetric sets of APs that contain
743// // only one APs, and use them as placeholder in case the same AP-user
744// // is found on symmetric branches.
745// for (AttachmentPoint ap : vrtx.getAttachmentPoints())
746// {
747// if (doneAPs.contains(ap) || ap.isAvailableThroughout())
748// continue;
749//
750// Vertex user = ap.getLinkedAPThroughout().getOwner();
751// if (alreadyAssignedVrtxs.contains(user))
752// continue;
753//
754// // Create an artifact of SymmetricAPs that contains one entry
755// SymmetricAPs soloSymAps = new SymmetricAPs();
756// soloSymAps.add(ap);
757//
758// // Well, this contains only one entry, but for consistency we still
759// // use a list.
760// List<Vertex> symVertexes = new ArrayList<Vertex>();
761// symVertexes.add(user);
762//
763// symSetsOfChildVrtxs.put(soloSymAps,symVertexes);
764// alreadyAssignedVrtxs.addAll(symVertexes);
765// }
766// return symSetsOfChildVrtxs;
767// }
768//
769//------------------------------------------------------------------------------
770
771// /**
772// * Checks if the {@link Vertex}s that are attached to two given
773// * {@link AttachmentPoint}s apA and apB satisfy these conditions:
774// * <ul>
775// * <li>the linked APs must return true from
776// * {@link AttachmentPoint#sameAs(AttachmentPoint)}</li>
777// * <li>the {@link Vertex} owner of apB is not contained in the set of
778// * already-assigned vertexes (the 3rd argument)</li>
779// * <li>the {@link Vertex}a attached to apA andapB must be return satisfy
780// * {@link Vertex#sameAs(Vertex)}</li>
781// * <li>if such vertexes are instances of {@link Fragment}, then they must
782// * satisfy {@link Fragment#isIsomorphicTo(Vertex)}.</li>
783// * </ul>
784// * These conditions, when satisfied for a pair of used and symmetric
785// * {@link AttachmentPoint}s apA and apB should suffice to assign the
786// * two user {@link Vertex}s to the same {@link SymmetricVertexes} set.
787// * @param apA one attachment point in the pair.
788// * @param apB the other attachment point in the pair.
789// * @param alreadyAssignedVrtxs a set of vertexes that have been already
790// * assigned to {@link SymmetricVertexes} set.
791// * @return
792// */
793// public static boolean areApsUsedBySymmetricUsers(AttachmentPoint apA,
794// AttachmentPoint apB, Set<Vertex> alreadyAssignedVrtxs)
795// {
796// AttachmentPoint apUserOfApA = apA.getLinkedAPThroughout();
797// Vertex userOfApA = apUserOfApA.getOwner();
798// boolean userOfApAIsFragment = Fragment.class.isInstance(userOfApA);
799//
800// // 1st condition: (fast failing) the linked AP must have
801// // the same features. This is faster than checking vertex
802// // isomorphism.
803// AttachmentPoint apUserOfApB = apB.getLinkedAPThroughout();
804// if (!apUserOfApA.sameAs(apUserOfApB))
805// {
806// return false;
807// }
808//
809// // 2nd condition: (fast-failing) the linked vertexes
810// // must be unassigned
811// Vertex userOfApB = apUserOfApB.getOwner();
812// if (alreadyAssignedVrtxs.contains(userOfApB))
813// {
814// return false;
815// }
816//
817// // 3rd condition: (not fast, not too slow) the linked
818// // vertexes must be have same features
819// if (!userOfApB.sameAs(userOfApA))
820// {
821// return false;
822// }
823//
824// // 4th condition: (slow) the linked vertexes
825// // are fragments that have been generated on the fly, so
826// // they do not have an assigned building block ID. We must
827// // therefore compare their internal structure.
828// if (userOfApAIsFragment)
829// {
830// // At this point we know the two vertexes are instances
831// // of the same class.
832// Fragment frgUserOfApA = (Fragment) userOfApA;
833// Fragment frgUserOfApB = (Fragment) userOfApB;
834// if (!frgUserOfApA.isIsomorphicTo(frgUserOfApB))
835// {
836// return false;
837// }
838// }
839// return true;
840// }
841
842//------------------------------------------------------------------------------
843
849 {
850 symVertices.remove(ss);
851 }
852
853//------------------------------------------------------------------------------
854
862 {
864 {
865 if (ss.contains(v))
866 {
867 return ss;
868 }
869 }
870 return new SymmetricVertexes();
871 }
872
873//------------------------------------------------------------------------------
874
875 public void setSymmetricVertexSets(List<SymmetricVertexes> symVertices)
876 {
877 this.symVertices.clear();
878 this.symVertices.addAll(symVertices);
879 }
880
881//------------------------------------------------------------------------------
882
890 throws DENOPTIMException
891 {
892 for (SymmetricVertexes oldSS : symVertices)
893 {
894 if (!Collections.disjoint(oldSS, symSet))
895 {
896 throw new DENOPTIMException("Adding " + symSet + " while "
897 + "there is already one that contains some of the same "
898 + "items");
899 }
900 }
901 symVertices.add(symSet);
902 }
903
904//------------------------------------------------------------------------------
905
906 public void setVertexList(ArrayList<Vertex> vertices)
907 {
908 gVertices = vertices;
909 jGraph = null;
910 jGraphKernel = null;
911 }
912
913//------------------------------------------------------------------------------
914
915 public void setEdgeList(ArrayList<Edge> edges)
916 {
917 gEdges = edges;
918 jGraph = null;
919 jGraphKernel = null;
920 }
921
922//------------------------------------------------------------------------------
923
924 public void setRings(ArrayList<Ring> rings)
925 {
926 gRings = rings;
927 jGraph = null;
928 jGraphKernel = null;
929 }
930
931//------------------------------------------------------------------------------
932
933 public void setCandidateClosableChains(ArrayList<ClosableChain> closableChains)
934 {
935 this.closableChains = closableChains;
936 }
937
938//------------------------------------------------------------------------------
939
940 public List<ClosableChain> getClosableChains()
941 {
942 return closableChains;
943 }
944
945//------------------------------------------------------------------------------
946
947 public List<Vertex> getVertexList()
948 {
949 return gVertices;
950 }
951
952//------------------------------------------------------------------------------
953
969 {
970 switch (gVertices.size())
971 {
972 case 0:
973 return null;
974 case 1:
975 return getVertexAtPosition(0);
976 }
978 for (Edge e : this.getEdgeList())
979 {
980 if (e.getTrgAP().getOwner() == v0)
981 {
982 ArrayList<Vertex> parentTree = new ArrayList<>();
983 getParentTree(v0,parentTree);
984 return parentTree.get(parentTree.size()-1);
985 }
986 }
987 return v0;
988 }
989
990//------------------------------------------------------------------------------
991
992 public List<Edge> getEdgeList()
993 {
994 return gEdges;
995 }
996
997//------------------------------------------------------------------------------
998
999 public List<Ring> getRings()
1000 {
1001 return gRings;
1002 }
1003
1004//------------------------------------------------------------------------------
1005
1012 public List<Edge> getEdgesWithSrc(Vertex v)
1013 {
1014 List<Edge> edges = new ArrayList<Edge>();
1015 for (Edge e : this.getEdgeList())
1016 {
1017 if (e.getSrcAP().getOwner() == v)
1018 {
1019 edges.add(e);
1020 }
1021 }
1022 return edges;
1023 }
1024
1025//------------------------------------------------------------------------------
1026
1033 public List<Edge> getEdgesWithTrg(Vertex v)
1034 {
1035 List<Edge> edges = new ArrayList<Edge>();
1036 for (Edge e : this.getEdgeList())
1037 {
1038 if (e.getTrgAP().getOwner() == v)
1039 {
1040 edges.add(e);
1041 }
1042 }
1043 return edges;
1044 }
1045
1046//------------------------------------------------------------------------------
1047
1054 public ArrayList<Ring> getRingsInvolvingVertex(Vertex v)
1055 {
1056 ArrayList<Ring> rings = new ArrayList<Ring>();
1057 for (Ring r : gRings)
1058 {
1059 if (r.contains(v))
1060 {
1061 rings.add(r);
1062 }
1063 }
1064 return rings;
1065 }
1066
1067//------------------------------------------------------------------------------
1068
1075 public ArrayList<Ring> getRingsInvolvingVertex(Vertex[] vs)
1076 {
1077 ArrayList<Ring> rings = new ArrayList<Ring>();
1078 for (Ring r : gRings)
1079 {
1080 boolean matchesAll = true;
1081 for (int i=0; i<vs.length; i++)
1082 {
1083 if (!r.contains(vs[i]))
1084 {
1085 matchesAll = false;
1086 break;
1087 }
1088 }
1089 if (matchesAll)
1090 {
1091 rings.add(r);
1092 }
1093 }
1094 return rings;
1095 }
1096
1097//------------------------------------------------------------------------------
1098
1099 public ArrayList<Ring> getRingsInvolvingVertexID(int vid)
1100 {
1101 ArrayList<Ring> rings = new ArrayList<Ring>();
1102 for (Ring r : gRings)
1103 {
1104 if (r.containsID(vid))
1105 {
1106 rings.add(r);
1107 }
1108 }
1109 return rings;
1110 }
1111
1112//------------------------------------------------------------------------------
1113
1120 public boolean hasRings()
1121 {
1122 return gRings.size() > 0;
1123 }
1124
1125//------------------------------------------------------------------------------
1126
1134 public boolean hasOrEmbedsRings()
1135 {
1136 if (gRings.size() > 0)
1137 return true;
1138 for (Vertex v : gVertices)
1139 {
1140 if (!(v instanceof Template))
1141 continue;
1142
1143 Template t = (Template) v;
1145 return true;
1146 }
1147 return false;
1148 }
1149
1150//------------------------------------------------------------------------------
1151
1152 public boolean isVertexIDInRing(int vid)
1153 {
1154 boolean result = false;
1155 for (Ring r : gRings)
1156 {
1157 if (r.containsID(vid))
1158 {
1159 result = true;
1160 break;
1161 }
1162 }
1163 return result;
1164 }
1165
1166//------------------------------------------------------------------------------
1167
1168 public boolean isVertexInRing(Vertex v)
1169 {
1170 boolean result = false;
1171 for (Ring r : gRings)
1172 {
1173 if (r.contains(v))
1174 {
1175 result = true;
1176 break;
1177 }
1178 }
1179 return result;
1180 }
1181
1182//------------------------------------------------------------------------------
1183
1190 public ArrayList<Vertex> getRCVertices()
1191 {
1192 ArrayList<Vertex> rcvLst = new ArrayList<Vertex>();
1193 for (Vertex v : gVertices)
1194 {
1195 if (v.isRCV())
1196 {
1197 rcvLst.add(v);
1198 }
1199 }
1200 return rcvLst;
1201 }
1202
1203//------------------------------------------------------------------------------
1204
1212 public ArrayList<Vertex> getFreeRCVertices()
1213 {
1214 ArrayList<Vertex> rcvLst = getRCVertices();
1215 ArrayList<Vertex> free = new ArrayList<Vertex>();
1216 for (Vertex v : rcvLst)
1217 {
1218 if (!isVertexInRing(v))
1219 {
1220 free.add(v);
1221 }
1222 }
1223 return free;
1224 }
1225
1226//------------------------------------------------------------------------------
1227
1235 public ArrayList<Vertex> getUsedRCVertices()
1236 {
1237 ArrayList<Vertex> used = new ArrayList<Vertex>();
1238 used.addAll(getRCVertices());
1239 used.removeAll(getFreeRCVertices());
1240 return used;
1241 }
1242
1243//------------------------------------------------------------------------------
1244
1249 public void addEdge(Edge edge)
1250 {
1251 gEdges.add(edge);
1252 jGraph = null;
1253 jGraphKernel = null;
1254 }
1255
1256//------------------------------------------------------------------------------
1257
1258 public void addRing(Ring ring)
1259 {
1260 gRings.add(ring);
1261 jGraph = null;
1262 jGraphKernel = null;
1263 }
1264
1265//------------------------------------------------------------------------------
1266
1275 public void addRing(Vertex vI, Vertex vJ)
1276 throws DENOPTIMException
1277 {
1278 BondType bndTypI = vI.getEdgeToParent().getBondType();
1279 BondType bndTypJ = vJ.getEdgeToParent().getBondType();
1280 if (bndTypI != bndTypJ)
1281 {
1282 String s = "Attempt to close rings is not compatible "
1283 + "to the different bond type specified by the "
1284 + "head and tail APs: (" + bndTypI + "!="
1285 + bndTypJ + " for vertices " + vI + " "
1286 + vJ + ")";
1287 throw new DENOPTIMException(s);
1288 }
1289 addRing(vI,vJ,bndTypI);
1290 jGraph = null;
1291 jGraphKernel = null;
1292 }
1293
1294//------------------------------------------------------------------------------
1295
1303 public void addRing(Vertex vI, Vertex vJ, BondType bndTyp)
1304 {
1305 PathSubGraph path = new PathSubGraph(vI,vJ,this);
1306 ArrayList<Vertex> arrLst = new ArrayList<Vertex>();
1307 arrLst.addAll(path.getVertecesPath());
1308 Ring ring = new Ring(arrLst);
1309 ring.setBondType(bndTyp);
1310 this.addRing(ring);
1311 jGraph = null;
1312 jGraphKernel = null;
1313 }
1314
1315//------------------------------------------------------------------------------
1316
1325 public void addVertex(Vertex vertex) throws DENOPTIMException
1326 {
1327 if (containsVertexID(vertex.getVertexId()))
1328 throw new DENOPTIMException("Vertex must have a VertexID that is "
1329 + "unique within the graph. VertexID '"
1330 + vertex.getVertexId()+ "' already present in graph "
1331 + getGraphId());
1332 vertex.setGraphOwner(this);
1333 gVertices.add(vertex);
1334 jGraph = null;
1335 jGraphKernel = null;
1336 }
1337
1338//------------------------------------------------------------------------------
1339
1347 public void removeVertex(Vertex vertex)
1348 {
1349 if (!gVertices.contains(vertex))
1350 {
1351 return;
1352 }
1353
1354 vertex.resetGraphOwner();
1355 long vid = vertex.getVertexId();
1356
1357 // delete also any ring involving the removed vertex
1358 if (isVertexInRing(vertex))
1359 {
1360 ArrayList<Ring> rToRm = getRingsInvolvingVertex(vertex);
1361 for (Ring r : rToRm)
1362 {
1363 removeRing(r);
1364 }
1365 }
1366
1367 // remove edges involving the removed vertex
1368 ArrayList<Edge> eToDel = new ArrayList<>();
1369 for (int i=0; i<gEdges.size(); i++)
1370 {
1371 Edge edge = gEdges.get(i);
1372 if (vid == edge.getTrgVertex())
1373 {
1374 eToDel.add(edge);
1375 }
1376 // NB: the following allows to break the spanning tree
1377 if (vid == edge.getSrcVertex())
1378 {
1379 eToDel.add(edge);
1380 }
1381 }
1382 for (Edge e : eToDel)
1383 {
1384 this.removeEdge(e);
1385 }
1386
1387 //delete the removed vertex from symmetric sets, but leave other vertices
1388 List<SymmetricVertexes> ssToRemove = new ArrayList<SymmetricVertexes>();
1390 {
1391 if (ss.contains(vertex))
1392 {
1393 if (ss.size() < 3)
1394 {
1395 ssToRemove.add(ss);
1396 }
1397 else
1398 {
1399 ss.remove(vertex);
1400 }
1401 }
1402 }
1403 symVertices.removeAll(ssToRemove);
1404
1405 // remove the vertex from the graph
1406 gVertices.remove(vertex);
1407
1408 jGraph = null;
1409 jGraphKernel = null;
1410 }
1411
1412//------------------------------------------------------------------------------
1413
1423 public boolean removeVertexAndWeld(Vertex vertex,
1424 FragmentSpace fragSpace) throws DENOPTIMException
1425 {
1426 if (!gVertices.contains(vertex))
1427 {
1428 return false;
1429 }
1430
1431 List<Vertex> symSites = getSymVerticesForVertex(vertex);
1432 if (symSites.size() == 0)
1433 {
1434 symSites.add(vertex);
1435 } else {
1436 //TODO-V3 flip coin to decide if this should be a symmetric operation or not
1437 }
1438 for (Vertex oldLink : symSites)
1439 {
1441 if (!removeSingleVertexAndWeld(oldLink, fragSpace))
1442 {
1443 return false;
1444 }
1445 }
1446 // Reject deletions that cause the collapse of a 3-atom ring into a
1447 // loop (i.e., 1-atom ring) or multiple connection (i.e., a 3-atom ring)
1448 for (Ring r : gRings)
1449 {
1450 // 3 = 1 actual vertex + 2 RCVs
1451 if (r.getSize()!=3)
1452 continue;
1453
1454 AttachmentPoint apH = r.getHeadVertex().getEdgeToParent()
1455 .getSrcAPThroughout();
1456 AttachmentPoint apT = r.getTailVertex().getEdgeToParent()
1457 .getSrcAPThroughout();
1458
1459 if (apH.hasSameSrcAtom(apT) || apH.hasConnectedSrcAtom(apT))
1460 return false;
1461 }
1462 return true;
1463 }
1464
1465//------------------------------------------------------------------------------
1466
1475 public boolean removeSingleVertexAndWeld(Vertex vertex,
1476 FragmentSpace fragSpace) throws DENOPTIMException
1477 {
1478 if (!gVertices.contains(vertex))
1479 {
1480 return false;
1481 }
1482 if (vertex == getSourceVertex())
1483 {
1484 // Make sure there is something to weld, or give up. This to avoid
1485 // trying to remove the scaffold vertex (i.e., a vertex that has no
1486 // parents in this graph and the APs of which are only user as
1487 // source APs)
1488 boolean foundLinkToParent = false;
1489 for (AttachmentPoint ap : vertex.getAttachmentPoints())
1490 {
1491 if (ap.isAvailable() && !ap.isAvailableThroughout())
1492 {
1493 if (!ap.isSrcInUserThroughout())
1494 foundLinkToParent = true;
1495 }
1496 }
1497 if (!foundLinkToParent)
1498 return false;
1499
1500 // When we try to remove the only vertex inside a template, we
1501 // are removing the template itself
1502 if (gVertices.size()==1 && templateJacket!=null)
1503 {
1505 templateJacket, fragSpace);
1506 }
1507 }
1508
1509 // Get all APs that we'll try to weld into the parent
1510 ArrayList<AttachmentPoint> needyAPsOnChildren =
1511 new ArrayList<AttachmentPoint>();
1512 // And all APs where we could weld onto
1513 ArrayList<AttachmentPoint> freeAPsOnParent =
1514 new ArrayList<AttachmentPoint>();
1515 // vertex.getAPsFromChilddren(); //No, because it enter templates
1516 Map<AttachmentPoint,AttachmentPoint> apOnOldToNeedyAP =
1517 new HashMap<AttachmentPoint,AttachmentPoint>();
1518 for (AttachmentPoint apOnOld : vertex.getAttachmentPoints())
1519 {
1520 if (!apOnOld.isAvailableThroughout())
1521 {
1522 if (apOnOld.isSrcInUserThroughout())
1523 {
1524 // Links that depart from vertex
1525 AttachmentPoint needyAP =
1526 apOnOld.getLinkedAPThroughout();
1527 // NB: here do not use getSrcThroughout because it would
1528 // enter trg templates rather than staying on their surface.
1529 needyAPsOnChildren.add(needyAP);
1530 apOnOldToNeedyAP.put(apOnOld, needyAP);
1531 } else {
1532 AttachmentPoint apOnParent =
1533 apOnOld.getLinkedAPThroughout();
1534 // NB: here do not use getSrcThroughout because it would
1535 // enter src templates rather than staying on their surface.
1536 freeAPsOnParent.add(apOnParent);
1537 freeAPsOnParent.addAll(apOnParent.getOwner()
1539 }
1540 }
1541 }
1542
1543 // Get all possible parentAPs-childAPs mappings
1544 List<APMapping> mappings = fragSpace.mapAPClassCompatibilities(
1545 freeAPsOnParent, needyAPsOnChildren, 500);
1546 if (mappings.size() == 0)
1547 {
1548 // No APClass-compatible possibility of removing the link.
1549 return false;
1550 }
1551
1552 // Score mapping to prioritise those that preserve rings.
1553 // This to differentiate from the combination of DELETE+EXTEND operation
1554 // which cannot preserve rings.
1555 List<Integer> preferences = new ArrayList<Integer>();
1556 // Score rings in this level's graph
1557 for (int i=0; i<needyAPsOnChildren.size(); i++)
1558 {
1559 AttachmentPoint needyAP = needyAPsOnChildren.get(i);
1560 preferences.add(0);
1561
1562 Vertex ownerOfNeedy = needyAP.getOwner();
1563 for (Ring r : ownerOfNeedy.getGraphOwner()
1564 .getRingsInvolvingVertex(ownerOfNeedy))
1565 {
1566 // NB: here we stay at the level of the graph owning ownerOfNeedy
1567 Vertex lastBeforeOwnerOfNeedy =
1568 needyAP.getLinkedAP().getOwner();
1569 if (r.contains(lastBeforeOwnerOfNeedy))
1570 {
1571 preferences.set(i, preferences.get(i) + 1);
1572 }
1573 }
1574 }
1575
1576 // Choose best scoring mapping
1577 int maxScore = Integer.MIN_VALUE;
1578 APMapping bestScoringMapping = null;
1579 for (APMapping apm : mappings)
1580 {
1581 int score = 0;
1582 for (AttachmentPoint ap : apm.values())
1583 {
1584 score = score + preferences.get(needyAPsOnChildren.indexOf(ap));
1585 }
1586 if (score > maxScore)
1587 {
1588 maxScore = score;
1589 bestScoringMapping = apm;
1590 }
1591 }
1592
1593 APMapping bestScoringMappingReverse = new APMapping();
1594 for (Entry<AttachmentPoint, AttachmentPoint> e :
1595 bestScoringMapping.entrySet())
1596 {
1597 bestScoringMappingReverse.put(e.getValue(), e.getKey());
1598 }
1599
1600 // Update rings involving vertex directly (i.e., in this graph)
1601 ArrayList<Ring> rToEdit = getRingsInvolvingVertex(vertex);
1602 ArrayList<Ring> ringsToRemove = new ArrayList<Ring>();
1603 for (Ring r : rToEdit)
1604 {
1605 r.removeVertex(vertex);
1606 if (r.getSize() < 3)
1607 ringsToRemove.add(r);
1608 }
1609 for (Ring r : ringsToRemove)
1610 {
1611 removeRing(r);
1612 }
1613
1614 // Remove edges to/from old vertex, while keeping track of edits to do
1615 // in a hypothetical jacket template (if such template exists)
1616 LinkedHashMap<AttachmentPoint,AttachmentPoint> newInReplaceOldInInTmpl =
1617 new LinkedHashMap<AttachmentPoint,AttachmentPoint>();
1618 List<AttachmentPoint> oldAPToRemoveFromTmpl =
1619 new ArrayList<AttachmentPoint>();
1620 for (AttachmentPoint oldAP : vertex.getAttachmentPoints())
1621 {
1622 if (oldAP.isAvailable())
1623 {
1624 // NB: if this graph is embedded in a template, free/available
1625 // APs at this level (and sources at the vertex we are removing)
1626 // are mapped on the jacket templates' surface, and must be
1627 // removed.
1628 if (templateJacket!=null)
1629 {
1630 if (!oldAP.isAvailableThroughout())
1631 {
1632 AttachmentPoint lAP =
1633 oldAP.getLinkedAPThroughout();
1634 if (bestScoringMapping.keySet().contains(lAP))
1635 {
1636 newInReplaceOldInInTmpl.put(
1637 bestScoringMapping.get(lAP), oldAP);
1638 } else if (bestScoringMapping.values().contains(lAP))
1639 {
1640 newInReplaceOldInInTmpl.put(
1641 bestScoringMappingReverse.get(lAP), oldAP);
1642 } else {
1643 oldAPToRemoveFromTmpl.add(oldAP);
1644 }
1645 } else {
1646 oldAPToRemoveFromTmpl.add(oldAP);
1647 }
1648 }
1649 } else {
1650 removeEdge(oldAP.getEdgeUser());
1651 }
1652 }
1653
1654 // Update pointers in symmetric sets in this graph level
1655 // NB: this deals only with the symmetric relations of the removed vertex
1656 // The symm. relations of other removed child vertices are dealt with
1657 // when removing those vertices.
1658 List<SymmetricVertexes> ssToRemove = new ArrayList<SymmetricVertexes>();
1659 Iterator<SymmetricVertexes> ssIter = getSymSetsIterator();
1660 while (ssIter.hasNext())
1661 {
1662 SymmetricVertexes ss = ssIter.next();
1663 if (ss.contains(vertex))
1664 {
1665 ss.remove(vertex);
1666 }
1667 if (ss.size() < 2)
1668 ssToRemove.add(ss);
1669 }
1670 symVertices.removeAll(ssToRemove);
1671
1672 // Remove the vertex
1673 getVertexList().remove(vertex);
1674 vertex.resetGraphOwner();
1675
1676 // Add new edges (within the graph owning the removed vertex)
1677 List<AttachmentPoint> reconnettedApsOnChilds =
1678 new ArrayList<AttachmentPoint>();
1679 for (Entry<AttachmentPoint,AttachmentPoint> e :
1680 bestScoringMapping.entrySet())
1681 {
1682 AttachmentPoint apOnParent = e.getKey();
1683 AttachmentPoint apOnChild = e.getValue();
1684 if (containsVertex(apOnChild.getOwner())
1685 && containsVertex(apOnParent.getOwner()))
1686 {
1687 Edge edge = new Edge(apOnParent,apOnChild,
1688 apOnParent.getAPClass().getBondType());
1689 addEdge(edge);
1690 reconnettedApsOnChilds.add(apOnChild);
1691 } else {
1692 if (templateJacket!=null)
1693 {
1694 if (containsVertex(apOnParent.getOwner()))
1695 {
1697 newInReplaceOldInInTmpl.get(apOnParent), //AP on old vertex
1698 apOnParent);
1699 reconnettedApsOnChilds.add(apOnChild);
1700 }
1701 if (containsVertex(apOnChild.getOwner()))
1702 {
1704 newInReplaceOldInInTmpl.get(apOnChild), //AP on old vertex
1705 apOnChild);
1706 reconnettedApsOnChilds.add(apOnChild);
1707 }
1708 // The case where neither is contained in 'this' cannot
1709 // occur because of the initial checks that identify
1710 // attempts to remove the only vertex inside a template.
1711 } else {
1712 DENOPTIMException de = new DENOPTIMException("AP '"
1713 + apOnChild + "' seems connected to a template, "
1714 + "no template was found. Possible bug!");
1715 throw de;
1716 }
1717 }
1718 }
1719
1720 // update the mapping of this vertex's APs in the jacket template
1721 if (templateJacket!=null)
1722 {
1723 // Remove all APs that existed only in the old vertex
1724 for (AttachmentPoint apOnOld : oldAPToRemoveFromTmpl)
1725 {
1727 }
1728 }
1729
1730 // Remove branches of child-APs that were not mapped/done
1731 for (AttachmentPoint apOnChild : needyAPsOnChildren)
1732 {
1733 if (!reconnettedApsOnChilds.contains(apOnChild))
1734 {
1735 removeOrphanBranchStartingAt(apOnChild.getOwner());
1736 }
1737 }
1738
1739 jGraph = null;
1740 jGraphKernel = null;
1741
1742 return !this.containsVertex(vertex);
1743 }
1744
1745//------------------------------------------------------------------------------
1746
1755 throws DENOPTIMException
1756 {
1757 List<Vertex> rcvToReplace = new ArrayList<Vertex>();
1758 List<AttachmentPoint> apToCap = new ArrayList<AttachmentPoint>();
1759 for (Vertex v : getRCVertices())
1760 {
1761 if (getRingsInvolvingVertex(v).size()==0
1762 && v.getEdgeToParent()!=null)
1763 {
1764 rcvToReplace.add(v);
1765 apToCap.add(v.getEdgeToParent().getSrcAP());
1766 }
1767 }
1768 for (int i=0; i<rcvToReplace.size(); i++)
1769 {
1770 Vertex v = rcvToReplace.get(i);
1771 removeVertex(v);
1772
1773 AttachmentPoint apOnParent = apToCap.get(i);
1774 APClass cappAPClass = fragSpace.getAPClassOfCappingVertex(
1775 apOnParent.getAPClass());
1776
1777 if (cappAPClass != null)
1778 {
1779 Vertex capVrt = fragSpace.getCappingVertexWithAPClass(
1780 cappAPClass);
1781 capVrt.setVertexId(v.getVertexId());
1782 appendVertexOnAP(apOnParent, capVrt.getAP(0));
1783 }
1784 }
1785 }
1786
1787//------------------------------------------------------------------------------
1788
1797 {
1798 //Remove previous labeling
1799 for (Vertex v : gVertices)
1800 v.removeProperty(DENOPTIMConstants.VRTSYMMSETID);
1801
1802 Iterator<SymmetricVertexes> ssIter = getSymSetsIterator();
1803 int i = 0;
1804 while (ssIter.hasNext())
1805 {
1806 SymmetricVertexes ss = ssIter.next();
1807 String symmLabel = ss.hashCode() + "-" + i;
1808 for (Vertex v : ss)
1809 {
1810 v.setProperty(DENOPTIMConstants.VRTSYMMSETID, symmLabel);
1811 }
1812 i++;
1813 }
1814 for (Vertex v : gVertices)
1815 {
1816 i++;
1817 if (!v.hasProperty(DENOPTIMConstants.VRTSYMMSETID))
1818 v.setProperty(DENOPTIMConstants.VRTSYMMSETID, v.hashCode()+"-"+i);
1819 }
1820 }
1821
1822//------------------------------------------------------------------------------
1823
1829 {
1830 Map<String,List<Vertex>> collectedLabels = new HashMap<>();
1831 for (Vertex v : gVertices)
1832 {
1833 if (v.hasProperty(DENOPTIMConstants.VRTSYMMSETID))
1834 {
1835 String label = v.getProperty(
1836 DENOPTIMConstants.VRTSYMMSETID).toString();
1837 if (collectedLabels.containsKey(label))
1838 {
1839 collectedLabels.get(label).add(v);
1840 } else {
1841 List<Vertex> lst = new ArrayList<Vertex>();
1842 lst.add(v);
1843 collectedLabels.put(label, lst);
1844 }
1845 v.removeProperty(DENOPTIMConstants.VRTSYMMSETID);
1846 }
1847 }
1848
1849 for (String label : collectedLabels.keySet())
1850 {
1851 List<Vertex> symmvertices = collectedLabels.get(label);
1852
1853 if (symmvertices.size()>1)
1854 {
1855 SymmetricVertexes ss = null;
1856 for (Vertex v : symmvertices)
1857 {
1859 {
1860 ss = getSymSetForVertex(v);
1861 break;
1862 }
1863 }
1864
1865 if (ss != null)
1866 {
1867 for (Vertex v : symmvertices)
1868 ss.add(v);
1869
1870 } else {
1871 ss = new SymmetricVertexes();
1872 for (Vertex v : symmvertices)
1873 ss.add(v);
1874 try
1875 {
1877 } catch (DENOPTIMException e)
1878 {
1879 //this can never happen because we are testing for
1880 // preliminary existence of an id in the existing sets.
1881 }
1882 }
1883 }
1884 }
1885 }
1886
1887
1888//------------------------------------------------------------------------------
1889
1909 public boolean replaceSubGraph(List<Vertex> subGrpVrtxs,
1910 DGraph incomingGraph,
1911 LinkedHashMap<AttachmentPoint,AttachmentPoint> apMap,
1912 FragmentSpace fragSpace) throws DENOPTIMException
1913 {
1914 for (Vertex vToRemove : subGrpVrtxs)
1915 {
1916 if (!gVertices.contains(vToRemove))
1917 {
1918 return false;
1919 }
1920 }
1921
1922 // Capping groups are removed and, if needed, re-added back
1923 subGrpVrtxs.stream().filter(v -> v.getBuildingBlockType()==BBType.CAP)
1924 .forEach(v -> this.removeVertex(v));
1925 subGrpVrtxs.removeIf(v -> v.getBuildingBlockType()==BBType.CAP);
1926 if (subGrpVrtxs.size() == 0)
1927 {
1928 throw new DENOPTIMException("Capping groups cannot be the only "
1929 + "vertex in a subgraph to replace.");
1930 }
1931
1932 // Refresh the symmetry set labels so that clones of the branch inherit
1933 // the same symmetry set labels.
1934 incomingGraph.reassignSymmetricLabels();
1935
1937
1938 // Verify that also the surrounding of vertices in the lists is
1939 // consistent between subGrpVrtxs and verticesToRemove. Even if the
1940 // two are consistent, there can still be differences in the childs.
1941 List<List<Vertex>> compatibleSymSubGrps = new ArrayList<List<Vertex>>();
1942 for (List<Vertex> symmetricSubGrpVrtx : getSymmetricSubGraphs(subGrpVrtxs))
1943 {
1944 boolean skip = false;
1945 for (int iv=0; iv<subGrpVrtxs.size(); iv++)
1946 {
1947 if (skip)
1948 break;
1949 Vertex oriVs = subGrpVrtxs.get(iv);
1950 Vertex symVs = symmetricSubGrpVrtx.get(iv);
1951 List<Vertex> oriVsChildren = oriVs.getChilddren();
1952 List<Vertex> symVsChildren = symVs.getChilddren();
1953
1954 // NB: oriVsChildren does not include CAPs from the
1955 // initial subgraph, while symVsChildren does include the
1956 // corresponding CAPs.
1957 oriVsChildren.removeIf(v -> v.getBuildingBlockType()==BBType.CAP);
1958 symVsChildren.removeIf(v -> v.getBuildingBlockType()==BBType.CAP);
1959 if (oriVsChildren.size()!=symVsChildren.size())
1960 {
1961 // we continue in the outer loop
1962 skip = true;
1963 continue;
1964 }
1965 for (int ic=0; ic<oriVsChildren.size(); ic++)
1966 {
1967 if (skip)
1968 break;
1969 // We have already checked those in the subgraph
1970 if (subGrpVrtxs.contains(oriVsChildren.get(ic)))
1971 continue;
1972 // We do allow the two child to be different vertices, but
1973 // we avoid having one CAP and one not. this because it will
1974 // lead to having free APs on the parent of the first and
1975 // busy APs on the parent of the second. This prevents
1976 // finding a mapping of the free APs.
1977 if (oriVsChildren.get(ic).getBuildingBlockType()
1978 != symVsChildren.get(ic).getBuildingBlockType())
1979 {
1980 skip = true;
1981 continue;
1982 }
1983 }
1984 }
1985 if (!skip)
1986 compatibleSymSubGrps.add(symmetricSubGrpVrtx);
1987 }
1988 if (compatibleSymSubGrps.size()==0)
1989 throw new DENOPTIMException("Failed to detect autosymmetry.");
1990
1991 for (List<Vertex> verticesToRemove : compatibleSymSubGrps)
1992 {
1993 // Prepare incoming graph
1994 DGraph graphToAdd = incomingGraph.clone();
1995 graphToAdd.renumberGraphVertices();
1996 List<Vertex> vertexAddedToThis = new ArrayList<Vertex>(
1997 graphToAdd.gVertices);
1998
1999 // Prepare subgraph (it already does not contain caps)
2000 removeCappingGroupsFromChilds(verticesToRemove);
2001
2002 // Prepare AP mapping projecting the one for subGrpVrtxs
2003 LinkedHashMap<AttachmentPoint,AttachmentPoint> localApMap =
2004 new LinkedHashMap<AttachmentPoint,AttachmentPoint>();
2005 for (Map.Entry<AttachmentPoint,AttachmentPoint> e : apMap.entrySet())
2006 {
2007 // WARNING! Assumption that subGrpVrtxs and verticesToRemove
2008 // are sorted accordingly to symmetry, which should be the case.
2009 int vrtPosOnOld = subGrpVrtxs.indexOf(e.getKey().getOwner());
2010 int apPosOnOld = e.getKey().getIndexInOwner();
2011 AttachmentPoint apOnOld = verticesToRemove.get(
2012 vrtPosOnOld).getAP(apPosOnOld);
2013
2014 int vrtPosOnNew = incomingGraph.indexOf(e.getValue().getOwner());
2015 int apPosOnNew = e.getValue().getIndexInOwner();
2016 AttachmentPoint apOnNew = graphToAdd.getVertexAtPosition(
2017 vrtPosOnNew).getAP(apPosOnNew);
2018 localApMap.put(apOnOld,apOnNew);
2019 }
2020
2021 if (!replaceSingleSubGraph(verticesToRemove, graphToAdd, localApMap))
2022 {
2023 return false;
2024 }
2025 addCappingGroups(vertexAddedToThis, fragSpace);
2026 }
2028 return true;
2029 }
2030
2031//------------------------------------------------------------------------------
2032
2045 public List<List<Vertex>> getSymmetricSubGraphs(
2046 List<Vertex> subGrpVrtxs) throws DENOPTIMException
2047 {
2048 if (subGrpVrtxs.stream().anyMatch(v -> v.getBuildingBlockType()==BBType.CAP))
2049 throw new DENOPTIMException("Capping groups must not be part of "
2050 + "symmetric subgraphs");
2051
2052 List<List<Vertex>> symSites = new ArrayList<List<Vertex>>();
2053
2054 if (subGrpVrtxs.size()==1)
2055 {
2056 for (Vertex sv : getSymVerticesForVertex(subGrpVrtxs.get(0)))
2057 {
2058 ArrayList<Vertex> lst = new ArrayList<Vertex>();
2059 lst.add(sv);
2060 symSites.add(lst);
2061 }
2062 if (symSites.size()==0)
2063 {
2064 symSites.add(subGrpVrtxs);
2065 }
2066 return symSites;
2067 }
2068
2069 // Identify the (sole) grand parent.
2070 List<Vertex> thoseWithoutParent = new ArrayList<Vertex>();
2071 for (Vertex v : subGrpVrtxs)
2072 {
2073 if (!subGrpVrtxs.contains(v.getParent()))
2074 thoseWithoutParent.add(v);
2075 }
2076 if (thoseWithoutParent.size()!=1)
2077 {
2078 throw new DENOPTIMException("SubGraph has more than one grand "
2079 + "parent.");
2080 }
2081 Vertex sourceOfSubGraph = thoseWithoutParent.get(0);
2082 int numSymmetricSubGraphs = getSymVerticesForVertex(sourceOfSubGraph).size();
2083 if (numSymmetricSubGraphs==0)
2084 {
2085 symSites.add(subGrpVrtxs);
2086 return symSites;
2087 }
2088
2089 // Identify the ends of the subgraph's spanning tree
2090 List<Vertex> thoseWithoutChildren = new ArrayList<Vertex>();
2091 for (Vertex v : subGrpVrtxs)
2092 {
2093 if (Collections.disjoint(v.getChilddren(),subGrpVrtxs))
2094 thoseWithoutChildren.add(v);
2095 }
2096
2097 // We want to verify that all the ends of the subgraph's spanning tree
2098 // have the same number of symmetric partners. This, while collecting
2099 // all ends that are outside the subgraph and are symmetric to any of
2100 // the ends belonging to the subgraph. The first, in fact, are the ends
2101 // of the symmetric subgraphs.
2102 Set<Vertex> upperLimits = new HashSet<Vertex>();
2103 Set<Vertex> doneBySymmetry = new HashSet<Vertex>();
2104 for (Vertex upperLimit : thoseWithoutChildren)
2105 {
2106 // We need to understand how many symmetric vertices are already
2107 // within the subgraph
2108 int numInSubGraphReplicas = 1;
2109
2110 if (doneBySymmetry.contains(upperLimit))
2111 continue;
2112
2113 // These are symmetric vertices that do belong to the subgraph
2114 Set<Vertex> symmSitesOnBranch = new HashSet<Vertex>(
2115 getSymVerticesForVertex(upperLimit));
2116 symmSitesOnBranch.retainAll(subGrpVrtxs);
2117 if (symmSitesOnBranch.size()>0)
2118 {
2119 numInSubGraphReplicas = symmSitesOnBranch.size();
2120 doneBySymmetry.addAll(symmSitesOnBranch);
2121 }
2122
2123 List<Vertex> lst = getSymVerticesForVertex(upperLimit);
2124 if (lst.size() != numInSubGraphReplicas*numSymmetricSubGraphs)
2125 {
2126 // The subgraph is not symmetrically reproduced.
2127 symSites.add(subGrpVrtxs);
2128 return symSites;
2129 }
2130 upperLimits.addAll(lst);
2131 }
2132
2133 for (Vertex symSources : getSymVerticesForVertex(sourceOfSubGraph))
2134 {
2135 List<Vertex> symSubGraph = new ArrayList<Vertex>();
2136 // The source of the symmetric subgraph is always the first!
2137 symSubGraph.add(symSources);
2138 getChildTreeLimited(symSources, symSubGraph, upperLimits);
2139 //NB: Capping groups are not supposed to be in the list.
2140 symSubGraph.removeIf(v -> v.getBuildingBlockType()==BBType.CAP);
2141 if (symSubGraph.size()!=subGrpVrtxs.size())
2142 {
2143 symSites = new ArrayList<List<Vertex>>();
2144 symSites.add(subGrpVrtxs);
2145 return symSites;
2146 }
2147 symSites.add(symSubGraph);
2148 }
2149
2150 return symSites;
2151 }
2152
2153//------------------------------------------------------------------------------
2154
2183 public boolean replaceSingleSubGraph(List<Vertex> subGrpVrtxs,
2184 DGraph newSubGraph,
2185 LinkedHashMap<AttachmentPoint,AttachmentPoint> apMap)
2186 throws DENOPTIMException
2187 {
2188 if (!gVertices.containsAll(subGrpVrtxs)
2189 || gVertices.contains(newSubGraph.getVertexAtPosition(0)))
2190 {
2191 return false;
2192 }
2193
2194 // Identify vertex that will be added
2195 ArrayList<Vertex> newvertices = new ArrayList<Vertex>();
2196 newvertices.addAll(newSubGraph.getVertexList());
2197
2198 // Collect APs from the vertices that will be removed, and that might
2199 // be reflected onto the jacket template or used to make links to the
2200 // rest of the graph.
2201 List<AttachmentPoint> interfaceApsOnOldBranch =
2202 new ArrayList<AttachmentPoint>();
2203 for (Vertex vToDel : subGrpVrtxs)
2204 {
2205 for (AttachmentPoint ap : vToDel.getAttachmentPoints())
2206 {
2207 if (ap.isAvailable())
2208 {
2209 // being available, this AP might be reflected onto
2210 // jacket template
2211 interfaceApsOnOldBranch.add(ap);
2212 } else {
2213 Vertex user = ap.getLinkedAP().getOwner();
2214 if (!subGrpVrtxs.contains(user))
2215 {
2216 interfaceApsOnOldBranch.add(ap);
2217 }
2218 }
2219 }
2220 }
2221
2222 List<AttachmentPoint> interfaceApsOnNewBranch =
2223 new ArrayList<AttachmentPoint>();
2224 for (Vertex v : newSubGraph.getVertexList())
2225 {
2226 for (AttachmentPoint ap : v.getAttachmentPoints())
2227 {
2228 if (ap.isAvailable())
2229 {
2230 // being available, this AP will have to be reflected onto
2231 // jacket template
2232 interfaceApsOnNewBranch.add(ap);
2233 }
2234 }
2235 }
2236
2237 // Keep track of the links that will be broken and re-created,
2238 // and also of the relation free APs may have with a possible template
2239 // that embeds this graph.
2240 LinkedHashMap<AttachmentPoint,AttachmentPoint>
2241 linksToRecreate = new LinkedHashMap<>();
2242 LinkedHashMap<AttachmentPoint,BondType>
2243 linkTypesToRecreate = new LinkedHashMap<>();
2244 LinkedHashMap<AttachmentPoint,AttachmentPoint>
2245 inToOutAPForTemplate = new LinkedHashMap<>();
2246 List<AttachmentPoint> oldAPToRemoveFromTmpl = new ArrayList<>();
2247 AttachmentPoint trgAPOnNewLink = null;
2248 for (AttachmentPoint oldAP : interfaceApsOnOldBranch)
2249 {
2250 if (oldAP.isAvailable())
2251 {
2252 // NB: if this graph is embedded in a template, free/available
2253 // APs at this level (and from the old link)
2254 // are mapped on the templates' surface
2255 if (templateJacket!=null)
2256 {
2257 if (oldAP.isAvailableThroughout())
2258 {
2259 if (!apMap.containsKey(oldAP))
2260 {
2261 // An AP of the old link is going to be removed from the
2262 // template-jacket's list of APs
2263 oldAPToRemoveFromTmpl.add(oldAP);
2264 } else {
2265 // This AP is not used, not even outside of the template
2266 // but for some reason the apMapping wants to keep it
2267 inToOutAPForTemplate.put(apMap.get(oldAP),oldAP);
2268 }
2269 } else {
2270 if (!apMap.containsKey(oldAP))
2271 {
2272 throw new DENOPTIMException("Cannot replace subgraph "
2273 + "if a used AP has no mapping.");
2274 } else {
2275 // This AP is not used, not even outside of the template
2276 // but for some reason the apMapping wants to keep it
2277 inToOutAPForTemplate.put(apMap.get(oldAP),oldAP);
2278 }
2279 }
2280 }
2281 continue;
2282 }
2283
2284 if (!apMap.containsKey(oldAP))
2285 {
2286 throw new DENOPTIMException("Cannot replace subgraph if a used "
2287 + "AP has no mapping. Missing mapping for AP "
2288 + oldAP.getIndexInOwner() + " in "
2289 + oldAP.getOwner().getVertexId());
2290 }
2291 AttachmentPoint newAP = apMap.get(oldAP);
2292 linksToRecreate.put(newAP, oldAP.getLinkedAP());
2293 linkTypesToRecreate.put(newAP, oldAP.getEdgeUser().getBondType());
2294
2295 // This is were we identify the edge/ap to the parent of the oldLink
2296 if (!oldAP.isSrcInUser())
2297 {
2298 trgAPOnNewLink = newAP;
2299 }
2300 }
2301
2302 // Identify rings that are affected by the change of vertices
2303 Map<Ring,List<Vertex>> ringsOverSubGraph =
2304 new HashMap<Ring,List<Vertex>>();
2305 for (int iA=0; iA<interfaceApsOnOldBranch.size(); iA++)
2306 {
2307 AttachmentPoint apA = interfaceApsOnOldBranch.get(iA);
2308
2309 if (apA.isAvailable())
2310 continue;
2311
2312 for (int iB=(iA+1); iB<interfaceApsOnOldBranch.size(); iB++)
2313 {
2314 AttachmentPoint apB = interfaceApsOnOldBranch.get(iB);
2315
2316 if (apB.isAvailable())
2317 continue;
2318
2319 Vertex vLinkedOnA = apA.getLinkedAP().getOwner();
2320 Vertex vLinkedOnB = apB.getLinkedAP().getOwner();
2322 new Vertex[] {
2323 apA.getOwner(), vLinkedOnA,
2324 apB.getOwner(), vLinkedOnB}))
2325 {
2326 List<Vertex> vPair = new ArrayList<Vertex>();
2327 vPair.add(r.getCloserToHead(vLinkedOnA, vLinkedOnB));
2328 vPair.add(r.getCloserToTail(vLinkedOnA, vLinkedOnB));
2329 ringsOverSubGraph.put(r, vPair);
2330 }
2331 }
2332 }
2333
2334 // remove the vertex-to-delete from the rings where they participate
2335 for (Ring r : ringsOverSubGraph.keySet())
2336 {
2337 List<Vertex> vPair = ringsOverSubGraph.get(r);
2338 PathSubGraph path = new PathSubGraph(vPair.get(0),vPair.get(1),this);
2339 List<Vertex> verticesInPath = path.getVertecesPath();
2340 for (int i=1; i<(verticesInPath.size()-1); i++)
2341 {
2342 r.removeVertex(verticesInPath.get(i));
2343 }
2344 }
2345
2346 // remove edges with old vertex
2347 for (AttachmentPoint oldAP : interfaceApsOnOldBranch)
2348 {
2349 if (!oldAP.isAvailable())
2350 removeEdge(oldAP.getEdgeUser());
2351 }
2352
2353 // remove the vertex from the graph
2354 for (Vertex vToDel : subGrpVrtxs)
2355 {
2356 // WARNING! This removes rings involving these vertices.
2357 removeVertex(vToDel);
2358 }
2359
2360 // finally introduce the new vertices from incoming graph into this graph
2361 for (Vertex incomingVrtx : newSubGraph.getVertexList())
2362 {
2363 addVertex(incomingVrtx);
2364 }
2365
2366 // import edges from incoming graph
2367 for (Edge incomingEdge : newSubGraph.getEdgeList())
2368 {
2369 addEdge(incomingEdge);
2370 }
2371
2372 // import rings from incoming graph
2373 for (Ring incomingRing : newSubGraph.getRings())
2374 {
2375 addRing(incomingRing);
2376 }
2377
2378 // import symmetric sets from incoming graph? No, this method doesn't do
2379 // it because we want to use it in situations where we have to perform
2380 // multiple replaceSubGraph operations and, afterwards, use the
2381 // symmetric labels to create symmetric sets that might span across
2382 // more than one of the subgraphs that were added.
2383
2384 // We keep track of the APs on the new link that have been dealt with
2385 List<AttachmentPoint> doneApsOnNew =
2386 new ArrayList<AttachmentPoint>();
2387
2388 // Connect the incoming subgraph to the rest of the graph
2389 if (trgAPOnNewLink != null)
2390 {
2391 // the incoming graph has a parent vertex, and the edge should be
2392 // directed accordingly
2393 Edge edge = new Edge(
2394 linksToRecreate.get(trgAPOnNewLink),
2395 trgAPOnNewLink,
2396 linkTypesToRecreate.get(trgAPOnNewLink));
2397 addEdge(edge);
2398 doneApsOnNew.add(trgAPOnNewLink);
2399 } else {
2400 // newLink does NOT have a parent vertex, so all the
2401 // edges see newLink as target vertex. Such links are dealt with
2402 // in the loop below. So, there is nothing special to do, here.
2403 }
2404 for (AttachmentPoint apOnNew : linksToRecreate.keySet())
2405 {
2406 if (apOnNew == trgAPOnNewLink)
2407 {
2408 continue; //done just before this loop
2409 }
2410 AttachmentPoint trgOnChild = linksToRecreate.get(apOnNew);
2411 Edge edge = new Edge(apOnNew,trgOnChild,
2412 linkTypesToRecreate.get(apOnNew));
2413 addEdge(edge);
2414 doneApsOnNew.add(apOnNew);
2415 }
2416
2417 // redefine rings that spanned over the removed subgraph
2418 for (Ring r : ringsOverSubGraph.keySet())
2419 {
2420 List<Vertex> vPair = ringsOverSubGraph.get(r);
2421 PathSubGraph path = new PathSubGraph(vPair.get(0),vPair.get(1),this);
2422 int initialInsertPoint = r.getPositionOf(vPair.get(0));
2423 List<Vertex> verticesInPath = path.getVertecesPath();
2424 for (int i=1; i<(verticesInPath.size()-1); i++)
2425 {
2426 r.insertVertex(initialInsertPoint+i, verticesInPath.get(i));
2427 }
2428 }
2429
2430 // update the mapping of this vertices' APs in the jacket template
2431 if (templateJacket != null)
2432 {
2434 for (AttachmentPoint apOnNew : inToOutAPForTemplate.keySet())
2435 {
2437 inToOutAPForTemplate.get(apOnNew),apOnNew);
2438 doneApsOnNew.add(apOnNew);
2439 }
2440
2441 // Project all remaining APs of new branch on the surface of template
2442 for (AttachmentPoint apOnNew : interfaceApsOnNewBranch)
2443 {
2444 if (!doneApsOnNew.contains(apOnNew))
2445 {
2447 }
2448 }
2449
2450 // Remove all APs that existed only in the old branch
2451 for (AttachmentPoint apOnOld : oldAPToRemoveFromTmpl)
2452 {
2454 }
2455 }
2456
2457 jGraph = null;
2458 jGraphKernel = null;
2459
2460 for (Vertex vOld : subGrpVrtxs)
2461 if (this.containsVertex(vOld))
2462 return false;
2463 for (Vertex vNew : newvertices)
2464 if (!this.containsVertex(vNew))
2465 return false;
2466 return true;
2467 }
2468
2469//------------------------------------------------------------------------------
2470
2487 public boolean replaceVertex(Vertex vertex, int bbId, BBType bbt,
2488 LinkedHashMap<Integer, Integer> apIdMap, FragmentSpace fragSpace)
2489 throws DENOPTIMException
2490 {
2491 return replaceVertex(vertex, bbId, bbt, apIdMap, true, fragSpace);
2492 }
2493
2494//------------------------------------------------------------------------------
2495
2511 public boolean replaceVertex(Vertex vertex, int bbId, BBType bbt,
2512 LinkedHashMap<Integer, Integer> apIdMap, boolean symmetry,
2513 FragmentSpace fragSpace)
2514 throws DENOPTIMException
2515 {
2516 if (!gVertices.contains(vertex))
2517 {
2518 return false;
2519 }
2520
2521 List<Vertex> symSites = new ArrayList<Vertex>();
2522 if (symmetry)
2523 {
2524 symSites = getSymVerticesForVertex(vertex);
2525 }
2526 if (symSites.size() == 0)
2527 {
2528 symSites.add(vertex);
2529 }
2530
2533 GraphUtils.getUniqueVertexIndex(), bbId, bbt, fragSpace);
2534 DGraph incomingGraph = new DGraph();
2535 incomingGraph.addVertex(newLink);
2536 incomingGraph.reassignSymmetricLabels();
2537
2538 for (Vertex oldLink : symSites)
2539 {
2540 DGraph graphAdded = incomingGraph.clone();
2542 oldLink.getUnfilteredMutationTypes());
2543 graphAdded.renumberGraphVertices();
2544
2545 ArrayList<Vertex> oldVertex = new ArrayList<Vertex>();
2546 oldVertex.add(oldLink);
2547 LinkedHashMap<AttachmentPoint,AttachmentPoint> apMap =
2548 new LinkedHashMap<AttachmentPoint,AttachmentPoint>();
2549 for (Map.Entry<Integer,Integer> e : apIdMap.entrySet())
2550 {
2551 apMap.put(oldLink.getAP(e.getKey()),
2552 graphAdded.getVertexAtPosition(0).getAP(e.getValue()));
2553 }
2554
2555 if (!replaceSingleSubGraph(oldVertex, graphAdded, apMap))
2556 {
2557 return false;
2558 }
2559 }
2561 return true;
2562 }
2563
2564//------------------------------------------------------------------------------
2565
2587 //NB: LinkedHashMap is used to retain reproducibility between runs.
2588
2589 public boolean insertVertex(Edge edge, int bbId, BBType bbt,
2590 LinkedHashMap<AttachmentPoint,Integer> apMap,
2591 FragmentSpace fragSpace)
2592 throws DENOPTIMException
2593 {
2594 if (!gEdges.contains(edge))
2595 {
2596 return false;
2597 }
2598
2599 List<Edge> symSites = new ArrayList<Edge> ();
2600 List<LinkedHashMap<AttachmentPoint,Integer>> symApMaps =
2601 new ArrayList<LinkedHashMap<AttachmentPoint,Integer>>();
2602 List<Vertex> symTrgvertices = getSymVerticesForVertex(
2603 edge.getTrgAP().getOwner());
2604 if (symTrgvertices.size() == 0)
2605 {
2606 symSites.add(edge);
2607 symApMaps.add(apMap);
2608 } else {
2609 for (Vertex trgVrtx : symTrgvertices)
2610 {
2611 Edge symEdge = trgVrtx.getEdgeToParent();
2612 symSites.add(symEdge);
2613
2614 LinkedHashMap<AttachmentPoint,Integer> locApMap = new
2615 LinkedHashMap<AttachmentPoint,Integer>();
2616 locApMap.put(symEdge.getSrcAP(), apMap.get(edge.getSrcAP()));
2617 locApMap.put(symEdge.getTrgAP(), apMap.get(edge.getTrgAP()));
2618 symApMaps.add(locApMap);
2619 }
2620 }
2621
2623 for (int i=0; i<symSites.size(); i++)
2624 {
2625 Edge symEdge = symSites.get(i);
2626 LinkedHashMap<AttachmentPoint,Integer> locApMap = symApMaps.get(i);
2627
2630 GraphUtils.getUniqueVertexIndex(), bbId, bbt, fragSpace);
2631 newSS.add(newLink);
2632 LinkedHashMap<AttachmentPoint,AttachmentPoint> apToApMap =
2633 new LinkedHashMap<AttachmentPoint,AttachmentPoint>();
2634 for (AttachmentPoint apOnGraph : locApMap.keySet())
2635 {
2636 apToApMap.put(apOnGraph, newLink.getAP(locApMap.get(apOnGraph)));
2637 }
2638 if (!insertSingleVertex(symEdge, newLink, apToApMap))
2639 {
2640 return false;
2641 }
2642 }
2643 if (newSS.size()>1)
2644 {
2646 }
2647 return true;
2648 }
2649
2650//------------------------------------------------------------------------------
2651
2669 public boolean insertSingleVertex(Edge edge, Vertex newLink,
2670 LinkedHashMap<AttachmentPoint,AttachmentPoint> apMap)
2671 throws DENOPTIMException
2672 {
2673 //TODO: for reproducibility the AP mapping should become an optional
2674 // parameter: if given we try to use it, if not given we GraphLinkFinder
2675 // will try to find a suitable mapping.
2676
2677 if (!gEdges.contains(edge) || gVertices.contains(newLink))
2678 {
2679 return false;
2680 }
2681
2682 // First keep track of the links that will be broken and re-created,
2683 // and also of the relation free APs may have with a possible template
2684 // that embeds this graph.
2685 AttachmentPoint orisEdgeSrc = edge.getSrcAP();
2686 AttachmentPoint orisEdgeTrg = edge.getTrgAP();
2687 Vertex srcVrtx = orisEdgeSrc.getOwner();
2688 Vertex trgVrtx = orisEdgeTrg.getOwner();
2689
2690 removeEdge(edge);
2691
2692 // Introduce the new vertex in the graph
2693 addVertex(newLink);
2694
2695 // Connect the new vertex to the graph
2696 Edge eSrcToLink = new Edge(orisEdgeSrc,
2697 apMap.get(orisEdgeSrc), edge.getBondType());
2698 addEdge(eSrcToLink);
2699 Edge eLinkToTrg = new Edge(apMap.get(orisEdgeTrg),
2700 orisEdgeTrg, edge.getBondType());
2701 addEdge(eLinkToTrg);
2702
2703 // update any affected ring
2704 if (isVertexInRing(srcVrtx) && isVertexInRing(trgVrtx))
2705 {
2706 ArrayList<Ring> rToEdit = new ArrayList<Ring>();
2707 rToEdit.addAll(getRingsInvolvingVertex(srcVrtx));
2708 rToEdit.retainAll(getRingsInvolvingVertex(trgVrtx));
2709 for (Ring r : rToEdit)
2710 {
2711 r.insertVertex(newLink,srcVrtx,trgVrtx);
2712 }
2713 }
2714
2715 // NB: if this graph is embedded in a template, new free/available
2716 // APs introduced with the new link need to be mapped on the surface of
2717 // the template
2718 if (templateJacket != null)
2719 {
2720 for (AttachmentPoint ap : newLink.getAttachmentPoints())
2721 {
2722 if (ap.isAvailable())
2723 {
2725 }
2726 }
2727 }
2728
2729 jGraph = null;
2730 jGraphKernel = null;
2731
2732 return !gEdges.contains(edge) && this.containsVertex(newLink);
2733 }
2734
2735//------------------------------------------------------------------------------
2736
2744 {
2745 return ((pos >= gVertices.size()) || pos < 0) ? null :
2746 gVertices.get(pos);
2747 }
2748
2749//------------------------------------------------------------------------------
2750
2760 {
2761 if (gVertices.contains(v))
2762 return true;
2763
2764 for (Vertex vrt : gVertices)
2765 {
2766 if (vrt instanceof Template)
2767 {
2768 Template t = (Template) vrt;
2770 return true;
2771 }
2772 }
2773 return false;
2774 }
2775
2776
2777//------------------------------------------------------------------------------
2778
2786 public boolean containsVertex(Vertex v)
2787 {
2788 return gVertices.contains(v);
2789 }
2790
2791//------------------------------------------------------------------------------
2792
2798 public int indexOf(Vertex v)
2799 {
2800 return gVertices.indexOf(v);
2801 }
2802
2803//------------------------------------------------------------------------------
2804
2811 public Vertex getVertexWithId(long vid)
2812 {
2813 Vertex v = null;
2814 int idx = indexOfVertexWithID(vid);
2815 if (idx != -1)
2816 v = gVertices.get(idx);
2817 return v;
2818 }
2819
2820//------------------------------------------------------------------------------
2821
2827 public int indexOfVertexWithID(long vid)
2828 {
2829 int idx = -1;
2830 for (int i=0; i<gVertices.size(); i++)
2831 {
2832 Vertex v = gVertices.get(i);
2833 if (v.getVertexId() == vid)
2834 {
2835 idx = i;
2836 break;
2837 }
2838 }
2839 return idx;
2840 }
2841
2842//------------------------------------------------------------------------------
2843
2849 public void removeEdge(Edge edge)
2850 {
2851 if (gEdges.contains(edge))
2852 {
2853 AttachmentPoint srcAP = edge.getSrcAP();
2854 AttachmentPoint trgAP = edge.getTrgAP();
2855 srcAP.setUser(null);
2856 trgAP.setUser(null);
2857
2858 gEdges.remove(edge);
2859 }
2860 jGraph = null;
2861 jGraphKernel = null;
2862 }
2863
2864//------------------------------------------------------------------------------
2865
2866 public void removeRing(Ring ring)
2867 {
2868 if (gRings.contains(ring))
2869 {
2870 gRings.remove(ring);
2871 }
2872 jGraph = null;
2873 jGraphKernel = null;
2874 }
2875
2876//------------------------------------------------------------------------------
2877
2878 public Edge getEdgeAtPosition(int pos)
2879 {
2880 if ((pos >= gEdges.size()) || pos < 0)
2881 return null;
2882 return gEdges.get(pos);
2883 }
2884
2885//------------------------------------------------------------------------------
2886
2887 public int getEdgeCount()
2888 {
2889 return gEdges.size();
2890 }
2891
2892//------------------------------------------------------------------------------
2893
2894 public int getRingCount()
2895 {
2896 return gRings.size();
2897 }
2898
2899//------------------------------------------------------------------------------
2900
2901 public int getVertexCount()
2902 {
2903 return gVertices.size();
2904 }
2905
2906//------------------------------------------------------------------------------
2907
2908 @Override
2909 public String toString()
2910 {
2911 StringBuilder sb = new StringBuilder(512);
2912
2913 sb.append(graphId).append(" ");
2914
2915 for (int i=0; i<gVertices.size(); i++)
2916 {
2917 sb.append(gVertices.get(i).toString()).append(",");
2918 }
2919
2920 sb.append(" ");
2921
2922 for (int i=0; i<gEdges.size(); i++)
2923 {
2924 sb.append(gEdges.get(i).toString()).append(",");
2925 }
2926
2927 sb.append(" ");
2928
2929 for (int i=0; i<gRings.size(); i++)
2930 {
2931 sb.append(gRings.get(i).toString()).append(" ");
2932 }
2933
2934 for (int i=0; i<symVertices.size(); i++)
2935 {
2936 sb.append(symVertices.get(i).toString()).append(" ");
2937 }
2938
2939 return sb.toString();
2940 }
2941
2942//------------------------------------------------------------------------------
2943
2953 @Deprecated
2954 public int getBondingAPIndex(Vertex srcVert, int dapidx,
2955 Vertex dstVert)
2956 {
2957 int n = getEdgeCount();
2958 for (int i = 0; i < n; i++)
2959 {
2960 Edge edge = getEdgeList().get(i);
2961
2962 // get the vertex ids
2963 long v1_id = edge.getSrcVertex();
2964 long v2_id = edge.getTrgVertex();
2965
2966 int dap_idx_v1 = edge.getSrcAPID();
2967
2968 if (srcVert.getVertexId() == v1_id && v2_id == dstVert.getVertexId()
2969 && dap_idx_v1 == dapidx)
2970 {
2971 return edge.getTrgAPID();
2972 }
2973 }
2974
2975 return -1;
2976 }
2977
2978//------------------------------------------------------------------------------
2979
2986 public ArrayList<Vertex> getChildVertices(Vertex vertex)
2987 {
2988 return vertex.getChilddren();
2989 }
2990
2991//------------------------------------------------------------------------------
2992
3000 public void getChildrenTree(Vertex vertex, List<Vertex> children)
3001 {
3002 List<Vertex> lst = getChildVertices(vertex);
3003 if (lst.isEmpty())
3004 {
3005 return;
3006 }
3007 for (Vertex child : lst)
3008 {
3009 if (!children.contains(child))
3010 {
3011 children.add(child);
3012 getChildrenTree(child, children);
3013 }
3014 }
3015 }
3016
3017//------------------------------------------------------------------------------
3018
3033 public void getChildrenTree(Vertex vertex, List<Vertex> children,
3034 boolean markBranches)
3035 {
3036 if (!markBranches)
3037 {
3038 getChildrenTree(vertex, children);
3039 return;
3040 }
3041
3042 AtomicInteger branchIdGenerator = new AtomicInteger(0);
3043 List<Integer> thisBranchId = new ArrayList<Integer>();
3044 thisBranchId.add(branchIdGenerator.getAndIncrement());
3045
3046 vertex.setProperty(DENOPTIMConstants.GRAPHBRANCHID, thisBranchId);
3047
3048 List<Vertex> lst = getChildVertices(vertex);
3049 if (lst.isEmpty())
3050 {
3051 return;
3052 }
3053 for (Vertex child : lst)
3054 {
3055 if (!children.contains(child))
3056 {
3057 children.add(child);
3058 if (lst.size()==1)
3059 {
3060 child.setProperty(DENOPTIMConstants.GRAPHBRANCHID,
3061 thisBranchId);
3062 getChildrenTree(child, children, branchIdGenerator,
3063 thisBranchId);
3064 } else {
3065 List<Integer> newBranchId = new ArrayList<>(thisBranchId);
3066 newBranchId.add(branchIdGenerator.getAndIncrement());
3067 child.setProperty(DENOPTIMConstants.GRAPHBRANCHID,
3068 newBranchId);
3069 getChildrenTree(child, children, branchIdGenerator,
3070 newBranchId);
3071 }
3072 }
3073 }
3074 }
3075
3076//------------------------------------------------------------------------------
3077
3090 public void getChildrenTree(Vertex vertex, List<Vertex> children,
3091 AtomicInteger branchIdGenerator, List<Integer> prevBranchId)
3092 {
3093 List<Vertex> lst = getChildVertices(vertex);
3094 if (lst.isEmpty())
3095 {
3096 return;
3097 }
3098 for (Vertex child : lst)
3099 {
3100 if (!children.contains(child))
3101 {
3102 children.add(child);
3103 if (lst.size()==1)
3104 {
3105 child.setProperty(DENOPTIMConstants.GRAPHBRANCHID,
3106 prevBranchId);
3107 getChildrenTree(child, children, branchIdGenerator,
3108 prevBranchId);
3109 } else {
3110 List<Integer> newBranchId = new ArrayList<>(prevBranchId);
3111 newBranchId.add(branchIdGenerator.getAndIncrement());
3112 child.setProperty(DENOPTIMConstants.GRAPHBRANCHID,
3113 newBranchId);
3114 getChildrenTree(child, children, branchIdGenerator,
3115 newBranchId);
3116 }
3117 }
3118 }
3119 }
3120
3121//------------------------------------------------------------------------------
3122
3135 public void getChildrenTree(Vertex vertex,
3136 List<Vertex> children, int numLayers, boolean stopBeforeRCVs)
3137 {
3138 if (numLayers==0)
3139 {
3140 return;
3141 }
3142 List<Vertex> lst = getChildVertices(vertex);
3143 if (lst.isEmpty())
3144 {
3145 return;
3146 }
3147 for (Vertex child : lst)
3148 {
3149 if (children.contains(child))
3150 continue;
3151
3152 if (stopBeforeRCVs && child.isRCV())
3153 continue;
3154
3155 children.add(child);
3156 getChildrenTree(child, children, numLayers-1, stopBeforeRCVs);
3157 }
3158 }
3159
3160//------------------------------------------------------------------------------
3161
3170 public List<Integer> getBranchIdOfVertexAtPosition(int i)
3171 {
3173 }
3174
3175//------------------------------------------------------------------------------
3176
3186 @SuppressWarnings("unchecked")
3187 public List<Integer> getBranchIdOfVertex(Vertex v)
3188 {
3189 if (!gVertices.contains(v))
3190 return null;
3191
3192 return (List<Integer>) v.getProperty(DENOPTIMConstants.GRAPHBRANCHID);
3193 }
3194
3195//------------------------------------------------------------------------------
3196
3208 {
3209 List<Integer> lst = getBranchIdOfVertex(v);
3210 String s = "";
3211 for (Integer i : lst)
3212 s = s + i + "_";
3213 return s;
3214 }
3215
3216//------------------------------------------------------------------------------
3217
3229 public boolean directedPathExists(Vertex src, Vertex trg)
3230 {
3231 List<Integer> bIdSrc = getBranchIdOfVertex(src);
3232 List<Integer> bIdTrg = getBranchIdOfVertex(trg);
3233 if (bIdSrc==null || bIdTrg==null)
3234 return false;
3235 if (bIdSrc.size()>bIdTrg.size())
3236 return false;
3237 int sharedSubBranches = 0;
3238 for (int i=0; i<bIdSrc.size(); i++)
3239 {
3240 if (bIdSrc.get(i)==bIdTrg.get(i))
3241 sharedSubBranches++;
3242 }
3243 return sharedSubBranches==bIdSrc.size();
3244 }
3245
3246//------------------------------------------------------------------------------
3247
3257 public void getChildTreeLimited(Vertex vertex,
3258 List<Vertex> children, boolean stopBeforeRCVs)
3259 {
3260 List<Vertex> lst = getChildVertices(vertex);
3261 if (lst.isEmpty())
3262 {
3263 return;
3264 }
3265 for (Vertex child : lst)
3266 {
3267 if (children.contains(child))
3268 continue;
3269
3270 if (stopBeforeRCVs && child.isRCV())
3271 continue;
3272
3273 children.add(child);
3274 getChildTreeLimited(child, children, stopBeforeRCVs);
3275 }
3276 }
3277
3278//------------------------------------------------------------------------------
3279
3289 public void getChildTreeLimited(Vertex vertex,
3290 List<Vertex> children, Set<Vertex> limits)
3291 {
3292 List<Vertex> lst = getChildVertices(vertex);
3293 if (lst.isEmpty())
3294 {
3295 return;
3296 }
3297 for (Vertex child : lst)
3298 {
3299 if (!children.contains(child))
3300 {
3301 children.add(child);
3302 if (!limits.contains(child))
3303 getChildTreeLimited(child, children, limits);
3304 }
3305 }
3306 }
3307
3308//------------------------------------------------------------------------------
3309
3321 public void getChildTreeLimited(Vertex vertex,
3322 List<Vertex> children, List<Vertex> limitsInClone,
3323 boolean stopBeforeRCVs)
3324 {
3325 List<Vertex> lst = getChildVertices(vertex);
3326 if (lst.isEmpty())
3327 {
3328 return;
3329 }
3330 for (Vertex child : lst)
3331 {
3332 if (children.contains(child))
3333 continue;
3334
3335 if (stopBeforeRCVs && child.isRCV())
3336 continue;
3337
3338 children.add(child);
3339 if (!limitsInClone.contains(child))
3340 getChildTreeLimited(child, children, limitsInClone, stopBeforeRCVs);
3341 }
3342 }
3343
3344//------------------------------------------------------------------------------
3345
3352 public Vertex getDeepestAmongThese(List<Vertex> list)
3353 {
3354 Vertex deepest = null;
3355 int shortest = Integer.MAX_VALUE;
3356 for (Vertex vertex : list)
3357 {
3358 List<Vertex> parentTree = new ArrayList<Vertex>();
3359 getParentTree(vertex, parentTree);
3360 if (parentTree.size()<shortest)
3361 {
3362 shortest = parentTree.size();
3363 deepest = vertex;
3364 }
3365 }
3366 return deepest;
3367 }
3368
3369//------------------------------------------------------------------------------
3370
3378 public void getParentTree(Vertex vertex,
3379 List<Vertex> parentTree)
3380 {
3381 Vertex parent = getParent(vertex);
3382 if (parent == null)
3383 {
3384 return;
3385 }
3386 if (parentTree.contains(parent))
3387 {
3388 // Cyclic graphs are not allowed!
3389 throw new IllegalArgumentException();
3390 }
3391 parentTree.add(parent);
3392 getParentTree(parent, parentTree);
3393 }
3394
3395//------------------------------------------------------------------------------
3396
3398 {
3399 Edge edge = v.getEdgeToParent();
3400 if (edge != null)
3401 {
3402 return edge.getSrcAP().getOwner();
3403 }
3404 return null;
3405 }
3406
3407//------------------------------------------------------------------------------
3408
3414 @Override
3415 public DGraph clone()
3416 {
3417 // When cloning, the VertexID remains the same so we'll have two
3418 // deep-copies of the same vertex having the same VertexID
3419 ArrayList<Vertex> cListVrtx = new ArrayList<>();
3420 Map<Long, Vertex> vidsInClone = new HashMap<Long, Vertex>();
3421 for (Vertex vOrig : gVertices)
3422 {
3423 Vertex vClone = vOrig.clone();
3424 cListVrtx.add(vClone);
3425 vidsInClone.put(vClone.getVertexId(), vClone);
3426 }
3427
3428 ArrayList<Edge> cListEdges = new ArrayList<>();
3429 for (Edge e : gEdges)
3430 {
3431 long srcVrtxId = e.getSrcVertex();
3432 int srcApId = this.getVertexWithId(srcVrtxId).getIndexOfAP(
3433 e.getSrcAP());
3434
3435 long trgVrtxId = e.getTrgVertex();
3436 int trgApId = this.getVertexWithId(trgVrtxId).getIndexOfAP(
3437 e.getTrgAP());
3438
3439 AttachmentPoint srcAPClone = vidsInClone.get(
3440 srcVrtxId).getAP(srcApId);
3441 AttachmentPoint trgAPClone = vidsInClone.get(
3442 trgVrtxId).getAP(trgApId);
3443
3444 cListEdges.add(new Edge(srcAPClone, trgAPClone,
3445 e.getBondType()));
3446 }
3447
3448 DGraph clone = new DGraph(cListVrtx, cListEdges);
3449
3450 // Copy the list but using the references to the cloned vertices
3451 ArrayList<Ring> cListRings = new ArrayList<>();
3452 for (Ring ring : gRings)
3453 {
3454 Ring cRing = new Ring();
3455 for (int iv=0; iv<ring.getSize(); iv++)
3456 {
3457 Vertex origVrtx = ring.getVertexAtPosition(iv);
3458 cRing.addVertex(
3459 clone.getVertexWithId(origVrtx.getVertexId()));
3460 }
3461 cRing.setBondType(ring.getBondType());
3462 cListRings.add(cRing);
3463 }
3464 clone.setRings(cListRings);
3465
3466 // The chainLinks are made of primitives, so it's just fine
3467 ArrayList<ClosableChain> cListClosableChains =
3468 new ArrayList<>();
3469 for (ClosableChain cc : closableChains)
3470 {
3471 cListClosableChains.add(cc.clone());
3472 }
3473 clone.setCandidateClosableChains(cListClosableChains);
3474
3475
3476 List<SymmetricVertexes> cSymVertices = new ArrayList<>();
3478 {
3479 SymmetricVertexes clonedSS = new SymmetricVertexes();
3480 for (Vertex origVrt : ss)
3481 {
3482 clonedSS.add(clone.gVertices.get(gVertices.indexOf(origVrt)));
3483 }
3484 cSymVertices.add(clonedSS);
3485 }
3486 clone.setSymmetricVertexSets(cSymVertices);
3487
3490
3491 return clone;
3492 }
3493
3494//------------------------------------------------------------------------------
3495
3503 {
3504 Vertex v = getVertexWithId(l);
3505 if (v == null)
3506 {
3507 return null;
3508 }
3509 return v.getEdgeToParent();
3510 }
3511
3512//------------------------------------------------------------------------------
3513
3520 public ArrayList<Integer> getIndexOfEdgesWithChild(int vid)
3521 {
3522 ArrayList<Integer> lstEdges = new ArrayList<>();
3523 for (int j=0; j<getEdgeCount(); j++)
3524 {
3525 Edge edge = getEdgeAtPosition(j);
3526
3527 if (edge.getSrcVertex() == vid)
3528 {
3529 lstEdges.add(j);
3530 }
3531 }
3532 return lstEdges;
3533 }
3534
3535//------------------------------------------------------------------------------
3536
3543 public ArrayList<Edge> getEdgesWithChild(int vid)
3544 {
3545 ArrayList<Edge> lstEdges = new ArrayList<>();
3546 for (int j=0; j<getEdgeCount(); j++)
3547 {
3548 Edge edge = getEdgeAtPosition(j);
3549
3550 if (edge.getSrcVertex() == vid)
3551 {
3552 lstEdges.add(edge);
3553 }
3554 }
3555 return lstEdges;
3556 }
3557
3558//------------------------------------------------------------------------------
3559
3563 public long getMaxVertexId()
3564 {
3565 long mval = Long.MIN_VALUE;
3566 for (Vertex v : gVertices) {
3567 mval = Math.max(mval, v.getVertexId());
3568 }
3569 return mval;
3570 }
3571
3572//------------------------------------------------------------------------------
3573
3578 public boolean containsVertexID(long l)
3579 {
3580 boolean result = false;
3581 for (Vertex v : gVertices)
3582 {
3583 if (l == v.getVertexId())
3584 {
3585 result = true;
3586 break;
3587 }
3588 }
3589 return result;
3590 }
3591
3592//------------------------------------------------------------------------------
3593
3597 public void cleanup()
3598 {
3599 if (gVertices != null)
3600 {
3601 gVertices.clear();
3602 }
3603 if (gEdges != null)
3604 {
3605 gEdges.clear();
3606 }
3607 if (gRings != null)
3608 {
3609 gRings.clear();
3610 }
3611 if (symVertices != null)
3612 {
3613 symVertices.clear();
3614 }
3615 if (closableChains != null)
3616 {
3617 closableChains.clear();
3618 }
3619 jGraph = null;
3620 jGraphKernel = null;
3621 }
3622
3623//------------------------------------------------------------------------------
3624
3625 /*
3626 * NB: this javadoc string is reproduced in the user manual HTML file.
3627 * In case of modifications, please keep the two sources compatible by
3628 * reproducing the modification on both sites.
3629 */
3630
3682 public boolean isIsomorphicTo(DGraph other) {
3683 if (this.jGraph == null)
3684 {
3685 this.jGraph = GraphConversionTool.getJGraphFromGraph(this);
3686 }
3687 if (other.jGraph == null)
3688 {
3689 other.jGraph = GraphConversionTool.getJGraphFromGraph(other);
3690 }
3691
3692 // Simple but slow because it ignores symmetry
3693 /*
3694 Comparator<DENOPTIMVertex> vComp = (v1, v2) -> {
3695 // Vertex.sameAs returns boolean, so we need to produce
3696 // an int to allow comparison.
3697 StringBuilder sb = new StringBuilder();
3698 boolean areSame = v1.sameAs(v2, sb);
3699
3700 if (areSame) {
3701 return 0;
3702 } else {
3703 return Integer.compare(v1.getBuildingBlockId(),
3704 v2.getBuildingBlockId());
3705 }
3706 };
3707 */
3708
3709 Comparator<Vertex> vComp = new Comparator<Vertex>() {
3710
3711 Map<Vertex,Set<Vertex>> symmetryShortCuts =
3712 new HashMap<Vertex,Set<Vertex>>();
3713
3714 @Override
3715 public int compare(Vertex v1, Vertex v2) {
3716
3717 // exploit symmetric relations between vertices
3718 if (symmetryShortCuts.containsKey(v1)
3719 && symmetryShortCuts.get(v1).contains(v2))
3720 {
3721 return 0;
3722 }
3723
3724 // Vertex.sameAs returns boolean, so we need to produce
3725 // an int to allow comparison.
3726 StringBuilder sb = new StringBuilder();
3727 if (v1.sameAs(v2, sb))
3728 {
3729 Set<Vertex> symToV2 = new HashSet<Vertex>();
3730 symToV2.addAll(v2.getGraphOwner().getSymSetForVertex(v2));
3731 Set<Vertex> symToV1 = new HashSet<Vertex>();
3732 symToV1.addAll(v1.getGraphOwner().getSymSetForVertex(v1));
3733 for (Vertex v1s : symToV1)
3734 {
3735 if (symmetryShortCuts.containsKey(v1s))
3736 {
3737 symmetryShortCuts.get(v1s).addAll(symToV2);
3738 } else {
3739 symmetryShortCuts.put(v1s,symToV2);
3740 }
3741 }
3742 return 0;
3743 } else {
3744 // We must return something different than zero
3745 if (Integer.compare(v1.getBuildingBlockId(),
3746 v2.getBuildingBlockId())!=0)
3747 return Integer.compare(v1.getBuildingBlockId(),
3748 v2.getBuildingBlockId());
3749 if (Integer.compare(v1.hashCode(),
3750 v2.hashCode())!=0)
3751 return Integer.compare(v1.hashCode(),
3752 v2.hashCode());
3753 return Integer.compare(v1.getBuildingBlockId()+v1.hashCode(),
3754 v2.getBuildingBlockId()+v2.hashCode());
3755 }
3756 }
3757 };
3758
3759 Comparator<UndirectedEdge> eComp =
3761
3762 // NB: these two were created to evaluate the simplest and fasted
3763 // possible scenario. It turns out that for a graph like the following
3764 // one the time spent to do automorphism (i.e., isomorphism with itself)
3765 // can only be improved by 20% when using these two simplest and
3766 // useless (i.e., inaccurate) comparators. Instead the above, and useful
3767 // comparators do introduce some computational demands, but are less
3768 // detrimental than having to address a wide multitude of possible
3769 // mappings: this seems to be the liming factor, rather than the
3770 // implementation of the comparators.
3771
3772 // Example of challenging, yet simple graph:
3773 //29 853_1_0_-1,855_2_1_0,857_1_1_0,858_1_1_0,859_1_1_0,861_2_1_1,862_2_1_1,863_2_1_1,864_2_1_1,865_2_1_1,866_2_1_1,867_2_1_1,868_2_1_1,869_2_1_1, 853_1_855_0_1_c:0_ATneutral:0,853_0_857_1_1_c:0_c:0,853_2_858_1_1_c:0_c:0,853_3_859_1_1_c:0_c:0,857_0_861_0_1_c:0_ATneutral:0,857_2_862_0_1_c:0_ATneutral:0,857_3_863_0_1_c:0_ATneutral:0,858_0_864_0_1_c:0_ATneutral:0,858_2_865_0_1_c:0_ATneutral:0,858_3_866_0_1_c:0_ATneutral:0,859_0_867_0_1_c:0_ATneutral:0,859_2_868_0_1_c:0_ATneutral:0,859_3_869_0_1_c:0_ATneutral:0, SymmetricSet [symIds=[857, 858, 859]] SymmetricSet [symIds=[861, 862, 863, 864, 865, 866, 867, 868, 869]]
3774
3775 /*
3776 Comparator<UndirectedEdgeRelation> eCompDummy = (e1, e2) -> {
3777 return Integer.compare(e1.hashCode(),e2.hashCode());
3778 };
3779 Comparator<DENOPTIMVertex> vCompDummy = (v1, v2) -> {
3780 return Integer.compare(v1.getBuildingBlockId(),
3781 v2.getBuildingBlockId());
3782 };
3783 */
3784
3785 VF2GraphIsomorphismInspector<Vertex, UndirectedEdge> vf2 =
3786 new VF2GraphIsomorphismInspector<>(this.jGraph, other.jGraph,
3787 vComp, eComp);
3788
3789 return vf2.isomorphismExists();
3790 }
3791
3792//------------------------------------------------------------------------------
3793
3809 public boolean isIsostructuralTo(DGraph other) {
3810 if (this.jGraphKernel == null)
3811 {
3812 this.jGraphKernel = GraphConversionTool.getJGraphKernelFromGraph(this);
3813 }
3814 if (other.jGraphKernel == null)
3815 {
3816 other.jGraphKernel = GraphConversionTool.getJGraphKernelFromGraph(other);
3817 }
3818
3819 Comparator<Node> vComp = new Comparator<Node>() {
3820
3821 Map<Node,Set<Node>> symmetryShortCuts =
3822 new HashMap<Node,Set<Node>>();
3823
3824 @Override
3825 public int compare(Node v1, Node v2) {
3826
3827 // exploit symmetric relations between vertices
3828 if (symmetryShortCuts.containsKey(v1)
3829 && symmetryShortCuts.get(v1).contains(v2))
3830 {
3831 return 0;
3832 }
3833
3834 int result = v1.compare(v2);
3835 if (result==0)
3836 {
3837 Vertex dv1 = v1.getDNPVertex();
3838 Vertex dv2 = v2.getDNPVertex();
3839 if (dv1==null && dv2==null)
3840 {
3841 return result;
3842 }
3843
3844 Set<Node> symToV2 = new HashSet<Node>();
3845 for (Vertex sv : dv2.getGraphOwner().getSymSetForVertex(dv2))
3846 {
3847 symToV2.add((Node) sv.getProperty(
3849 }
3850
3851 Set<Node> symToV1 = new HashSet<Node>();
3852 for (Vertex sv : dv1.getGraphOwner().getSymSetForVertex(dv1))
3853 {
3854 symToV1.add((Node) sv.getProperty(
3856 }
3857
3858 for (Node v1s : symToV1)
3859 {
3860 if (symmetryShortCuts.containsKey(v1s))
3861 {
3862 symmetryShortCuts.get(v1s).addAll(symToV2);
3863 } else {
3864 symmetryShortCuts.put(v1s,symToV2);
3865 }
3866 }
3867 return 0;
3868 }
3869 return result;
3870 }
3871 };
3872
3873 Comparator<NodeConnection> eComp = NodeConnection::compare;
3874
3875 VF2GraphIsomorphismInspector<Node, NodeConnection> vf2 =
3876 new VF2GraphIsomorphismInspector<>(this.jGraphKernel,
3877 other.jGraphKernel, vComp, eComp);
3878
3879 return vf2.isomorphismExists();
3880 }
3881
3882//------------------------------------------------------------------------------
3883
3894 public boolean sameAs(DGraph other, StringBuilder reason)
3895 {
3896 if (this.getEdgeCount() != other.getEdgeCount())
3897 {
3898 reason.append("Different number of edges ("+this.getEdgeCount()+":"
3899 +other.getEdgeCount()+")");
3900 return false;
3901 }
3902
3903 if (this.getVertexCount() != other.getVertexCount())
3904 {
3905 reason.append("Different number of vertices ("+this.getVertexCount()+":"
3906 +other.getVertexCount()+")");
3907 return false;
3908 }
3909
3910 if (this.getSymmetricSetCount() != other.getSymmetricSetCount())
3911 {
3912 reason.append("Different number of symmetric sets ("
3913 + this.getSymmetricSetCount() + ":"
3914 + other.getSymmetricSetCount() + ")");
3915 return false;
3916 }
3917
3918 if (this.getRingCount() != other.getRingCount())
3919 {
3920 reason.append("Different number of Rings ("+this.getRingCount()+":"
3921 +other.getRingCount()+")");
3922 return false;
3923 }
3924
3925 //Pairwise correspondence of vertices
3926 Map<Vertex,Vertex> vertexMap =
3927 new HashMap<Vertex,Vertex>();
3928
3929 vertexMap.put(this.getVertexAtPosition(0),other.getVertexAtPosition(0));
3930
3931 //WARNING: assuming that the first vertex in the vertex list is the root
3932 // and also that there are no disconnections. Both assumptions are
3933 // reasonable for graphs.
3934 try {
3935 if (!compareGraphNodes(this.getVertexAtPosition(0), this,
3936 other.getVertexAtPosition(0), other,
3937 vertexMap,reason))
3938 {
3939 return false;
3940 }
3941 } catch (DENOPTIMException e) {
3942 e.printStackTrace();
3943 reason.append("Exception");
3944 return false;
3945 }
3946
3947 //Check Symmetric sets
3948 Iterator<SymmetricVertexes> ssIter = this.getSymSetsIterator();
3949 while (ssIter.hasNext())
3950 {
3951 SymmetricVertexes ssT = ssIter.next();
3952
3954 vertexMap.get(ssT.get(0)));
3955 if (ssO.size() == 0)
3956 {
3957 // ssO is empty because no SymmetricSet was found that
3958 // contains the given vertex. This means the two graphs
3959 // are different
3960 reason.append("Symmetric set not found for vertex ("
3961 + ssT.get(0) + ")");
3962 return false;
3963 }
3964
3965 if (ssT.size() != ssO.size())
3966 {
3967 reason.append("Different number of symmetric sets on vertex "
3968 + ssT.get(0) + "("+ssT.size()+":"+ssO.size()+")");
3969 return false;
3970 }
3971
3972 Set<Vertex> mappedVrtxFromThis = new HashSet<>();
3973 ssT.stream().forEach(v -> mappedVrtxFromThis.add(vertexMap.get(v)));
3974
3975 Set<Vertex> vrtxFromOther = new HashSet<>();
3976 ssO.stream().forEach(v -> vrtxFromOther.add(v));
3977 if (!vrtxFromOther.equals(mappedVrtxFromThis))
3978 {
3979 reason.append("Difference in symmetric set " + ssT + " vs " + ssO);
3980 return false;
3981 }
3982 }
3983
3984 //Check Rings
3985 for (Ring rT : this.getRings())
3986 {
3987 Vertex vhT = rT.getHeadVertex();
3988 Vertex vtT = rT.getTailVertex();
3989 boolean hasRing = other
3990 .getRingsInvolvingVertex(vertexMap.get(vhT))
3991 .stream()
3992 .anyMatch(rO -> sameAsRings(reason, vertexMap, rT, vhT,
3993 vtT, rO));
3994 if (!hasRing) {
3995 return false;
3996 }
3997 }
3998
3999 return true;
4000 }
4001
4002//------------------------------------------------------------------------------
4003
4004 private boolean sameAsRings(StringBuilder reason, Map<Vertex,
4005 Vertex> vertexMap, Ring rT, Vertex vhT,
4006 Vertex vtT, Ring rO) {
4007 if (rT.getSize() != rO.getSize()) {
4008 reason.append("Different ring size (").append(rT.getSize())
4009 .append(":").append(rO.getSize()).append(")");
4010 return false;
4011 }
4012
4013 if (rO.getHeadVertex() == vertexMap.get(vhT)
4014 && rO.getTailVertex() == vertexMap.get(vtT)) {
4015 for (int i = 1; i < rT.getSize(); i++) {
4016 if (vertexMap.get(rT.getVertexAtPosition(i))
4017 != rO.getVertexAtPosition(i)) {
4018 reason.append("Rings differ (A) (").append(rT).append(":")
4019 .append(rO).append(")");
4020 return false;
4021 }
4022 }
4023 } else if (rO.getHeadVertex() == vertexMap.get(vtT)
4024 && rO.getTailVertex() == vertexMap.get(vhT)) {
4025 for (int i = 1; i < rT.getSize(); i++) {
4026 int j = rO.getSize() - i - 1;
4027 if (vertexMap.get(rT.getVertexAtPosition(i))
4028 != rO.getVertexAtPosition(j)) {
4029 reason.append("Rings differ (B) (").append(rT).append(":")
4030 .append(rO).append(")");
4031 return false;
4032 }
4033 }
4034 } else {
4035 reason.append("Rings differ (C) (").append(rT).append(":")
4036 .append(rO).append(")");
4037 return false;
4038 }
4039 return true;
4040 }
4041
4042//------------------------------------------------------------------------------
4043
4054 public static boolean compareGraphNodes(Vertex thisV,
4055 DGraph thisG,
4056 Vertex otherV,
4057 DGraph otherG) throws DENOPTIMException
4058 {
4059 Map<Vertex, Vertex> map = new HashMap<>();
4060 map.put(thisV, otherV);
4061 return compareGraphNodes(thisV, thisG, otherV, otherG, map,
4062 new StringBuilder());
4063 }
4064
4065//------------------------------------------------------------------------------
4066
4078 private static boolean compareGraphNodes(Vertex seedOnA,
4079 DGraph gA, Vertex seedOnB, DGraph gB,
4080 Map<Vertex,Vertex> vertexMap, StringBuilder reason)
4081 throws DENOPTIMException
4082 {
4083 if (!seedOnA.sameAs(seedOnB, reason))
4084 {
4085 reason.append("Different vertex ("+seedOnA+":"+seedOnB+")");
4086 return false;
4087 }
4088
4089 List<Edge> edgesFromThis = gA.getEdgesWithSrc(seedOnA);
4090 List<Edge> edgesFromOther = gB.getEdgesWithSrc(seedOnB);
4091 if (edgesFromThis.size() != edgesFromOther.size())
4092 {
4093 reason.append("Different number of edges from vertex "+seedOnA+" ("
4094 +edgesFromThis.size()+":"
4095 +edgesFromOther.size()+")");
4096 return false;
4097 }
4098
4099 // pairwise correspondence between child vertices
4100 ArrayList<Vertex[]> pairs = new ArrayList<Vertex[]>();
4101
4102 for (Edge et : edgesFromThis)
4103 {
4104 boolean found = false;
4105 Edge eo = null;
4106 StringBuilder innerSb = new StringBuilder();
4107 int otherEdgeI = 0;
4108 for (Edge e : edgesFromOther)
4109 {
4110 innerSb.append(" Edge"+otherEdgeI+":");
4111 if (et.sameAs(e,innerSb))
4112 {
4113 found = true;
4114 eo = e;
4115 break;
4116 }
4117 }
4118 if (!found)
4119 {
4120 reason.append("Edge not found in other("+et+"). "
4121 + "Edges in othes: "+innerSb.toString());
4122 return false;
4123 }
4124
4125 //Check: this should never be true
4126 if (vertexMap.keySet().contains(
4127 gA.getVertexWithId(et.getTrgVertex())))
4128 {
4129 throw new DENOPTIMException("More than one attempt to set vertex map.");
4130 }
4131 vertexMap.put(gA.getVertexWithId(et.getTrgVertex()),
4132 gB.getVertexWithId(eo.getTrgVertex()));
4133
4134 Vertex[] pair = new Vertex[]{
4135 gA.getVertexWithId(et.getTrgVertex()),
4136 gB.getVertexWithId(eo.getTrgVertex())};
4137 pairs.add(pair);
4138 }
4139
4140 //Recursion on child vertices
4141 for (Vertex[] pair : pairs)
4142 {
4143 Vertex v = pair[0];
4144 Vertex o = pair[1];
4145 boolean localRes = compareGraphNodes(v, gA, o, gB,vertexMap,
4146 reason);
4147 if (!localRes)
4148 {
4149 return false;
4150 }
4151 }
4152
4153 return true;
4154 }
4155
4156//------------------------------------------------------------------------------
4157
4164 public boolean containsAtoms()
4165 {
4166 for (Vertex v : getVertexList())
4167 {
4168 if (v.containsAtoms())
4169 {
4170 return true;
4171 }
4172 }
4173 return false;
4174 }
4175
4176//------------------------------------------------------------------------------
4177
4183 {
4184 int n = 0;
4185 for (Vertex v : getVertexList())
4186 {
4187 n += v.getHeavyAtomsCount();
4188 }
4189 return n;
4190 }
4191
4192//------------------------------------------------------------------------------
4193
4199 public ArrayList<AttachmentPoint> getAttachmentPoints()
4200 {
4201 ArrayList<AttachmentPoint> lstAPs =
4202 new ArrayList<AttachmentPoint>();
4203 for (Vertex v : gVertices)
4204 {
4205 lstAPs.addAll(v.getAttachmentPoints());
4206 }
4207 return lstAPs;
4208 }
4209
4210//------------------------------------------------------------------------------
4211
4217 public ArrayList<AttachmentPoint> getAvailableAPs()
4218 {
4219 ArrayList<AttachmentPoint> lstFreeAPs =
4220 new ArrayList<AttachmentPoint>();
4222 {
4223 if (ap.isAvailable())
4224 {
4225 lstFreeAPs.add(ap);
4226 }
4227 }
4228 return lstFreeAPs;
4229 }
4230
4231//------------------------------------------------------------------------------
4232
4240 public List<AttachmentPoint> getAvailableAPsThroughout()
4241 {
4242 ArrayList<AttachmentPoint> lstFreeAPs =
4243 new ArrayList<AttachmentPoint>();
4245 {
4246 if (ap.isAvailableThroughout())
4247 {
4248 lstFreeAPs.add(ap);
4249 }
4250 }
4251 return lstFreeAPs;
4252 }
4253
4254//------------------------------------------------------------------------------
4255
4265 {
4266 AttachmentPoint ap = null;
4267 for (AttachmentPoint apCand : getAttachmentPoints())
4268 {
4269 if (apCand.getID() == id)
4270 {
4271 ap = apCand;
4272 break;
4273 }
4274 }
4275 return ap;
4276 }
4277
4278//------------------------------------------------------------------------------
4279
4280 protected int getUniqueAPIndex()
4281 {
4282 return apCounter.getAndIncrement();
4283 }
4284
4285//------------------------------------------------------------------------------
4286
4293 public boolean graphNeedsCappingGroups(FragmentSpace fragSpace)
4294 {
4295 for (Vertex v : getVertexList()) {
4296 for (AttachmentPoint ap : v.getAttachmentPoints()) {
4297 if (ap.isAvailable() && fragSpace.getAPClassOfCappingVertex(
4298 ap.getAPClass()) !=null
4299 ) {
4300 return true;
4301 }
4302 }
4303 }
4304 return false;
4305 }
4306
4307//------------------------------------------------------------------------------
4308
4313 public void removeCappingGroupsOn(Vertex vertex)
4314 {
4315 ArrayList<Vertex> toDel = new ArrayList<Vertex>();
4316 for (Vertex vtx : this.getChildVertices(vertex))
4317 {
4318 if (vtx instanceof Fragment == false)
4319 {
4320 continue;
4321 }
4322 // capping groups have fragment type 2
4323 if (((Fragment) vtx).getBuildingBlockType() == BBType.CAP
4324 && !isVertexInRing(vtx))
4325 {
4326 toDel.add(vtx);
4327 }
4328 }
4329
4330 for (Vertex v : toDel)
4331 {
4332 removeVertex(v);
4333 }
4334 }
4335
4336//------------------------------------------------------------------------------
4337
4343 public void removeCappingGroups(List<Vertex> lstVerts)
4344 {
4345 List<Long> rvids = new ArrayList<>();
4346 for (int i=0; i<lstVerts.size(); i++)
4347 {
4348 Vertex vtx = lstVerts.get(i);
4349 if (vtx instanceof Fragment == false)
4350 {
4351 continue;
4352 }
4353
4354 if (((Fragment) vtx).getBuildingBlockType() == BBType.CAP
4355 && !isVertexInRing(vtx))
4356 {
4357 rvids.add(vtx.getVertexId());
4358 }
4359 }
4360
4361 // remove the vids from the vertex lst
4362 for (int i=0; i<rvids.size(); i++)
4363 {
4364 long vid = rvids.get(i);
4366 }
4367 }
4368
4369//------------------------------------------------------------------------------
4370
4371 public void removeCappingGroupsFromChilds(List<Vertex> lstVerts)
4372 {
4373 for (Vertex v : lstVerts)
4374 {
4376 }
4377 }
4378
4379//------------------------------------------------------------------------------
4380
4386 {
4387 removeCappingGroups(new ArrayList<Vertex>(gVertices));
4388 }
4389
4390//------------------------------------------------------------------------------
4391
4399 {
4400 if (!fragSpace.useAPclassBasedApproach())
4401 return;
4402 addCappingGroups(new ArrayList<Vertex>(gVertices), fragSpace);
4403 }
4404
4405//------------------------------------------------------------------------------
4406
4421 public void addCappingGroups(List<Vertex> vertexAddedToThis,
4422 FragmentSpace fragSpace) throws DENOPTIMException
4423 {
4424 if (!fragSpace.useAPclassBasedApproach())
4425 return;
4426
4427 for (Vertex curVertex : vertexAddedToThis)
4428 {
4429 // no capping of a capping group. Since capping groups are expected
4430 // to have only one AP, there should never be a capping group with
4431 // a free AP.
4432 if (curVertex.getBuildingBlockType() == Vertex.BBType.CAP)
4433 {
4434 continue;
4435 }
4436
4437 for (AttachmentPoint curDap : curVertex.getAttachmentPoints())
4438 {
4439 if (curDap.isAvailableThroughout())
4440 {
4441 APClass apcCap = fragSpace.getAPClassOfCappingVertex(
4442 curDap.getAPClass());
4443 if (apcCap != null)
4444 {
4445 int bbIdCap = fragSpace.getCappingFragment(apcCap);
4446
4447 if (bbIdCap != -1)
4448 {
4451 bbIdCap, BBType.CAP, fragSpace);
4452 DGraph molGraph = curDap.getOwner()
4453 .getGraphOwner();
4454 if (molGraph == null)
4455 throw new Error("Cannot add capping "
4456 + "groups to a vertex that does not "
4457 + "belong to a graph.");
4458 molGraph.appendVertexOnAP(curDap, capVrtx.getAP(0));
4459 }
4460 else
4461 {
4462 String msg = "Capping is required but no proper "
4463 + "capping fragment found with APCalss "
4464 + apcCap;
4465 throw new Error(msg);
4466 }
4467 }
4468 }
4469 }
4470 }
4471 }
4472
4473//------------------------------------------------------------------------------
4474
4487 public DGraph extractSubgraph(int index)
4488 throws DENOPTIMException
4489 {
4490 return extractSubgraph(this.getVertexAtPosition(index));
4491 }
4492
4493//------------------------------------------------------------------------------
4494
4507 throws DENOPTIMException
4508 {
4509 return extractSubgraph(seed, Integer.MAX_VALUE, false);
4510 }
4511
4512//------------------------------------------------------------------------------
4513
4532 public DGraph extractSubgraph(Vertex seed, int numLayers,
4533 boolean stopBeforeRCVs) throws DENOPTIMException
4534 {
4535 if (!this.gVertices.contains(seed))
4536 {
4537 throw new DENOPTIMException("Attempt to extract a subgraph giving "
4538 + "a seed vertex that is not contained in this graph.");
4539 }
4540 DGraph subGraph = this.clone();
4541 Vertex seedClone = subGraph.getVertexAtPosition(
4542 this.indexOf(seed));
4543
4544 ArrayList<Vertex> subGrpVrtxs = new ArrayList<Vertex>();
4545 subGrpVrtxs.add(seedClone);
4546 subGraph.getChildrenTree(seedClone, subGrpVrtxs, numLayers, stopBeforeRCVs);
4547 ArrayList<Vertex> toRemove = new ArrayList<Vertex>();
4548 for (Vertex v : subGraph.gVertices)
4549 {
4550 if (!subGrpVrtxs.contains(v))
4551 {
4552 toRemove.add(v);
4553 }
4554 }
4555
4556 for (Vertex v : toRemove)
4557 {
4558 subGraph.removeVertex(v);
4559 }
4560
4561 return subGraph;
4562 }
4563
4564//------------------------------------------------------------------------------
4565
4584 List<Vertex> limits, boolean stopBeforeRCVs)
4585 throws DENOPTIMException
4586 {
4587 if (!this.gVertices.contains(seed))
4588 {
4589 throw new DENOPTIMException("Attempt to extract a subgraph giving "
4590 + "a seed vertex that is not contained in this graph.");
4591 }
4592
4593 if (limits.size()==0)
4594 {
4595 return extractSubgraph(seed, stopBeforeRCVs);
4596 }
4597
4598 DGraph subGraph = this.clone();
4599 Vertex seedClone = subGraph.getVertexAtPosition(
4600 this.indexOf(seed));
4601
4602 List<Vertex> limitsInClone = new ArrayList<Vertex>();
4603 for (Vertex v : limits)
4604 limitsInClone.add(subGraph.getVertexAtPosition(this.indexOf(v)));
4605
4606 ArrayList<Vertex> subGrpVrtxs = new ArrayList<Vertex>();
4607 subGrpVrtxs.add(seedClone);
4608 subGraph.getChildTreeLimited(seedClone, subGrpVrtxs, limitsInClone,
4609 stopBeforeRCVs);
4610
4611 ArrayList<Vertex> toRemove = new ArrayList<Vertex>();
4612 for (Vertex v : subGraph.gVertices)
4613 {
4614 if (!subGrpVrtxs.contains(v))
4615 {
4616 toRemove.add(v);
4617 }
4618 }
4619 for (Vertex v : toRemove)
4620 {
4621 subGraph.removeVertex(v);
4622 }
4623
4624 return subGraph;
4625 }
4626
4627//------------------------------------------------------------------------------
4628
4643 public DGraph extractSubgraph(Vertex seed, boolean stopBeforeRCVs)
4644 throws DENOPTIMException
4645 {
4646 if (!this.gVertices.contains(seed))
4647 {
4648 throw new DENOPTIMException("Attempt to extract a subgraph giving "
4649 + "a seed vertex that is not contained in this graph.");
4650 }
4651
4652 DGraph subGraph = this.clone();
4653 Vertex seedClone = subGraph.getVertexAtPosition(
4654 this.indexOf(seed));
4655
4656 ArrayList<Vertex> subGrpVrtxs = new ArrayList<Vertex>();
4657 subGrpVrtxs.add(seedClone);
4658 subGraph.getChildTreeLimited(seedClone, subGrpVrtxs, stopBeforeRCVs);
4659
4660 ArrayList<Vertex> toRemove = new ArrayList<Vertex>();
4661 for (Vertex v : subGraph.gVertices)
4662 {
4663 if (!subGrpVrtxs.contains(v))
4664 {
4665 toRemove.add(v);
4666 }
4667 }
4668 for (Vertex v : toRemove)
4669 {
4670 subGraph.removeVertex(v);
4671 }
4672
4673 return subGraph;
4674 }
4675
4676//------------------------------------------------------------------------------
4677
4686 public List<DGraph> extractPattern(GraphPattern pattern)
4687 throws DENOPTIMException
4688 {
4689 return extractPattern(pattern, false).keySet().stream().collect(
4690 Collectors.toList());
4691 }
4692
4693//------------------------------------------------------------------------------
4694
4717 public Map<DGraph,ObjectPair> extractPattern(GraphPattern pattern,
4718 boolean recordConnectivity) throws DENOPTIMException
4719 {
4720 if (pattern != GraphPattern.RING) {
4721 throw new IllegalArgumentException("Graph pattern " + pattern +
4722 " not supported.");
4723 }
4724
4725 List<Set<Vertex>> disjointMultiCycleVertices = this
4726 .getRings()
4727 .stream()
4728 .map(Ring::getVertices)
4729 .map(HashSet::new)
4730 .collect(Collectors.toList());
4731
4732 GeneralUtils.unionOfIntersectingSets(disjointMultiCycleVertices);
4733
4734 Map<DGraph,ObjectPair> subGraphsAndConnections = new LinkedHashMap<>();
4735 for (Set<Vertex> fusedRing : disjointMultiCycleVertices) {
4736 if (recordConnectivity)
4737 {
4738 Set<Edge> connectionToSubgraph = new HashSet<Edge>();
4739 Set<Edge> connectionFromSubgraph = new HashSet<Edge>();
4740 DGraph subGraph = extractSubgraph(fusedRing, connectionToSubgraph,
4741 connectionFromSubgraph);
4742 ObjectPair connections = new ObjectPair(connectionToSubgraph,
4743 connectionFromSubgraph);
4744 subGraphsAndConnections.put(subGraph, connections);
4745 } else {
4746 DGraph subGraph = extractSubgraph(fusedRing);
4747 subGraphsAndConnections.put(subGraph, null);
4748 }
4749 }
4750
4751 for (DGraph g : subGraphsAndConnections.keySet()) {
4752 g.storeCurrentVertexIDs();
4753 g.renumberGraphVertices();
4755 }
4756
4757 return subGraphsAndConnections;
4758 }
4759
4760 //------------------------------------------------------------------------------
4761
4768 public DGraph extractSubgraph(Collection<Vertex> definedOn)
4769 {
4770 DGraph subgraph = extractSubgraph(definedOn, null, null);
4771 return subgraph;
4772 }
4773
4774//------------------------------------------------------------------------------
4775
4787 public DGraph extractSubgraph(Collection<Vertex> definedOn,
4788 Set<Edge> connectionToSubgraph,
4789 Set<Edge> connectionFromSubgraph)
4790 {
4791
4792 DGraph subgraph = this.clone();
4793
4794 Set<Vertex> complement = subgraph
4795 .getVertexList()
4796 .stream()
4797 .filter(u -> definedOn
4798 .stream()
4799 .allMatch(v -> v.getVertexId() != u.getVertexId())
4800 ).collect(Collectors.toSet());
4801
4802 Set<Long> vrtxIDsInComplement = complement.stream()
4803 .map(v -> v.getVertexId())
4804 .collect(Collectors.toSet());
4805
4806 if (connectionToSubgraph!=null && connectionFromSubgraph!=null)
4807 {
4808 for (Vertex v : definedOn)
4809 {
4810 for (Edge e : this.getEdgeList())
4811 {
4812 if (e.getSrcAP().getOwner() == v &&
4813 vrtxIDsInComplement.contains(e.getTrgVertex()))
4814 {
4815 connectionFromSubgraph.add(e);
4816 }
4817
4818 if (e.getTrgAP().getOwner() == v &&
4819 vrtxIDsInComplement.contains(e.getSrcVertex()))
4820 {
4821 connectionToSubgraph.add(e);
4822 }
4823 }
4824 }
4825 }
4826
4827 for (Vertex v : complement) {
4828 subgraph.removeVertex(v);
4829 }
4830
4831 return subgraph;
4832 }
4833
4834//------------------------------------------------------------------------------
4835
4846 FragmentSpace fragSpace) throws DENOPTIMException
4847 {
4848 return embedPatternsInTemplates(pattern, fragSpace, ContractLevel.FREE);
4849 }
4850
4851//------------------------------------------------------------------------------
4852
4867 FragmentSpace fragSpace, ContractLevel contract)
4868 throws DENOPTIMException
4869 {
4870 // We will return a modified clone of this graph
4871 DGraph graph = this.clone();
4872 // We use IDs to find the mapping of APs between cloned graphs. So, must
4873 // ensure the IDs of APs are unique within the graph.
4874 graph.ensureUniqueApIDs();
4875
4876 // Identify the subgraphs to be replaced by templates
4877 Map<DGraph,ObjectPair> subGraphsAndLinks = graph.extractPattern(
4878 pattern, true);
4879
4880 // Replace the subgraphs with the templates
4881 for (Map.Entry<DGraph,ObjectPair> entry : subGraphsAndLinks.entrySet())
4882 {
4883 // WARNING: while the subgraph is a clone of 'graph', the sets
4884 // contain referenced to the edges of 'graph'.
4885 DGraph subGraph = entry.getKey();
4886
4887 // Make template
4888 BBType tmplType = subGraph.hasScaffoldTypeVertex() ?
4889 BBType.SCAFFOLD :
4891 Template tmpl = new Template(tmplType);
4892 tmpl.setInnerGraph(subGraph);
4893 tmpl.setContractLevel(contract);
4894
4895 // Recover info on which APs of the original subgraph (i.e., APs in
4896 // 'graph') correspond to APs on the template.
4897 LinkedHashMap<AttachmentPoint, AttachmentPoint> apMapOrigToTmpl =
4898 new LinkedHashMap<AttachmentPoint, AttachmentPoint>();
4899 @SuppressWarnings("unchecked")
4900 Set<Edge> edsToSubgrph = (Set<Edge>) entry.getValue().getFirst();
4901 for (Edge e : edsToSubgrph)
4902 {
4903 AttachmentPoint apOnOrig = e.getTrgAP();
4904 AttachmentPoint apOnTmpl = tmpl.getOuterAPFromInnerAP(
4905 subGraph.getAPWithId(apOnOrig.getID()));
4906 apMapOrigToTmpl.put(apOnOrig, apOnTmpl);
4907 }
4908 @SuppressWarnings("unchecked")
4909 Set<Edge> edsFromSubGrph = (Set<Edge>) entry.getValue().getSecond();
4910 for (Edge e : edsFromSubGrph)
4911 {
4912 AttachmentPoint apOnOrig = e.getSrcAP();
4913 AttachmentPoint apOnTmpl = tmpl.getOuterAPFromInnerAP(
4914 subGraph.getAPWithId(apOnOrig.getID()));
4915 apMapOrigToTmpl.put(apOnOrig, apOnTmpl);
4916 }
4917
4918 // Identify the vertexes in the subgraph replaced by the template
4919 List<Vertex> toReplaceByTemplate = new ArrayList<>();
4920 for (Vertex embeddedVrtx : subGraph.gVertices)
4921 {
4922 long vIdInThis = (long) embeddedVrtx.getProperty(
4924 toReplaceByTemplate.add(graph.getVertexWithId(vIdInThis));
4925 }
4926
4927 // Do the actual replacement of original subgraph with the template
4928 DGraph singleVertedGraph = new DGraph();
4929 singleVertedGraph.addVertex(tmpl);
4930 graph.replaceSubGraph(toReplaceByTemplate, singleVertedGraph,
4931 apMapOrigToTmpl, fragSpace);
4932 }
4933
4934 return graph;
4935 }
4936
4937//------------------------------------------------------------------------------
4938
4946 private static void reorderVertexList(DGraph g)
4947 {
4948 Vertex newScaffold = g.getSourceVertex();
4949 if (newScaffold == null) {
4950 return;
4951 }
4952 DGraph.setScaffold(newScaffold);
4954 }
4955
4956//------------------------------------------------------------------------------
4957
4962 private static void fixEdgeDirections(DGraph graph)
4963 {
4964 Vertex src = graph.getSourceVertex();
4965 fixEdgeDirections(src, new HashSet<>());
4966 }
4967
4968//------------------------------------------------------------------------------
4969
4974 private static void fixEdgeDirections(Vertex v,
4975 Set<Long> visited)
4976 {
4977 visited.add(v.getVertexId());
4978 int visitedVertexEncounters = 0;
4979 for (int i = 0; i < v.getNumberOfAPs(); i++) {
4980 AttachmentPoint ap = v.getAP(i);
4981 Edge edge = ap.getEdgeUser();
4982 if (edge != null) {
4983 long srcVertex = edge.getSrcVertex();
4984 boolean srcIsVisited = srcVertex != v.getVertexId()
4985 && visited.contains(srcVertex);
4986
4987 visitedVertexEncounters += srcIsVisited ? 1 : 0;
4988 if (visitedVertexEncounters >= 2) {
4989 throw new IllegalArgumentException("Invalid graph. "
4990 + "Contains a cycle.");
4991 }
4992
4993 boolean edgeIsWrongWay = edge.getTrgVertex()
4994 == v.getVertexId() && !srcIsVisited;
4995 if (edgeIsWrongWay) {
4996 edge.flipEdge();
4997 }
4998 if (!srcIsVisited) {
4999 fixEdgeDirections(edge.getTrgAP().getOwner(), visited);
5000 }
5001 }
5002 }
5003 }
5004
5005//------------------------------------------------------------------------------
5006
5017 public boolean removeBranchStartingAt(Vertex v, boolean symmetry)
5018 throws DENOPTIMException
5019 {
5020 boolean res = true;
5021 if (hasSymmetryInvolvingVertex(v) && symmetry)
5022 {
5023 for (Vertex sv : getSymSetForVertex(v))
5024 {
5025 boolean res2 = removeBranchStartingAt(sv);
5026 if (!res2)
5027 {
5028 res = res2;
5029 }
5030 }
5031 }
5032 else
5033 {
5034 res = removeBranchStartingAt(v);
5035 }
5036 return res;
5037 }
5038
5039//------------------------------------------------------------------------------
5040
5051 throws DENOPTIMException
5052 {
5053 Edge edgeToParent = v.getEdgeToParent();
5054 if (edgeToParent != null)
5055 {
5056 removeEdge(edgeToParent);
5057 }
5059 }
5060
5061//------------------------------------------------------------------------------
5062
5077 throws DENOPTIMException
5078 {
5079 // now get the vertices attached to v
5080 ArrayList<Vertex> children = new ArrayList<Vertex>();
5081 getChildrenTree(v, children);
5082
5083 // delete the children vertices and associated edges
5084 for (Vertex c : children) {
5085 removeVertex(c);
5086 }
5087
5088 // finally delete the vertex and associated edges
5089 removeVertex(v);
5090
5091 return getVertexWithId(v.getVertexId()) == null;
5092 }
5093
5094//------------------------------------------------------------------------------
5095
5108 FragmentSpace fragSpace) throws DENOPTIMException
5109 {
5110 List<Ring> rings = getRingsInvolvingVertex(v);
5111 if (rings.isEmpty())
5112 {
5113 return false;
5114 }
5115
5116 // Identify the RCVs defining the chord that might become an edge
5117 // The corresponding ring is the "frame" we'll use throughout this
5118 // operation, and is the smallest ring that is closest to the appointed
5119 // vertex.
5120 Ring frame = null;
5121 Vertex[] replacedByEdge = new Vertex[2];
5122 int minDist = Integer.MAX_VALUE;
5123 BondType bt = null;
5124 for (Ring r : rings)
5125 {
5126 int dist = Math.min(r.getDistance(r.getHeadVertex(),v),
5127 r.getDistance(r.getTailVertex(),v));
5128 if (dist < minDist)
5129 {
5130 minDist = dist;
5131 frame = r;
5132 replacedByEdge[0] = r.getHeadVertex();
5133 replacedByEdge[1] = r.getTailVertex();
5134 bt = r.getBondType();
5135 }
5136 }
5137
5138 // Find out where branching vertices are along the frame ring
5139 boolean frameHasBranching = false;
5140 List<Integer> branchingPositions = new ArrayList<Integer>();
5141 int posOfFocusVrtInRing = frame.getPositionOf(v);
5142 for (int i=0; i<frame.getSize(); i++)
5143 {
5144 Vertex vi = frame.getVertexAtPosition(i);
5145 // We consider the scaffold as a branching point, i.e., it will never be removed
5147 {
5148 branchingPositions.add(i);
5149 continue;
5150 }
5151 long oNonCap = vi.getAttachmentPoints().size()
5154 if (oNonCap > 2)
5155 {
5156 branchingPositions.add(i);
5157 frameHasBranching = true;
5158 }
5159 }
5160
5161 // Make sure this ring is not all there is in this graph.
5162 if (rings.size()==1 && !frameHasBranching)
5163 {
5164 return false;
5165 }
5166
5167 // Identify the end points of chain that gets removed, i.e., the chain
5168 // containing V and is between branchingDownstreamId and
5169 // branchingUpstreamId gets removed.
5170 int branchingDownstreamId = -1;
5171 for (int i=0; i<frame.getSize(); i++)
5172 {
5173 int iTranslated = i + posOfFocusVrtInRing;
5174 if (iTranslated >= frame.getSize())
5175 iTranslated = iTranslated - frame.getSize();
5176 if (branchingPositions.contains(iTranslated))
5177 {
5178 branchingDownstreamId = iTranslated;
5179 break;
5180 }
5181 }
5182 int branchingUpstreamId = -1;
5183 for (int i=(frame.getSize()-1); i>-1; i--)
5184 {
5185 int iTranslated = i + posOfFocusVrtInRing;
5186 if (iTranslated >= frame.getSize())
5187 iTranslated = iTranslated - frame.getSize();
5188 if (branchingPositions.contains(iTranslated))
5189 {
5190 branchingUpstreamId = iTranslated;
5191 break;
5192 }
5193 }
5194
5195 // Now, collect the vertices along the ring based on whether they
5196 // will be removed or remain (possible with a change of edge direction
5197 // and replacement of an RCV pair by edge)
5198 List<Vertex> remainingChain = new ArrayList<Vertex>();
5199 for (int i=0; i<frame.getSize(); i++)
5200 {
5201 int iTranslated = i + branchingDownstreamId;
5202 if (iTranslated >= frame.getSize())
5203 iTranslated = iTranslated - frame.getSize();
5204 remainingChain.add(frame.getVertexAtPosition(iTranslated));
5205 if (iTranslated == branchingUpstreamId)
5206 {
5207 break;
5208 }
5209 }
5210 List<Vertex> toRemoveChain = new ArrayList<Vertex>();
5211 for (int i=0; i<frame.getSize(); i++)
5212 {
5213 int iTranslated = i + branchingUpstreamId + 1; //exclude branch point
5214 if (iTranslated >= frame.getSize())
5215 iTranslated = iTranslated - frame.getSize();
5216 toRemoveChain.add(frame.getVertexAtPosition(iTranslated));
5217 if (iTranslated == (branchingDownstreamId - 1)) //exclude branch point
5218 {
5219 break;
5220 }
5221 }
5222
5223 // Need to exclude the case where the chain to remove consists only of
5224 // the RCVs because it would lead to loss of the chord and creation of
5225 // cyclic graph. Also, proceeding without making the edge would simply
5226 // correspond to removing the chord.
5227 if (toRemoveChain.size() == 2)
5228 {
5229 int countOrRCVs = 0;
5230 for (Vertex vtr : toRemoveChain)
5231 {
5232 if (vtr.isRCV())
5233 countOrRCVs++;
5234 }
5235 if (countOrRCVs == 2)
5236 {
5237 return false;
5238 }
5239 }
5240
5241 // To understand if we need to reverse some edges, we identify the
5242 // deepest vertex level-wise. It may or may not be a scaffold!!!
5243 int deepestLevel = Integer.MAX_VALUE;
5244 Vertex deepestVrtRemainingChain = null;
5245 for (Vertex vint : remainingChain)
5246 {
5247 int lvl = getLevel(vint);
5248 if (lvl < deepestLevel)
5249 {
5250 deepestLevel = lvl;
5251 deepestVrtRemainingChain = vint;
5252 }
5253 }
5254
5255 // Check if we need to transform a pair of RCVs into an edge, and
5256 // identify APs used by the edge that replaces the to-be-removed RCVs.
5257 // I do not see how the chain can possibly contain only one of the
5258 // RCVs, so I assume that if one RCV is there, then the other is too.
5259 if (remainingChain.contains(replacedByEdge[0]))
5260 {
5261 AttachmentPoint apSrcOfNewEdge = replacedByEdge[0]
5263 AttachmentPoint apTrgOfNewEdge = replacedByEdge[1]
5265
5266 // Remove the RCVs that will be replaced by an edge
5267 removeVertex(replacedByEdge[0]);
5268 remainingChain.remove(replacedByEdge[0]);
5269 removeVertex(replacedByEdge[1]);
5270 remainingChain.remove(replacedByEdge[1]);
5271
5272 // And make the new edge. The direction can be anything. Later, we
5273 // decide if we need to reverse it.
5274 //NB: the compatibility between the APs should be granted by the
5275 // previous existence of the chord. so no need to check
5276 // apSrcOfNewEdge.getAPClass().isCPMapCompatibleWith(
5277 // apTrgOfNewEdge.getAPClass()))
5278 addEdge(new Edge(apSrcOfNewEdge, apTrgOfNewEdge, bt));
5279 } else {
5280 // We remove the frame already, otherwise we will try to recreate
5281 // such ring from RCVs and waste time with it.
5282 removeRing(frame);
5283 }
5284
5285 // Now, inspect the paths from the deepest vertex and outwards, to
5286 // find out where to start reversing edges.
5287 List<Vertex> chainToReverseA = new ArrayList<Vertex>();
5288 List<Vertex> chainToReverseB = new ArrayList<Vertex>();
5289 for (int i=(remainingChain.indexOf(deepestVrtRemainingChain)+1);
5290 i<remainingChain.size(); i++)
5291 {
5292 Vertex vPrev = remainingChain.get(i-1);
5293 Vertex vHere = remainingChain.get(i);
5294 if (!vPrev.getChilddren().contains(vHere))
5295 {
5296 // in an healthy spanning tree, once we find the first reversed
5297 // edge, all the following edges will also have to be reversed.
5298 if (chainToReverseA.size()==0)
5299 chainToReverseA.add(vPrev);
5300 chainToReverseA.add(vHere);
5301 }
5302 }
5303 for (int i=(remainingChain.indexOf(deepestVrtRemainingChain)-1);i>-1;i--)
5304 {
5305 Vertex vPrev = remainingChain.get(i+1);
5306 Vertex vHere = remainingChain.get(i);
5307 if (!vPrev.getChilddren().contains(vHere))
5308 {
5309 if (chainToReverseB.size()==0)
5310 chainToReverseB.add(vPrev);
5311 chainToReverseB.add(vHere);
5312 }
5313 }
5314
5315 // These are to remember all chords that will have to be recreated
5316 LinkedHashMap<Vertex,Vertex> chordsToRecreate =
5317 new LinkedHashMap<Vertex,Vertex>();
5318 LinkedHashMap<Vertex,BondType> chordsToRecreateBB =
5319 new LinkedHashMap<Vertex,BondType>();
5320
5321 // Change direction of those edges that have to be reversed as a
5322 // consequence of the change in the spanning tree.
5323 if (chainToReverseA.size()+chainToReverseB.size() > 1)
5324 {
5325 List<Vertex> chainToWorkOn = null;
5326 for (int ic=0; ic<2; ic++)
5327 {
5328 if (ic == 1)
5329 chainToWorkOn = chainToReverseA;
5330 else
5331 chainToWorkOn = chainToReverseB;
5332
5333 for (int i=1; i<chainToWorkOn.size(); i++)
5334 {
5335 Vertex vHere = chainToWorkOn.get(i);
5336 Vertex vPrev = chainToWorkOn.get(i-1);
5337 List<Ring> ringsToRecreate = new ArrayList<>();
5338 for (Ring r : getRingsInvolvingVertex(vHere))
5339 {
5340 ringsToRecreate.add(r);
5341 chordsToRecreate.put(r.getHeadVertex(),
5342 r.getTailVertex());
5343 chordsToRecreateBB.put(r.getHeadVertex(),
5344 r.getBondType());
5345 }
5346 for (Ring r : ringsToRecreate)
5347 {
5348 removeRing(r);
5349 }
5350
5351 Edge edgeToPrevious = vHere.getEdgeWith(vPrev);
5352 if (edgeToPrevious == null)
5353 {
5354 // Since we have already made the new edge this should
5355 // never happen.
5356 String debugFile = "debug_"+v.getVertexId()+".json";
5357 DenoptimIO.writeGraphToJSON(new File(debugFile), this);
5358 throw new DENOPTIMException("Unconnected vertices "
5359 + vHere.getVertexId() + " and "
5360 + vPrev.getVertexId() + ". Unable to deal with "
5361 + "removal of " + v + " from ring " + frame
5362 + " in graph " + this.getGraphId()
5363 + ". See graph in " + debugFile);
5364 } else {
5365 if (edgeToPrevious.getSrcAP().getOwner() == vHere)
5366 {
5367 // This is an edge that has to be reversed.
5368 AttachmentPoint newSrcAP =
5369 edgeToPrevious.getTrgAP();
5370 AttachmentPoint newTrgAP =
5371 edgeToPrevious.getSrcAP();
5372 if (newSrcAP.getAPClass().isCPMapCompatibleWith(
5373 newTrgAP.getAPClass(), fragSpace))
5374 {
5375 BondType oldBt = edgeToPrevious.getBondType();
5376 removeEdge(edgeToPrevious);
5377 addEdge(new Edge(newSrcAP, newTrgAP,
5378 oldBt));
5379 } else {
5380 // There is a non-reversible connection along
5381 // the way, therefore we cannot do this
5382 // specific mutation.
5383 return false;
5384 }
5385 }
5386 }
5387 }
5388 }
5389 }
5390
5391 // Delete the chain to be removed
5392 for (Vertex vtr : toRemoveChain)
5393 {
5394 // This works across template boundaries!
5395 for (Vertex child : vtr.getChildrenThroughout())
5396 {
5397 if (remainingChain.contains(child)
5398 || toRemoveChain.contains(child))
5399 continue;
5400 DGraph ownerOfChild = child.getGraphOwner();
5401 ownerOfChild.removeVertex(child);
5402 }
5403 if (templateJacket!= null)
5404 {
5405 List<AttachmentPoint> apProjectionsToRemove =
5406 new ArrayList<AttachmentPoint>();
5407 for (AttachmentPoint outerAP :
5409 {
5410 AttachmentPoint innerAP =
5412 if (innerAP.getOwner() == vtr)
5413 {
5414 apProjectionsToRemove.add(innerAP);
5415 }
5416 }
5417 for (AttachmentPoint apToRemove : apProjectionsToRemove)
5419 }
5420 removeVertex(vtr);
5421 }
5422
5423 // Regenerate the rings that have been affected
5424 for (Vertex h : chordsToRecreate.keySet())
5425 {
5426 addRing(h, chordsToRecreate.get(h), chordsToRecreateBB.get(h));
5427 }
5428
5429 // Symmetry relation need to be compared with the change of topology.
5430 // The worst that can happen is that two vertices that are
5431 // listed as symmetric are, instead, one the (grand)parent of
5432 // the other. This is inconsistent with the expectations when
5433 // dealing with any operation with symmetric vertices.
5434 // A different level does NOT imply a parent-child relation,
5435 // but is a sign that the topology has changed substantially,
5436 // and that the symmetric relation is, most likely, not sensible
5437 // anymore.
5438 List<SymmetricVertexes> ssToRemove = new ArrayList<SymmetricVertexes>();
5439 Iterator<SymmetricVertexes> ssIter = getSymSetsIterator();
5440 while (ssIter.hasNext())
5441 {
5442 SymmetricVertexes ss = ssIter.next();
5443 int level = -2;
5444 for (Vertex vrt : ss)
5445 {
5446 if (level==-2)
5447 {
5448 level = getLevel(vrt);
5449 } else {
5450 if (level != getLevel(vrt))
5451 {
5452 ssToRemove.add(ss);
5453 break;
5454 }
5455 }
5456 }
5457 }
5458 for (SymmetricVertexes ss : ssToRemove)
5460
5461 // The free-ed up APs need to be projected to template's surface
5462 if (templateJacket!= null)
5463 {
5464 for (AttachmentPoint innerAP : getAvailableAPs())
5465 {
5467 }
5468 }
5469
5470 return true;
5471 }
5472
5473//------------------------------------------------------------------------------
5474
5480 @Deprecated
5482 {
5483 HashMap<Long, Long> nmap = new HashMap<>();
5484 for (int i=0; i<getVertexCount(); i++)
5485 {
5486 long vid = getVertexList().get(i).getVertexId();
5487 long nvid = -vid;
5488 nmap.put(vid, nvid);
5489
5490 getVertexList().get(i).setVertexId(nvid);
5491
5492 for (int j=0; j<getEdgeCount(); j++)
5493 {
5494 Edge e = getEdgeList().get(j);
5495 if (e.getSrcVertex() == vid) {
5496 e.getSrcAP().getOwner().setVertexId(nvid);
5497 }
5498 if (e.getTrgVertex() == vid) {
5499 e.getTrgAP().getOwner().setVertexId(nvid);
5500 }
5501 }
5502 }
5503 }
5504
5505//------------------------------------------------------------------------------
5506
5513 {
5515 }
5516
5517//------------------------------------------------------------------------------
5518
5525 public Map<Long,Long> renumberVerticesGetMap()
5526 {
5527 Map<Long, Long> nmap = new HashMap<>();
5528
5529 // for the vertices in the graph, get new vertex ids
5530 for (int i=0; i<getVertexCount(); i++)
5531 {
5532 Vertex v = getVertexList().get(i);
5533 long vid = v.getVertexId();
5534 long nvid = GraphUtils.getUniqueVertexIndex();
5535
5536 nmap.put(vid, nvid);
5537
5538 v.setVertexId(nvid);
5540 }
5541
5542 return nmap;
5543 }
5544
5545//------------------------------------------------------------------------------
5546
5555 public int getLevel(Vertex v)
5556 {
5557 ArrayList<Vertex> parentTree = new ArrayList<>();
5558 getParentTree(v,parentTree);
5559 return parentTree.size() - 1;
5560 }
5561
5562//------------------------------------------------------------------------------
5563
5582 public Object[] checkConsistency(RunTimeParameters settings)
5583 throws DENOPTIMException
5584 {
5585 return checkConsistency(settings, false);
5586 }
5587
5588//------------------------------------------------------------------------------
5589
5613 public Object[] checkConsistency(RunTimeParameters settings, boolean permissive)
5614 throws DENOPTIMException
5615 {
5617 if (settings.containsParameters(ParametersType.RC_PARAMS))
5618 {
5619 rcSettings = (RingClosureParameters)settings.getParameters(
5621 }
5623 if (settings.containsParameters(ParametersType.FS_PARAMS))
5624 {
5625 fsSettings = (FragmentSpaceParameters)settings.getParameters(
5627 }
5628
5629 // calculate the molecule representation
5630 ThreeDimTreeBuilder t3d = new ThreeDimTreeBuilder(settings.getLogger(),
5631 settings.getRandomizer());
5632 t3d.setAlignBBsIn3D(false);
5633 IAtomContainer mol = t3d.convertGraphTo3DAtomContainer(this,true);
5634 if (mol == null)
5635 {
5636 String msg ="Evaluation of graph: graph-to-mol returned null!"
5637 + toString();
5638 settings.getLogger().log(Level.FINE, msg);
5639 return null;
5640 }
5641
5642 // check if the molecule is connected
5643 boolean isConnected = ConnectivityChecker.isConnected(mol);
5644 if (!isConnected)
5645 {
5646 String msg = "Evaluation of graph: Not all connected"
5647 + toString();
5648 settings.getLogger().log(Level.FINE, msg);
5649 return null;
5650 }
5651
5652 // SMILES
5653 String smiles = null;
5654 smiles = MoleculeUtils.getSMILESForMolecule(mol,settings.getLogger());
5655 if (smiles == null)
5656 {
5657 String msg = "Evaluation of graph: SMILES is null! "
5658 + toString();
5659 settings.getLogger().log(Level.FINE, msg);
5660 smiles = "FAIL: NO SMILES GENERATED";
5661 }
5662 // if by chance the smiles indicates a disconnected molecule
5663 if (smiles.contains(".") && !permissive)
5664 {
5665 String msg = "Evaluation of graph: SMILES contains \".\"" + smiles;
5666 settings.getLogger().log(Level.FINE, msg);
5667 return null;
5668 }
5669
5670 // criteria from definition of Fragment space
5671 // 1A) number of heavy atoms
5672 if (fsSettings.getMaxHeavyAtom()>0 && !permissive)
5673 {
5675 fsSettings.getMaxHeavyAtom())
5676 {
5677 String msg = "Evaluation of graph: Max atoms constraint "
5678 + " violated: " + smiles;
5679 settings.getLogger().log(Level.FINE, msg);
5680 return null;
5681 }
5682 }
5683
5684 // 1B) molecular weight
5685 double mw = MoleculeUtils.getMolecularWeight(mol);
5686 if (fsSettings.getMaxMW()>0 && !permissive)
5687 {
5688 if (mw > fsSettings.getMaxMW())
5689 {
5690 String msg = "Evaluation of graph: Molecular weight "
5691 + "constraint violated: " + smiles + " | MW: " + mw;
5692 settings.getLogger().log(Level.FINE, msg);
5693 return null;
5694 }
5695 }
5696 mol.setProperty("MOL_WT", mw);
5697
5698 // 1C) number of rotatable bonds
5700 if (fsSettings.getMaxRotatableBond()>0 && !permissive)
5701 {
5702 if (nrot > fsSettings.getMaxRotatableBond())
5703 {
5704 String msg = "Evaluation of graph: Max rotatable bonds "
5705 + "constraint violated: "+ smiles;
5706 settings.getLogger().log(Level.FINE, msg);
5707 return null;
5708 }
5709 }
5710 mol.setProperty("ROT_BND", nrot);
5711
5712 // 1D) unacceptable free APs
5713 if (fsSettings.getFragmentSpace().useAPclassBasedApproach())
5714 {
5715 if (hasForbiddenEnd(fsSettings))
5716 {
5717 String msg = "Evaluation of graph: forbidden end in graph!";
5718 settings.getLogger().log(Level.FINE, msg);
5719 return null;
5720 }
5721 }
5722
5723 // criteria from settings of ring closures
5724 if (rcSettings.allowRingClosures() && !permissive)
5725 {
5726 // Count rings and RCAs
5727 int nPossRings = 0;
5728 Set<String> doneType = new HashSet<>();
5729 Map<String,String> rcaTypes = RingClosingAttractor.RCATYPEMAP;
5730 for (String rcaTyp : rcaTypes.keySet())
5731 {
5732 if (doneType.contains(rcaTyp))
5733 {
5734 continue;
5735 }
5736
5737 int nThisType = 0;
5738 int nCompType = 0;
5739 for (Vertex v : getRCVertices())
5740 {
5741 if (v.containsAtoms())
5742 {
5743 IAtom atm = v.getIAtomContainer().getAtom(0);
5744 if (MoleculeUtils.getSymbolOrLabel(atm).equals(rcaTyp))
5745 {
5746 nThisType++;
5747 } else if (MoleculeUtils.getSymbolOrLabel(atm).equals(
5748 rcaTypes.get(rcaTyp)))
5749 {
5750 nCompType++;
5751 }
5752 if (rcaTyp.equals(rcaTypes.get(rcaTyp)))
5753 {
5754 nCompType++;
5755 }
5756 }
5757 }
5758
5759 // check number of rca per type
5760 if (nThisType > rcSettings.getMaxRcaPerType(rcaTyp) ||
5761 nCompType > rcSettings.getMaxRcaPerType(rcaTyp))
5762 {
5763 String msg = "Evaluation of graph: too many RCAs! "
5764 + rcaTyp + ":" + nThisType + " "
5765 + rcaTypes.get(rcaTyp) + ":" + nCompType;
5766 settings.getLogger().log(Level.FINE, msg);
5767 return null;
5768 }
5769 if (nThisType < rcSettings.getMinRcaPerType(rcaTyp) ||
5770 nCompType < rcSettings.getMinRcaPerType(rcaTyp))
5771 {
5772 String msg = "Evaluation of graph: too few RCAs! "
5773 + rcaTyp + ":" + nThisType + " "
5774 + rcaTypes.get(rcaTyp) + ":" + nCompType;
5775 settings.getLogger().log(Level.FINE, msg);
5776 return null;
5777 }
5778
5779 nPossRings = nPossRings + Math.min(nThisType, nCompType);
5780 doneType.add(rcaTyp);
5781 doneType.add(rcaTypes.get(rcaTyp));
5782 }
5783 if (nPossRings < rcSettings.getMinRingClosures())
5784 {
5785 String msg = "Evaluation of graph: too few ring candidates";
5786 settings.getLogger().log(Level.FINE, msg);
5787 return null;
5788 }
5789 }
5790
5791 // get the smiles/Inchi representation
5792 String inchiKey = MoleculeUtils.getInChIKeyForMolecule(mol,
5793 settings.getLogger());
5794 if (inchiKey == null)
5795 {
5796 String msg = "Evaluation of graph: InChI Key is null!";
5797 settings.getLogger().log(Level.WARNING, msg);
5798 inchiKey = "UNDEFINED_INCHI";
5799 }
5800
5801 Object[] res = new Object[3];
5802 res[0] = inchiKey;
5803 res[1] = smiles;
5804 res[2] = mol;
5805
5806 return res;
5807 }
5808
5809//------------------------------------------------------------------------------
5810
5818 public ArrayList<DGraph> makeAllGraphsWithDifferentRingSets(
5819 RunTimeParameters settings)
5820 throws DENOPTIMException
5821 {
5823 if (settings.containsParameters(ParametersType.RC_PARAMS))
5824 {
5825 rcSettings = (RingClosureParameters)settings.getParameters(
5827 }
5829 if (settings.containsParameters(ParametersType.FS_PARAMS))
5830 {
5831 fsSettings = (FragmentSpaceParameters)settings.getParameters(
5833 }
5834 ArrayList<DGraph> lstGraphs = new ArrayList<>();
5835
5836 boolean rcnEnabled = fsSettings.getFragmentSpace()
5838 if (!rcnEnabled)
5839 return lstGraphs;
5840
5841 boolean evaluateRings = rcSettings.allowRingClosures();
5842 if (!evaluateRings)
5843 return lstGraphs;
5844
5845 // get a atoms/bonds molecular representation (no 3D needed)
5846 ThreeDimTreeBuilder t3d = new ThreeDimTreeBuilder(settings.getLogger(),
5847 settings.getRandomizer());
5848 t3d.setAlignBBsIn3D(false);
5849 IAtomContainer mol = t3d.convertGraphTo3DAtomContainer(this,false);
5850
5851 // Set rotatable property as property of IBond
5853 fsSettings.getRotSpaceDefFile(), true, true,
5854 settings.getLogger());
5855
5856 // get the set of possible RCA combinations = ring closures
5857 CyclicGraphHandler cgh = new CyclicGraphHandler(rcSettings,
5858 fsSettings.getFragmentSpace());
5859 ArrayList<List<Ring>> allCombsOfRings =
5860 cgh.getPossibleCombinationOfRings(mol, this);
5861
5862 // Keep closable chains that are relevant for chelate formation
5863 if (rcSettings.buildChelatesMode())
5864 {
5865 ArrayList<List<Ring>> toRemove = new ArrayList<>();
5866 for (List<Ring> setRings : allCombsOfRings)
5867 {
5868 if (!cgh.checkChelatesGraph(this,setRings))
5869 {
5870 toRemove.add(setRings);
5871 }
5872 }
5873 allCombsOfRings.removeAll(toRemove);
5874 }
5875
5876 // prepare output graphs
5877 for (List<Ring> ringSet : allCombsOfRings)
5878 {
5879 // clone root graph
5880 DGraph newGraph = this.clone();
5881
5882 Map<Long,Long> vRenum = newGraph.renumberVerticesGetMap();
5884
5885 // add rings
5886 for (Ring oldRing : ringSet)
5887 {
5888 Ring newRing = new Ring();
5889 for (int i=0; i<oldRing.getSize(); i++)
5890 {
5891 long oldVId = oldRing.getVertexAtPosition(i).getVertexId();
5892 long newVId = vRenum.get(oldVId);
5893 newRing.addVertex(newGraph.getVertexWithId(newVId));
5894 }
5895 newRing.setBondType(oldRing.getBondType());
5896 newGraph.addRing(newRing);
5897 }
5898
5899 // store
5900 lstGraphs.add(newGraph);
5901 }
5902
5903 return lstGraphs;
5904 }
5905
5906//------------------------------------------------------------------------------
5907
5915 public boolean hasForbiddenEnd(FragmentSpaceParameters fsSettings)
5916 {
5917 List<Vertex> vertices = getVertexList();
5918 Set<APClass> classOfForbEnds =
5920 boolean found = false;
5921 for (Vertex vtx : vertices)
5922 {
5923 List<AttachmentPoint> daps = vtx.getAttachmentPoints();
5924 for (AttachmentPoint dp : daps)
5925 {
5926 if (dp.isAvailable())
5927 {
5928 APClass apClass = dp.getAPClass();
5929 if (classOfForbEnds.contains(apClass))
5930 {
5931 found = true;
5932 String msg = "Forbidden free AP for Vertex: "
5933 + vtx.getVertexId() + " "
5934 + vtx.toString()
5935 + "\n"+ this +" \n "
5936 + " AP class: " + apClass;
5937 fsSettings.getLogger().log(Level.WARNING, msg);
5938 break;
5939 }
5940 }
5941 }
5942 if (found)
5943 {
5944 break;
5945 }
5946 }
5947
5948 return found;
5949 }
5950
5951//------------------------------------------------------------------------------
5952
5972 public void appendGraphOnGraph(List<Vertex> parentVertices,
5973 List<Integer> parentAPIdx,
5974 DGraph subGraph,
5975 Vertex childVertex, int childAPIdx,
5976 BondType bndType, boolean onAllSymmAPs)
5977 throws DENOPTIMException
5978 {
5979 // Collector for symmetries created by appending copies of subGraph
5980 Map<Vertex, SymmetricVertexes> newSymSets = new HashMap<>();
5981
5982 // Repeat append for each parent vertex while collecting symmetries
5983 for (int i=0; i<parentVertices.size(); i++)
5984 {
5985 appendGraphOnGraph(parentVertices.get(i), parentAPIdx.get(i),
5986 subGraph, childVertex, childAPIdx, bndType,
5987 newSymSets, onAllSymmAPs);
5988 }
5989 }
5990
5991//------------------------------------------------------------------------------
5992
6006 AttachmentPoint trgAP) throws DENOPTIMException
6007 {
6008 if (!srcAP.isAvailable())
6009 {
6010 //TODO-gg del
6011 DenoptimIO.writeGraphToJSON(new File("/tmp/failing.json"),
6012 srcAP.getOwner().getGraphOwner().getOutermostGraphOwner());
6013 throw new DENOPTIMException("Attempt to use unavailable "
6014 + "attachment point " + srcAP + " on vertex "
6015 + srcAP.getOwner().getVertexId() + " as srcAP.");
6016 }
6017 if ( !trgAP.isAvailable())
6018 {
6019 throw new DENOPTIMException("Attempt to use unavailable "
6020 + "attachment point " + trgAP + " on vertex "
6021 + trgAP.getOwner().getVertexId() + " as trgAP.");
6022 }
6023
6024 BondType btSrc = srcAP.getBondType();
6025 BondType btTrg = trgAP.getBondType();
6026 BondType bndTyp = btSrc;
6027 if (btSrc != btTrg)
6028 {
6029 if (btSrc == BondType.ANY && btTrg != BondType.ANY)
6030 {
6031 bndTyp = btTrg;
6032 } else {
6033 if (btSrc != BondType.ANY && btTrg == BondType.ANY)
6034 {
6035 bndTyp = btSrc;
6036 } else {
6037 bndTyp = BondType.UNDEFINED;
6038 }
6039 }
6040 }
6041
6042 this.addVertex(trgAP.getOwner());
6043 Edge edge = new Edge(srcAP,trgAP, bndTyp);
6044 addEdge(edge);
6045 }
6046
6047//------------------------------------------------------------------------------
6048
6058 public void appendGraphOnAP(AttachmentPoint apOnThisGraph,
6059 AttachmentPoint apOnIncomingGraph, BondType bndType)
6060 throws DENOPTIMException
6061 {
6062 DGraph incomingGraph = apOnIncomingGraph.getOwner().getGraphOwner();
6063 incomingGraph.renumberGraphVertices();
6064
6065 Edge edge = new Edge(apOnThisGraph, apOnIncomingGraph,
6066 bndType);
6067 addEdge(edge);
6068
6069 //Import vertices
6070 for (Vertex incomingVrtx : incomingGraph.getVertexList())
6071 {
6072 addVertex(incomingVrtx);
6073 }
6074
6075 //Import edges
6076 for (Edge incomingEdge : incomingGraph.getEdgeList())
6077 {
6078 addEdge(incomingEdge);
6079 }
6080
6081 //Import rings
6082 for (Ring incomingRing : incomingGraph.getRings())
6083 {
6084 addRing(incomingRing);
6085 }
6086
6087 incomingGraph.cleanup();
6088 }
6089
6090//------------------------------------------------------------------------------
6091
6112 public void appendGraphOnAP(Vertex parentVertex, int parentAPIdx,
6113 DGraph subGraph,
6114 Vertex childVertex, int childAPIdx,
6115 BondType bndType,
6116 Map<Vertex, SymmetricVertexes> newSymSets)
6117 throws DENOPTIMException
6118 {
6119 // Clone and renumber the subgraph to ensure uniqueness
6120 DGraph sgClone = subGraph.clone();
6121 // The clones have the same vertex IDs before renumbering vertices
6122 Vertex cvClone = sgClone.getVertexWithId(
6123 childVertex.getVertexId());
6124 sgClone.renumberGraphVertices();
6125
6126 Edge edge = new Edge(parentVertex.getAP(parentAPIdx),
6127 cvClone.getAP(childAPIdx), bndType);
6128 addEdge(edge);
6129
6130 // Import all vertices from cloned subgraph, i.e., sgClone
6131 for (int i=0; i<sgClone.getVertexList().size(); i++)
6132 {
6133 Vertex clonV = sgClone.getVertexList().get(i);
6134 Vertex origV = subGraph.getVertexList().get(i);
6135
6136 addVertex(sgClone.getVertexList().get(i));
6137
6138 // also need to tmp store pointers to symmetric vertices
6139 // Why is this working on subGraph and not on sgClone?
6140 // Since we are only checking is there is symmetry, there should be
6141 // no difference between doing it on sgClone or subGraph.
6142 if (subGraph.hasSymmetryInvolvingVertex(origV))
6143 {
6144 if (newSymSets.containsKey(origV))
6145 {
6146 newSymSets.get(origV).add(clonV);
6147 }
6148 else
6149 {
6150 newSymSets.put(origV, sgClone.getSymSetForVertex(clonV));
6151 }
6152 }
6153 else
6154 {
6155 if (newSymSets.containsKey(origV))
6156 {
6157 newSymSets.get(origV).add(clonV);
6158 }
6159 else
6160 {
6162 ss.add(clonV);
6163 newSymSets.put(origV, ss);
6164 }
6165 }
6166 }
6167 // Import all edges from cloned subgraph
6168 for (int i=0; i<sgClone.getEdgeList().size(); i++)
6169 {
6170 addEdge(sgClone.getEdgeList().get(i));
6171 }
6172 // Import all rings from cloned subgraph
6173 for (int i=0; i<sgClone.getRings().size(); i++)
6174 {
6175 addRing(sgClone.getRings().get(i));
6176 }
6177
6178 // project tmp symmetric set into final symmetric sets
6179 Set<SymmetricVertexes> doneTmpSymSets = new HashSet<SymmetricVertexes>();
6180 for (Map.Entry<Vertex, SymmetricVertexes> e : newSymSets.entrySet())
6181 {
6182 SymmetricVertexes tmpSS = e.getValue();
6183 if (doneTmpSymSets.contains(tmpSS))
6184 {
6185 continue;
6186 }
6187 doneTmpSymSets.add(tmpSS);
6188 boolean done = false;
6189 // NB: no need to check all entries of tmpSS: the first is enough
6190 SymmetricVertexes oldSS;
6191 Iterator<SymmetricVertexes> iter = getSymSetsIterator();
6192 while (iter.hasNext())
6193 {
6194 oldSS = iter.next();
6195 if (oldSS.contains(tmpSS.get(0)))
6196 {
6197 oldSS.addAll(tmpSS);
6198 done = true;
6199 break;
6200 }
6201 }
6202 if (!done)
6203 {
6204 if (tmpSS.size() <= 1)
6205 {
6206 // tmpSS has always at least one entry: the initial vrtx
6207 continue;
6208 }
6209 //Move tmpSS into a new SS on molGraph
6211 newSS.addAll(tmpSS);
6213 }
6214 }
6215 }
6216
6217//------------------------------------------------------------------------------
6218
6237 public void appendGraphOnGraph(Vertex parentVertex,
6238 int parentAPIdx, DGraph subGraph,
6239 Vertex childVertex, int childAPIdx,
6240 BondType bndType,
6241 Map<Vertex, SymmetricVertexes> newSymSets,
6242 boolean onAllSymmAPs)
6243 throws DENOPTIMException
6244 {
6245 SymmetricAPs symAPs = parentVertex.getSymmetricAPs(
6246 parentVertex.getAP(parentAPIdx));
6247 if (symAPs.size()!=0 && onAllSymmAPs)
6248 {
6249 for (AttachmentPoint symAP : symAPs)
6250 {
6251 if (!symAP.isAvailable())
6252 {
6253 continue;
6254 }
6255 appendGraphOnAP(parentVertex, symAP.getIndexInOwner(),
6256 subGraph, childVertex,
6257 childAPIdx, bndType, newSymSets);
6258 }
6259 } else {
6260 appendGraphOnAP(parentVertex, parentAPIdx, subGraph, childVertex,
6261 childAPIdx, bndType, newSymSets);
6262 }
6263 }
6264
6265//-----------------------------------------------------------------------------
6266
6274 public List<Long> findVerticesIds(VertexQuery query, Logger logger)
6275 {
6276 List<Long> matches = new ArrayList<>();
6277 for (Vertex v : findVertices(query, logger))
6278 {
6279 matches.add(v.getVertexId());
6280 }
6281 return matches;
6282 }
6283
6284//-----------------------------------------------------------------------------
6285
6294 public ArrayList<Vertex> findVertices(VertexQuery vrtxQuery, Logger logger)
6295 {
6296 return findVertices(vrtxQuery, true,logger);
6297 }
6298
6299//-----------------------------------------------------------------------------
6300
6311 public ArrayList<Vertex> findVertices(VertexQuery vrtxQuery,
6312 boolean purgeSym, Logger logger)
6313 {
6314 ArrayList<Vertex> matches = new ArrayList<>(getVertexList());
6315
6316 logger.log(Level.FINE, "Candidates: " + matches);
6317
6318 //Check condition vertex ID
6319 Long vidQuery = vrtxQuery.getVertexIDQuery();
6320 if (vidQuery != null)
6321 {
6322 ArrayList<Vertex> newLst = new ArrayList<>();
6323 for (Vertex v : matches)
6324 {
6325 if (v.getVertexId() == vidQuery.intValue())
6326 {
6327 newLst.add(v);
6328 }
6329 }
6330 matches = newLst;
6331 }
6332 logger.log(Level.FINE," After filtering by vertex ID: " + matches);
6333
6334 //Check condition vertex type (NB: essentially the vertex implementation
6335 VertexType vtQuery = vrtxQuery.getVertexTypeQuery();
6336 if (vtQuery != null)
6337 {
6338 ArrayList<Vertex> newLst = new ArrayList<>();
6339 for (Vertex v : matches)
6340 {
6341 if (v.getVertexType() == vtQuery)
6342 {
6343 newLst.add(v);
6344 }
6345 }
6346 matches = newLst;
6347 logger.log(Level.FINER, " After filtering by vertex type: "
6348 + matches);
6349 }
6350
6351 //Check condition building block Type
6352 BBType bbtQuery = vrtxQuery.getVertexBBTypeQuery();
6353 if (bbtQuery != null)
6354 {
6355 ArrayList<Vertex> newLst = new ArrayList<>();
6356 for (Vertex v : matches)
6357 {
6358 if (v.getBuildingBlockType() == bbtQuery)
6359 {
6360 newLst.add(v);
6361 }
6362 }
6363 matches = newLst;
6364 logger.log(Level.FINER, " After filtering by building block "
6365 + "type: " + matches);
6366 }
6367
6368 //Check condition building block ID
6369 Integer bbID = vrtxQuery.getVertexBBIDQuery();
6370 if (bbID != null)
6371 {
6372 ArrayList<Vertex> newLst = new ArrayList<>();
6373 for (Vertex v : matches)
6374 {
6375 if (v.getBuildingBlockId() == bbID.intValue())
6376 {
6377 newLst.add(v);
6378 }
6379 }
6380 matches = newLst;
6381 logger.log(Level.FINER, " After filtering by building block ID: "
6382 + matches);
6383 }
6384
6385 //Check condition: level of vertex
6386 Integer levelQuery = vrtxQuery.getVertexLevelQuery();
6387 if (levelQuery != null)
6388 {
6389 ArrayList<Vertex> newLst = new ArrayList<Vertex>();
6390 for (Vertex v : matches)
6391 {
6392 if (getLevel(v) == levelQuery)
6393 {
6394 newLst.add(v);
6395 }
6396 }
6397 matches = newLst;
6398 logger.log(Level.FINER, " After filtering by level: " + matches);
6399 }
6400
6401 logger.log(Level.FINE, "After all vertex-based filters: " + matches);
6402
6403 List<EdgeQuery> inAndOutEdgeQueries = new ArrayList<>();
6404 inAndOutEdgeQueries.add(vrtxQuery.getInEdgeQuery());
6405 inAndOutEdgeQueries.add(vrtxQuery.getOutEdgeQuery());
6406 for (int i=0; i<2; i++)
6407 {
6408 String inOrOut = "";
6409 if (i==0)
6410 inOrOut = "incoming";
6411 else
6412 inOrOut = "ourgoing";
6413
6414 EdgeQuery edgeQuery = inAndOutEdgeQueries.get(i);
6415 if (edgeQuery == null)
6416 {
6417 continue;
6418 }
6419
6420 EdgeFinder edgeFinder = new EdgeFinder(i-1);
6421
6422 Integer eTrgApIDx = edgeQuery.getTargetAPIdx();
6423 if (eTrgApIDx != null)
6424 {
6425 ArrayList<Vertex> newLst = new ArrayList<>();
6426 for (Vertex v : matches)
6427 {
6428 for (Edge e : edgeFinder.apply(v))
6429 {
6430 if (e.getTrgAPID() == eTrgApIDx)
6431 {
6432 newLst.add(v);
6433 break;
6434 }
6435 }
6436 }
6437 matches = newLst;
6438 logger.log(Level.FINER, " After " + inOrOut
6439 + " edge trgAPID filter: " + matches);
6440 }
6441
6442 Integer eInSrcApIDx = edgeQuery.getSourceAPIdx();
6443 if (eInSrcApIDx != null)
6444 {
6445 ArrayList<Vertex> newLst = new ArrayList<>();
6446 for (Vertex v : matches)
6447 {
6448 for (Edge e : edgeFinder.apply(v))
6449 {
6450 if (e != null && e.getSrcAPID() == eInSrcApIDx)
6451 {
6452 newLst.add(v);
6453 break;
6454 }
6455 }
6456 }
6457 matches = newLst;
6458 logger.log(Level.FINER, " After " + inOrOut
6459 + " edge srcAPID filter: " + matches);
6460 }
6461
6462 if (i==0)
6463 {
6464 Long eSrcVrtID = edgeQuery.getSourceVertexId();
6465 if (eSrcVrtID != null)
6466 {
6467 ArrayList<Vertex> newLst = new ArrayList<>();
6468 for (Vertex v : matches)
6469 {
6470 for (Edge e : edgeFinder.apply(v))
6471 {
6472 if(e.getSrcAP().getOwner().getVertexId()==eSrcVrtID)
6473 {
6474 newLst.add(v);
6475 break;
6476 }
6477 }
6478 }
6479 matches = newLst;
6480 logger.log(Level.FINER, " After " + inOrOut
6481 + " edge src VertexID filter: " + matches);
6482 }
6483 } else if (i==1) {
6484 Long eTrgVrtID = edgeQuery.getTargetVertexId();
6485 if (eTrgVrtID != null)
6486 {
6487 ArrayList<Vertex> newLst = new ArrayList<>();
6488 for (Vertex v : matches)
6489 {
6490 for (Edge e : edgeFinder.apply(v))
6491 {
6492 if(e.getTrgAP().getOwner().getVertexId()==eTrgVrtID)
6493 {
6494 newLst.add(v);
6495 break;
6496 }
6497 }
6498 }
6499 matches = newLst;
6500 logger.log(Level.FINER, " After " + inOrOut
6501 + " edge trg VertexID filter: " + matches);
6502 }
6503 }
6504
6505 BondType btQuery = edgeQuery.getBondType();
6506 if (btQuery != null)
6507 {
6508 ArrayList<Vertex> newLst = new ArrayList<>();
6509 for (Vertex v : matches)
6510 {
6511 for (Edge e : edgeFinder.apply(v))
6512 {
6513 if (e.getBondType() == btQuery)
6514 {
6515 newLst.add(v);
6516 break;
6517 }
6518 }
6519 }
6520 matches = newLst;
6521 logger.log(Level.FINER, " After " + inOrOut
6522 + " edge bond type filter: " + matches);
6523 }
6524
6525 APClass srcAPC = edgeQuery.getSourceAPClass();
6526 if (srcAPC != null)
6527 {
6528 ArrayList<Vertex> newLst = new ArrayList<>();
6529 for (Vertex v : matches)
6530 {
6531 for (Edge e : edgeFinder.apply(v))
6532 {
6533 if (e.getSrcAPClass().equals(srcAPC))
6534 {
6535 newLst.add(v);
6536 break;
6537 }
6538 }
6539 }
6540 matches = newLst;
6541 }
6542
6543 APClass trgAPC = edgeQuery.getTargetAPClass();
6544 if (trgAPC != null)
6545 {
6546 ArrayList<Vertex> newLst = new ArrayList<>();
6547 for (Vertex v : matches)
6548 {
6549 for (Edge e : edgeFinder.apply(v))
6550 {
6551 if (e.getTrgAPClass().equals(trgAPC))
6552 {
6553 newLst.add(v);
6554 break;
6555 }
6556 }
6557 }
6558 matches = newLst;
6559 }
6560 logger.log(Level.FINER, "After all " + inOrOut
6561 + " edge-based filters: " + matches);
6562 }
6563
6564 // Identify symmetric sets and keep only one member
6565 if (purgeSym)
6566 removeSymmetryRedundance(matches);
6567
6568 logger.log(Level.FINE, "Final Matches (after symmetry): " + matches);
6569
6570 return matches;
6571 }
6572
6573//-----------------------------------------------------------------------------
6574
6581 private class EdgeFinder implements Function<Vertex,List<Edge>>
6582 {
6583 private int mode = 0;
6584
6589 public EdgeFinder(int i)
6590 {
6591 mode = i;
6592 }
6593
6594 @Override
6595 public List<Edge> apply(Vertex v)
6596 {
6597 List<Edge> edges = new ArrayList<Edge>();
6598 if (mode < 0)
6599 {
6600 Edge eToParent = v.getEdgeToParent();
6601 if (eToParent != null)
6602 edges.add(eToParent);
6603 } else {
6605 {
6606 if (!ap.isAvailable() && ap.isSrcInUser())
6607 {
6608 edges.add(ap.getEdgeUser());
6609 }
6610 }
6611 }
6612 return edges;
6613 }
6614 }
6615
6616//-----------------------------------------------------------------------------
6617
6624 public void removeSymmetryRedundance(List<Vertex> list)
6625 {
6626 List<Vertex> symRedundant = new ArrayList<>();
6627 Iterator<SymmetricVertexes> itSymm = getSymSetsIterator();
6628 while (itSymm.hasNext())
6629 {
6630 SymmetricVertexes ss = itSymm.next();
6631 for (Vertex v : list)
6632 {
6633 if (symRedundant.contains(v))
6634 {
6635 continue;
6636 }
6637 if (ss.contains(v))
6638 {
6639 symRedundant.addAll(ss);
6640 symRedundant.remove(v);
6641 }
6642 }
6643 }
6644 for (Vertex v : symRedundant)
6645 {
6646 list.remove(v);
6647 }
6648 }
6649
6650//-----------------------------------------------------------------------------
6651
6658 public void removeSymmetryRedundantIds(ArrayList<Long> list) {
6659 ArrayList<Vertex> vList = new ArrayList<>();
6660 for (long vid : list) {
6661 vList.add(getVertexWithId(vid));
6662 }
6664 list.clear();
6665 for (Vertex v : vList) {
6666 list.add(v.getVertexId());
6667 }
6668 }
6669
6670//------------------------------------------------------------------------------
6671
6685 public DGraph editGraph(ArrayList<GraphEdit> edits,
6686 boolean symmetry, FragmentSpace fragSpace, Logger logger)
6687 throws DENOPTIMException
6688 {
6689 DGraph modGraph = this.clone();
6690
6691 for (GraphEdit edit : edits)
6692 {
6693 logger.log(Level.FINE, "Graph edit task: " + edit.getType());
6694
6695 switch (edit.getType())
6696 {
6697 case REPLACECHILD:
6698 {
6699 DGraph inGraph = edit.getIncomingGraph();
6700 VertexQuery query = edit.getVertexQuery();
6701 int idAPOnInGraph = -1; // Initialization to invalid value
6702 Vertex rootOfInGraph = null;
6703 if (edit.getIncomingAPId() != null)
6704 {
6705 AttachmentPoint ap = inGraph.getAPWithId(
6706 edit.getIncomingAPId().intValue());
6707 if (ap == null)
6708 {
6709 String msg = "Skipping " + edit.getType() + " on "
6710 + "graph " + getGraphId() + ". The incoming"
6711 + " graph has no AP with ID = "
6712 + edit.getIncomingAPId() + ". The IDs of "
6713 + "free APs are:";
6714 for (AttachmentPoint freeAP : inGraph.getAvailableAPs())
6715 {
6716 msg = msg + " " + freeAP.getID();
6717 }
6718 msg = msg + ". "
6719 + "Please, use one of those values in "
6720 + "'idAPOnIncomingGraph'.";
6721 logger.log(Level.WARNING, msg);
6722 }
6723 idAPOnInGraph = ap.getIndexInOwner();
6724 rootOfInGraph = ap.getOwner();
6725 } else {
6726 ArrayList<AttachmentPoint> freeAPs =
6727 inGraph.getAvailableAPs();
6728 if (freeAPs.size()==1)
6729 {
6730 AttachmentPoint ap = freeAPs.get(0);
6731 idAPOnInGraph = ap.getIndexInOwner();
6732 rootOfInGraph = ap.getOwner();
6733 } else {
6734 String geClsName = GraphEdit.class.getSimpleName();
6735 String msg = "Skipping " + edit.getType() + " on "
6736 + "graph " + getGraphId() + ". The incoming"
6737 + " graph has more than one free AP ("
6738 + freeAPs.size() + ") and "
6739 + "the " + geClsName + " "
6740 + "does not provide sufficient information "
6741 + "to unambiguously choose one AP. "
6742 + "Please, add 'idAPOnIncomingGraph' in "
6743 + "the definition of " + geClsName + ".";
6744 logger.log(Level.WARNING, msg);
6745 }
6746 }
6747
6748 ArrayList<Vertex> matches = modGraph.findVertices(query,
6749 false, logger);
6750 for (Vertex vertexToReplace : matches)
6751 {
6752 Edge edgeToParent = vertexToReplace.getEdgeToParent();
6753 if (edgeToParent == null)
6754 {
6755 //The matched vertex has no parent, therefore
6756 // the change would correspond to changing the graph
6757 // completely. This is unlikely the desired effect,
6758 // so we do not do anything.
6759 continue;
6760 }
6761 Vertex parent = vertexToReplace.getParent();
6762 int srcApId = edgeToParent.getSrcAPID();
6763
6764 BondType bondType = edgeToParent.getBondType();
6765
6766 modGraph.removeBranchStartingAt(vertexToReplace,symmetry);
6767
6768 modGraph.appendGraphOnGraph(parent, srcApId, inGraph,
6769 rootOfInGraph, idAPOnInGraph, bondType,
6770 new HashMap<Vertex, SymmetricVertexes>(), symmetry);
6771 }
6772 break;
6773 }
6774 case CHANGEVERTEX:
6775 {
6776 // One of the ways to provide the incoming vertex/subgraph
6777 if (edit.getIncomingBBId() > -1
6778 && edit.getIncomingBBType() != null
6779 && edit.getIncomingGraph() == null)
6780 {
6781 ArrayList<Vertex> matches = modGraph.findVertices(
6782 edit.getVertexQuery(), false, logger);
6783 for (Vertex vertexToChange : matches)
6784 {
6785 if (modGraph.containsVertex(vertexToChange))
6786 {
6787 DGraph graph = vertexToChange.getGraphOwner();
6788 graph.replaceVertex(vertexToChange,
6789 edit.getIncomingBBId(),
6790 edit.getIncomingBBType(),
6791 edit.getAPMappig(),
6792 symmetry,
6793 fragSpace);
6794 }
6795 }
6796 }
6797 // Another of the ways to provide the incoming vertex/subgraph
6798 if (edit.getIncomingGraph() != null
6799 && edit.getIncomingBBType() == null)
6800 {
6801 // Since the replaceSingleSubGraph method below does not
6802 // deal with symmetry, we keep symmetrically-redundant
6803 // matches
6804 ArrayList<Vertex> matches = modGraph.findVertices(
6805 edit.getVertexQuery(), false, logger);
6806
6807 for (Vertex vertexToChange : matches)
6808 {
6809 DGraph graph = vertexToChange.getGraphOwner();
6810 DGraph newSubG = edit.getIncomingGraph().clone();
6811 newSubG.renumberGraphVertices();
6812
6813 LinkedHashMap<AttachmentPoint,AttachmentPoint> apMap =
6814 new LinkedHashMap<AttachmentPoint,AttachmentPoint>();
6815 for (Map.Entry<Integer,Integer> e :
6816 edit.getAPMappig().entrySet())
6817 {
6818 apMap.put(vertexToChange.getAP(e.getKey()),
6819 newSubG.getAvailableAPs().get(
6820 e.getValue()));
6821 }
6822
6823 List<Vertex> oldSubG = new ArrayList<Vertex>();
6824 oldSubG.add(vertexToChange);
6825 graph.replaceSingleSubGraph(oldSubG, newSubG, apMap);
6826 }
6827 }
6828
6829 break;
6830 }
6831 case DELETEVERTEX:
6832 {
6833 ArrayList<Vertex> matches = modGraph.findVertices(
6834 edit.getVertexQuery(), false, logger);
6835 for (Vertex vertexToRemove : matches)
6836 {
6837 if (modGraph.containsVertex(vertexToRemove))
6838 modGraph.removeBranchStartingAt(vertexToRemove,
6839 symmetry);
6840 }
6841 break;
6842 }
6843 }
6844 }
6845 return modGraph;
6846 }
6847
6848//------------------------------------------------------------------------------
6849
6858 public List<Vertex> getMutableSites()
6859 {
6860 List<Vertex> mutableSites = new ArrayList<Vertex>();
6861 for (Vertex v : gVertices)
6862 {
6863 mutableSites.addAll(v.getMutationSites(
6864 new ArrayList<MutationType>()));
6865 }
6866 return mutableSites;
6867 }
6868
6869//------------------------------------------------------------------------------
6870
6882 public List<Vertex> getMutableSites(List<MutationType> ignoredTypes)
6883 {
6884 List<Vertex> mutableSites = new ArrayList<Vertex>();
6885 for (Vertex v : gVertices)
6886 {
6887 mutableSites.addAll(v.getMutationSites(ignoredTypes));
6888 }
6889 return mutableSites;
6890 }
6891
6892//------------------------------------------------------------------------------
6893
6905 public List<Vertex> getSelectedMutableSites(MutationType requestedType)
6906 {
6907 List<Vertex> mutableSites = new ArrayList<Vertex>();
6908 for (Vertex v : gVertices)
6909 {
6910 v.getMutationSites()
6911 .stream()
6912 .filter(vrt -> vrt.getMutationTypes().contains(requestedType))
6913 .forEach(vrt -> mutableSites.add(vrt));
6914 }
6915 return mutableSites;
6916 }
6917
6918//------------------------------------------------------------------------------
6919
6926 public String toJson()
6927 {
6928 Gson gson = DENOPTIMgson.getWriter();
6929 String jsonOutput = gson.toJson(this);
6930 return jsonOutput;
6931 }
6932
6933//------------------------------------------------------------------------------
6934
6935 protected void ensureUniqueApIDs()
6936 {
6938 {
6939 ap.setID(apCounter.getAndIncrement());
6940 }
6941 }
6942
6943//------------------------------------------------------------------------------
6944
6951 public static DGraph fromJson(String json)
6952 {
6953 Gson gson = DENOPTIMgson.getReader();
6954 DGraph graph = gson.fromJson(json, DGraph.class);
6955 return graph;
6956 }
6957
6958//------------------------------------------------------------------------------
6959
6966 public static DGraph fromJson(Reader reader)
6967 {
6968 Gson gson = DENOPTIMgson.getReader();
6969 DGraph graph = gson.fromJson(reader, DGraph.class);
6970 return graph;
6971 }
6972
6973//------------------------------------------------------------------------------
6974
6978 public static class DENOPTIMGraphSerializer
6979 implements JsonSerializer<DGraph>
6980 {
6981 @Override
6982 public JsonElement serialize(DGraph g, Type typeOfSrc,
6983 JsonSerializationContext context)
6984 {
6985 boolean regenerateVrtxID = false;
6986 boolean regenerateAP = false;
6987 Set<Long> unqVrtxIDs = new HashSet<Long>();
6988 Set<Integer> unqApIDs = new HashSet<Integer>();
6989 for (Vertex v : g.getVertexList())
6990 {
6991 if (!unqVrtxIDs.add(v.getVertexId()))
6992 {
6993 regenerateVrtxID = true;
6994 }
6995 for (AttachmentPoint ap : v.getAttachmentPoints())
6996 {
6997 if (!unqApIDs.add(ap.getID()))
6998 {
6999 regenerateAP = true;
7000 break;
7001 }
7002 }
7003 }
7004 if (regenerateVrtxID)
7005 {
7007 }
7008 if (regenerateAP)
7009 {
7011 }
7012
7013 JsonObject jsonObject = new JsonObject();
7014 jsonObject.addProperty("graphId", g.graphId);
7015 jsonObject.add("gVertices", context.serialize(g.gVertices));
7016 jsonObject.add("gEdges", context.serialize(g.gEdges));
7017 jsonObject.add("gRings", context.serialize(g.gRings));
7018 jsonObject.add("symVertices", context.serialize(g.symVertices));
7019 return jsonObject;
7020 }
7021 }
7022
7023 //--------------------------------------------------------------------------
7024
7025 public static class DENOPTIMGraphDeserializer
7026 implements JsonDeserializer<DGraph>
7027 {
7028 @Override
7029 public DGraph deserialize(JsonElement json, Type typeOfT,
7030 JsonDeserializationContext context) throws JsonParseException
7031 {
7032 JsonObject jsonObject = json.getAsJsonObject();
7033
7034 // First, build a graph with a graph ID and a list of vertices
7035 JsonObject partialJsonObj = new JsonObject();
7036 partialJsonObj.add("graphId", jsonObject.get("graphId"));
7037 partialJsonObj.add("gVertices", jsonObject.get("gVertices"));
7038
7039 Gson gson = new GsonBuilder()
7040 .setExclusionStrategies(new DENOPTIMExclusionStrategyNoAPMap())
7041 .registerTypeAdapter(Vertex.class,
7043 .registerTypeAdapter(APClass.class, new APClassDeserializer())
7044 .setPrettyPrinting()
7045 .create();
7046
7047 DGraph graph = gson.fromJson(partialJsonObj, DGraph.class);
7048
7049 // Refresh APs
7050 for (Vertex v : graph.getVertexList())
7051 {
7052 // Regenerate reference to fragment owner
7053 v.setGraphOwner(graph);
7054
7055 for (AttachmentPoint ap : v.getAttachmentPoints())
7056 {
7057 // Regenerate reference to AP owner
7058 ap.setOwner(v);
7059 }
7060 }
7061
7062 // Then, recover those members that are heavily based on references:
7063 // edges, rings.
7064 JsonArray edgeArr = jsonObject.get("gEdges").getAsJsonArray();
7065 for (JsonElement e : edgeArr)
7066 {
7067 JsonObject o = e.getAsJsonObject();
7068 AttachmentPoint srcAP = graph.getAPWithId(
7069 o.get("srcAPID").getAsInt());
7070 AttachmentPoint trgAP = graph.getAPWithId(
7071 o.get("trgAPID").getAsInt());
7072
7073 Edge edge = new Edge(srcAP, trgAP,
7074 context.deserialize(o.get("bondType"),BondType.class));
7075 graph.addEdge(edge);
7076 }
7077
7078 // Now, recover the rings
7079 JsonArray ringArr = jsonObject.get("gRings").getAsJsonArray();
7080 for (JsonElement e : ringArr)
7081 {
7082 JsonObject o = e.getAsJsonObject();
7083 Ring ring = new Ring();
7084 for (JsonElement re : o.get("vertices").getAsJsonArray())
7085 {
7086 ring.addVertex(graph.getVertexWithId(re.getAsInt()));
7087 }
7088 ring.setBondType(context.deserialize(o.get("bndTyp"),
7089 BondType.class));
7090 graph.addRing(ring);
7091 }
7092
7093 //and symmetry relations between vertexes
7094 if (jsonObject.has("symVertices"))
7095 {
7096 for (JsonElement elSet : jsonObject.get("symVertices").getAsJsonArray())
7097 {
7099 for (JsonElement elId : elSet.getAsJsonArray())
7100 {
7101 int id = context.deserialize(elId, Integer.class);
7102 ss.add(graph.getVertexWithId(id));
7103 }
7104 try
7105 {
7106 graph.addSymmetricSetOfVertices(ss);
7107 } catch (DENOPTIMException e1)
7108 {
7109 e1.printStackTrace();
7110 throw new Error("Vertex listed in multiple symmetric "
7111 + "sets. Check this: " + elSet);
7112 }
7113 }
7114 }
7115
7116 return graph;
7117 }
7118 }
7119
7120//------------------------------------------------------------------------------
7121
7129 public static void setScaffold(Vertex v) {
7130 ArrayList<Vertex> newVertexList = new ArrayList<>();
7131
7132 Set<Long> visited = new HashSet<>();
7133 Queue<Vertex> currLevel = new ArrayDeque<>();
7134 Queue<Vertex> nextLevel = new ArrayDeque<>();
7135 currLevel.add(v);
7136
7137 while (!currLevel.isEmpty()) {
7138 Vertex currVertex = currLevel.poll();
7139
7140 long currId = currVertex.getVertexId();
7141 if (!visited.contains(currId)) {
7142 visited.add(currId);
7143
7144 newVertexList.add(currVertex);
7145
7146 Iterable<Vertex> neighbors = currVertex
7148 .stream()
7150 .filter(e -> e != null)
7151 .map(e -> e.getSrcVertex() == currId ?
7152 e.getTrgAP() : e.getSrcAP())
7154 .collect(Collectors.toList());
7155 for (Vertex adj : neighbors) {
7156 nextLevel.add(adj);
7157 }
7158 }
7159
7160 if (currLevel.isEmpty()) {
7161 currLevel = nextLevel;
7162 nextLevel = new ArrayDeque<>();
7163 }
7164 }
7165
7166 v.getGraphOwner().setVertexList(newVertexList);
7167 }
7168
7169//------------------------------------------------------------------------------
7170
7175 public boolean hasScaffoldTypeVertex() {
7176 return getVertexList()
7177 .stream()
7178 .anyMatch(v -> v.getBuildingBlockType() == BBType.SCAFFOLD);
7179 }
7180
7181//------------------------------------------------------------------------------
7182
7188 public void setTemplateJacket(Template template)
7189 {
7190 this.templateJacket = template;
7191 }
7192
7193//------------------------------------------------------------------------------
7194
7199 {
7200 return templateJacket;
7201 }
7202
7203//------------------------------------------------------------------------------
7204
7210 {
7211 if (templateJacket == null)
7212 return this;
7213 else
7215 }
7216
7217//------------------------------------------------------------------------------
7218
7231 public List<Template> getEmbeddingPath()
7232 {
7233 List<Template> path = new ArrayList<Template>();
7234 if (templateJacket==null)
7235 return path;
7236 if (templateJacket.getGraphOwner()!=null)
7238 path.add(templateJacket);
7239 return path;
7240 }
7241
7242//------------------------------------------------------------------------------
7243
7249 {
7250 for (Vertex v : gVertices)
7251 {
7252 v.setProperty(DENOPTIMConstants.STOREDVID, v.getVertexId());
7253 }
7254 }
7255
7256//------------------------------------------------------------------------------
7257
7271 public AttachmentPoint getAPOnLeftVertexID(long nbrVid, long vid)
7272 {
7273 Vertex v1 = getVertexWithId(nbrVid);
7274 Vertex v2 = getVertexWithId(vid);
7275 if ( v1== null || v2 == null)
7276 return null;
7277
7278 if (getChildVertices(v1).contains(v2))
7279 {
7280 return v2.getEdgeToParent().getSrcAP();
7281 } else if (getChildVertices(v2).contains(v1))
7282 {
7283 return v1.getEdgeToParent().getTrgAP();
7284 }
7285
7286 // At this point the two vertices are not directly connected, but there
7287 // could still be a chord between them. Here, we check for chords:
7288 /*
7289 for (DENOPTIMRing r : getRingsInvolvingVertex(v1))
7290 {
7291 if (r.contains(v2))
7292 {
7293 int lstId = r.getSize()-1;
7294 // Position 0 and lstId are where the RCVs sit
7295 if (r.getPositionOf(v1)==1 && r.getPositionOf(v2)==lstId)
7296 {
7297 return r.getHeadVertex().getEdgeToParent().getSrcAP();
7298 }
7299 if (r.getPositionOf(v1)==lstId && r.getPositionOf(v2)==1)
7300 {
7301 return r.getTailVertex().getEdgeToParent().getSrcAP();
7302 }
7303 }
7304 }
7305 */
7306 return null;
7307 }
7308
7309//------------------------------------------------------------------------------
7310
7320 public boolean isReversible(FragmentSpace fragSpace)
7321 {
7322 for (Edge e : gEdges)
7323 {
7324 if (!e.getTrgAPClass().isCPMapCompatibleWith(e.getSrcAPClass(),
7325 fragSpace))
7326 {
7327 return false;
7328 }
7329 }
7330 return true;
7331 }
7332
7333//------------------------------------------------------------------------------
7334
7352 DGraph graphB, List<Template> path)
7353 {
7354 if (path.isEmpty())
7355 return graphY;
7356 Template currentLevelVertex = null;
7357 DGraph currentLevelGraphEmdInB = graphB;
7358 DGraph currentLevelGraphEmbInY = graphY;
7359 for (Template t : path)
7360 {
7361 currentLevelVertex = (Template) currentLevelGraphEmbInY
7362 .getVertexAtPosition(currentLevelGraphEmdInB.indexOf(t));
7363 currentLevelGraphEmdInB = t.getInnerGraph();
7364 currentLevelGraphEmbInY = currentLevelVertex.getInnerGraph();
7365 }
7366 return currentLevelVertex.getInnerGraph();
7367 }
7368
7369//------------------------------------------------------------------------------
7370
7379 public List<AttachmentPoint> getInterfaceAPs(List<Vertex> subGraphB)
7380 {
7381 List<AttachmentPoint> interfaceAPs = new ArrayList<AttachmentPoint>();
7382 for (Vertex v : subGraphB)
7383 {
7384 for (AttachmentPoint ap : v.getAttachmentPoints())
7385 {
7386 if (ap.isAvailableThroughout())
7387 continue;
7388 if (ap.isAvailable())
7389 {
7390 // This AP is used across the template boundary
7391 interfaceAPs.add(ap);
7392 } else {
7393 Vertex user = ap.getLinkedAP().getOwner();
7394 if (!subGraphB.contains(user))
7395 {
7396 // AP used to make a connection to outside subgraph
7397 interfaceAPs.add(ap);
7398 }
7399 }
7400 }
7401 }
7402 return interfaceAPs;
7403 }
7404
7405//------------------------------------------------------------------------------
7406
7414 public List<AttachmentPoint> getSubgraphAPs(
7415 List<Vertex> subGraphB)
7416 {
7417 List<AttachmentPoint> aps = new ArrayList<AttachmentPoint>();
7418 for (Vertex v : subGraphB)
7419 {
7420 for (AttachmentPoint ap : v.getAttachmentPoints())
7421 {
7422 if (ap.isAvailable())
7423 {
7424 aps.add(ap);
7425 continue;
7426 }
7427 Vertex user = ap.getLinkedAP().getOwner();
7428 if (!subGraphB.contains(user))
7429 {
7430 // AP used to make a connection to outside subgraph
7431 aps.add(ap);
7432 }
7433 }
7434 }
7435 return aps;
7436 }
7437
7438//------------------------------------------------------------------------------
7439
7440}
General set of constants used in DENOPTIM.
static final Object GRAPHBRANCHID
Property of Vertex used to record the identity of the graph branch holding that Vertex.
static final Object STOREDVID
Key of the property remembering vertex IDs.
static final Object VRTSYMMSETID
Property of Vertex used to keep mark symmetric vertexes during graph operations and before defining t...
Class defining a space of building blocks.
boolean useAPclassBasedApproach()
Check usage of APClass-based approach, i.e., uses attachment points with annotated data (i....
APClass getAPClassOfCappingVertex(APClass srcApClass)
Parameters defining the fragment space.
boolean isCPMapCompatibleWith(APClass other, FragmentSpace fragSpace)
Check compatibility as defined in the compatibility matrix considering this AP as source and the othe...
Definition: APClass.java:483
BondType getBondType()
Definition: APClass.java:369
String toString()
Do not use this to make SDF representations.
Definition: APClass.java:380
Class representing a mapping between attachment points (APs).
Definition: APMapping.java:42
An attachment point (AP) is a possibility to attach a Vertex onto the vertex holding the AP (i....
AttachmentPoint getLinkedAP()
Gets the attachment point (AP) that is connected to this AP via the edge user.
Object getProperty(Object description)
void setUser(Edge edge)
Sets the reference to the edge that is using this attachment point.
APClass getAPClass()
Returns the Attachment Point class.
int getID()
Returns a unique integer that is used to sort list of attachment points.
BondType getBondType()
Returns the bond type preferred by this attachment point as defined by the APClass,...
boolean isAvailable()
Check availability of this attachment point.
boolean hasConnectedSrcAtom(AttachmentPoint other)
Checks if this and another APs are rooted on atoms that are bonded in any way other than a possible c...
boolean hasSameSrcAtom(AttachmentPoint other)
AttachmentPoint getLinkedAPThroughout()
Gets the attachment point (AP) that is connected to this AP via the edge user or in any edge user tha...
void setProperty(Object key, Object property)
Edge getEdgeUser()
Gets the edge that is using this AP, or null if no edge is using this AP.
A candidate is the combination of a denoptim graph with molecular representation and may include also...
Definition: Candidate.java:40
DGraph deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
Definition: DGraph.java:7029
We expect unique IDs for vertices.
Definition: DGraph.java:6980
JsonElement serialize(DGraph g, Type typeOfSrc, JsonSerializationContext context)
Definition: DGraph.java:6982
Utility to make selection of edges to a vertex tunable by a parameter.
Definition: DGraph.java:6582
List< Edge > apply(Vertex v)
Definition: DGraph.java:6595
Container for the list of vertices and the edges that connect them.
Definition: DGraph.java:102
boolean removeVertexAndWeld(Vertex vertex, FragmentSpace fragSpace)
Remove a given vertex belonging to this graph and re-connects the resulting graph branches as much as...
Definition: DGraph.java:1423
List< ClosableChain > getClosableChains()
Definition: DGraph.java:940
void getChildrenTree(Vertex vertex, List< Vertex > children, int numLayers, boolean stopBeforeRCVs)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:3135
void setTemplateJacket(Template template)
Sets the reference to a template that embeds this graph, i.e., this graph's "jacket" template.
Definition: DGraph.java:7188
void setVertexList(ArrayList< Vertex > vertices)
Definition: DGraph.java:906
String toJson()
Produces a string that represents this graph and that adheres to the JSON format.
Definition: DGraph.java:6926
void getChildTreeLimited(Vertex vertex, List< Vertex > children, Set< Vertex > limits)
Gets all the children of the current vertex recursively until it finds one of the vertices listed as ...
Definition: DGraph.java:3289
ArrayList< Integer > getIndexOfEdgesWithChild(int vid)
Definition: DGraph.java:3520
Candidate candidate
Reference to the candidate entity owning this graph, or null.
Definition: DGraph.java:145
boolean replaceVertex(Vertex vertex, int bbId, BBType bbt, LinkedHashMap< Integer, Integer > apIdMap, FragmentSpace fragSpace)
Replaced a given vertex belonging to this graph with a new vertex generated specifically for this pur...
Definition: DGraph.java:2487
AttachmentPoint getAPOnLeftVertexID(long nbrVid, long vid)
Finds the AP that is on the first given parameter and that is used to make a connection to the second...
Definition: DGraph.java:7271
Vertex getVertexWithId(long vid)
Searches for a vertex with the given identifier.
Definition: DGraph.java:2811
int getSymmetricSetCount()
Returns the number of symmetric sets of vertices.
Definition: DGraph.java:321
Vertex getSourceVertex()
Identifies and return the vertex from which the spanning tree originates.
Definition: DGraph.java:968
List< Integer > getBranchIdOfVertex(Vertex v)
Returns the branch identifier.
Definition: DGraph.java:3187
Edge getEdgeAtPosition(int pos)
Definition: DGraph.java:2878
void getChildrenTree(Vertex vertex, List< Vertex > children, boolean markBranches)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:3033
DGraph embedPatternsInTemplates(GraphPattern pattern, FragmentSpace fragSpace, ContractLevel contract)
Searches for the given pattern type and generated a new graph where each set of (clones of) vertexes ...
Definition: DGraph.java:4866
DGraph extractSubgraph(int index)
Creates a new graph that corresponds to the subgraph of this graph when exploring the spanning tree f...
Definition: DGraph.java:4487
void removeRing(Ring ring)
Definition: DGraph.java:2866
ArrayList< AttachmentPoint > getAttachmentPoints()
Returns the list of all attachment points contained in this graph.
Definition: DGraph.java:4199
boolean containsVertexID(long l)
Checks if a number is already used as VertexIDs within the graph.
Definition: DGraph.java:3578
boolean containsVertex(Vertex v)
Check if this graph contains the specified vertex.
Definition: DGraph.java:2786
boolean isIsomorphicTo(DGraph other)
Checks if this graph is "DENOPTIM-isomorphic" to the other one given.
Definition: DGraph.java:3682
ArrayList< AttachmentPoint > getAvailableAPs()
Returns the list of available attachment points contained in this graph.
Definition: DGraph.java:4217
void setCandidateClosableChains(ArrayList< ClosableChain > closableChains)
Definition: DGraph.java:933
ArrayList< Ring > getRingsInvolvingVertex(Vertex v)
Returns the list of rings that include the given vertex in their fundamental cycle.
Definition: DGraph.java:1054
void addVertex(Vertex vertex)
Appends a vertex to this graph without creating any edge.
Definition: DGraph.java:1325
ArrayList< Ring > getRingsInvolvingVertexID(int vid)
Definition: DGraph.java:1099
int indexOfVertexWithID(long vid)
Returns the position of the first vertex that has the given ID.
Definition: DGraph.java:2827
boolean removeSingleVertexAndWeld(Vertex vertex, FragmentSpace fragSpace)
Remove a given vertex belonging to this graph and re-connects the resulting graph branches as much as...
Definition: DGraph.java:1475
List< ClosableChain > closableChains
The potentially closable chains of vertices.
Definition: DGraph.java:121
DefaultUndirectedGraph< Vertex, UndirectedEdge > jGraph
JGraph representation used to detect DENOPTIM-isomorphism.
Definition: DGraph.java:156
DGraph embedPatternsInTemplates(GraphPattern pattern, FragmentSpace fragSpace)
Searches for the given pattern type and generated a new graph where each set of (clones of) vertexes ...
Definition: DGraph.java:4845
DGraph(List< Vertex > gVertices, List< Edge > gEdges)
Definition: DGraph.java:182
void getChildrenTree(Vertex vertex, List< Vertex > children)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:3000
boolean graphNeedsCappingGroups(FragmentSpace fragSpace)
Checks the graph for unused APs that need to be capped.
Definition: DGraph.java:4293
String getLocalMsg()
Definition: DGraph.java:287
AttachmentPoint getAPWithId(int id)
Returns the attachment point with the given identifier, or null if no AP is found with the given iden...
Definition: DGraph.java:4264
void removeVertex(Vertex vertex)
Remove a vertex from this graph.
Definition: DGraph.java:1347
Iterator< SymmetricVertexes > getSymSetsIterator()
Get an iterator for the sets of symmetrically related vertices.
Definition: DGraph.java:332
void setGraphId(int id)
Definition: DGraph.java:264
void removeSymmetryRedundance(List< Vertex > list)
Remove all but one of the symmetry-related partners in a list of vertices.
Definition: DGraph.java:6624
static void reorderVertexList(DGraph g)
Sets the vertex at the lowest level as the scaffold, changes the directions of edges so that the sc...
Definition: DGraph.java:4946
DGraph extractSubgraph(Vertex seed)
Creates a new graph that corresponds to the subgraph of this graph when exploring the spanning tree f...
Definition: DGraph.java:4506
ArrayList< Vertex > getRCVertices()
Search for ring closing vertices: vertices that contain only a RingClosingAttractor
Definition: DGraph.java:1190
ArrayList< Vertex > getFreeRCVertices()
Search for unused ring closing vertices: vertices that contain only a RingClosingAttractor and are no...
Definition: DGraph.java:1212
void setCandidateOwner(Candidate candidate)
Sets the reference to the candidate item that is defined by this graph.
Definition: DGraph.java:245
List< List< Vertex > > getSymmetricSubGraphs(List< Vertex > subGrpVrtxs)
We assume that the subgraph is a continuously connected, directed graph.
Definition: DGraph.java:2045
DGraph extractSubgraph(Vertex seed, int numLayers, boolean stopBeforeRCVs)
Creates a new graph that corresponds to the subgraph of this graph when exploring the spanning tree f...
Definition: DGraph.java:4532
int indexOf(Vertex v)
Returns the index of a vertex in the list of vertices of this graph.
Definition: DGraph.java:2798
DGraph editGraph(ArrayList< GraphEdit > edits, boolean symmetry, FragmentSpace fragSpace, Logger logger)
Edit this graph according to a given list of edit tasks.
Definition: DGraph.java:6685
List< Vertex > gVertices
The vertices belonging to this graph.
Definition: DGraph.java:106
boolean hasScaffoldTypeVertex()
Checks if this graph contains a scaffold vertex.
Definition: DGraph.java:7175
void setRings(ArrayList< Ring > rings)
Definition: DGraph.java:924
Object[] checkConsistency(RunTimeParameters settings)
Peeks into this graph to derive a preliminary chemical representation with SMILES and InChIKey.
Definition: DGraph.java:5582
Vertex getVertexAtPosition(int pos)
Returns the vertex that is in the given position of the list of vertices belonging to this graph.
Definition: DGraph.java:2743
boolean containsAtoms()
Returns true if this graph has any vertex that contains atoms.
Definition: DGraph.java:4164
List< Edge > getEdgesWithTrg(Vertex v)
Returns the list of edges that arrive from the given vertex, i.e., edges where the trgAP is owned by ...
Definition: DGraph.java:1033
static DGraph getEmbeddedGraphInClone(DGraph graphY, DGraph graphB, List< Template > path)
Searches for a graphs (X) embedded at any level in a graph (Y) by knowing.
Definition: DGraph.java:7351
List< Ring > gRings
The rings defined in this graph.
Definition: DGraph.java:116
int getBondingAPIndex(Vertex srcVert, int dapidx, Vertex dstVert)
Definition: DGraph.java:2954
void setSymmetricVertexSets(List< SymmetricVertexes > symVertices)
Definition: DGraph.java:875
AtomicInteger apCounter
Generator of unique AP identifiers within this graph.
Definition: DGraph.java:172
Vertex getDeepestAmongThese(List< Vertex > list)
Identify the oldest ancestor (i.e., most great grandparent) in the given collection.
Definition: DGraph.java:3352
void appendGraphOnAP(AttachmentPoint apOnThisGraph, AttachmentPoint apOnIncomingGraph, BondType bndType)
Appends a graph onto this graph.
Definition: DGraph.java:6058
static void setScaffold(Vertex v)
Update the graph so that the vertex argument is at the scaffold level i.e.
Definition: DGraph.java:7129
Map< DGraph, ObjectPair > extractPattern(GraphPattern pattern, boolean recordConnectivity)
Extracts subgraphs that match the provided pattern.
Definition: DGraph.java:4717
boolean isReversible(FragmentSpace fragSpace)
Checks is the every edge in the graph can be defined in the opposite direction according to the APCla...
Definition: DGraph.java:7320
String getBranchIdOfVertexAsStr(Vertex v)
Returns the branch identifier as a literal string.
Definition: DGraph.java:3207
List< AttachmentPoint > getAvailableAPsThroughout()
Returns the list of attachment points contained in this graph that are available throughout the templ...
Definition: DGraph.java:4240
boolean directedPathExists(Vertex src, Vertex trg)
Uses branch identifiers to define is two vertices are in such a relation that allows the drawing of a...
Definition: DGraph.java:3229
void appendVertexOnAP(AttachmentPoint srcAP, AttachmentPoint trgAP)
Append a vertex to this graph: adds the new vertex to the list of vertices belonging to the graph,...
Definition: DGraph.java:6005
List< Vertex > getVertexList()
Definition: DGraph.java:947
boolean removeBranchStartingAt(Vertex v)
Deletes the branch, i.e., the specified vertex and its children.
Definition: DGraph.java:5050
static boolean compareGraphNodes(Vertex thisV, DGraph thisG, Vertex otherV, DGraph otherG)
Compares graphs by spanning vertices starting from the given vertex and following the direction of ed...
Definition: DGraph.java:4054
boolean hasSymmetricAP()
Definition: DGraph.java:294
void convertSymmetricLabelsToSymmetricSets()
Looks for any symmetric labels, creates symmetric sets that collect the same information,...
Definition: DGraph.java:1828
DGraph(List< Vertex > gVertices, List< Edge > gEdges, List< Ring > gRings, List< ClosableChain > closableChains, List< SymmetricVertexes > symVertices)
Definition: DGraph.java:218
List< AttachmentPoint > getInterfaceAPs(List< Vertex > subGraphB)
Searches for all AttachmentPoints that represent the interface between a subgraph,...
Definition: DGraph.java:7379
DGraph clone()
Returns almost "deep-copy" of this graph.
Definition: DGraph.java:3415
boolean hasForbiddenEnd(FragmentSpaceParameters fsSettings)
Check if there are forbidden ends: free attachment points that are not suitable for capping and not a...
Definition: DGraph.java:5915
List< DGraph > extractPattern(GraphPattern pattern)
Extracts subgraphs that match the provided pattern.
Definition: DGraph.java:4686
void removeCappingGroups(List< Vertex > lstVerts)
Remove capping groups that belong to this graph and are in the given list.
Definition: DGraph.java:4343
ArrayList< Vertex > getChildVertices(Vertex vertex)
Definition: DGraph.java:2986
boolean sameAsRings(StringBuilder reason, Map< Vertex, Vertex > vertexMap, Ring rT, Vertex vhT, Vertex vtT, Ring rO)
Definition: DGraph.java:4004
DGraph extractSubgraph(Vertex seed, boolean stopBeforeRCVs)
Creates a new graph that corresponds to the subgraph of this graph when exploring the spanning tree f...
Definition: DGraph.java:4643
void renumberGraphVertices()
Reassign vertex IDs to all vertices of this graph.
Definition: DGraph.java:5512
boolean containsOrEmbedsVertex(Vertex v)
Check if the specified vertex is contained in this graph as a node or in any inner graphs that may be...
Definition: DGraph.java:2759
ArrayList< DGraph > makeAllGraphsWithDifferentRingSets(RunTimeParameters settings)
Evaluates the possibility of closing rings in this graph and generates all alternative graphs resulti...
Definition: DGraph.java:5818
static DGraph fromJson(Reader reader)
Reads a JSON string and returns an instance of this class.
Definition: DGraph.java:6966
void addRing(Vertex vI, Vertex vJ, BondType bndTyp)
Adds a chord between the given vertices, thus adding a ring in this graph.
Definition: DGraph.java:1303
List< Vertex > getSymVerticesForVertex(Vertex v)
Definition: DGraph.java:343
static final String SYM_ID
Key used to uniquely identify vertices and attachment points for symmetry detection.
Definition: DGraph.java:178
boolean replaceSubGraph(List< Vertex > subGrpVrtxs, DGraph incomingGraph, LinkedHashMap< AttachmentPoint, AttachmentPoint > apMap, FragmentSpace fragSpace)
Replaced the subgraph represented by a given collection of vertices that belong to this graph.
Definition: DGraph.java:1909
void changeSignOfVertexID()
Change all vertex IDs to the corresponding negative value.
Definition: DGraph.java:5481
static boolean compareGraphNodes(Vertex seedOnA, DGraph gA, Vertex seedOnB, DGraph gB, Map< Vertex, Vertex > vertexMap, StringBuilder reason)
Compares graphs by spanning vertices starting from the given vertex and following the direction of ed...
Definition: DGraph.java:4078
boolean insertSingleVertex(Edge edge, Vertex newLink, LinkedHashMap< AttachmentPoint, AttachmentPoint > apMap)
Inserts a given vertex in between two vertices connected by the given edge.
Definition: DGraph.java:2669
void getChildTreeLimited(Vertex vertex, List< Vertex > children, List< Vertex > limitsInClone, boolean stopBeforeRCVs)
Gets all the children of the current vertex recursively until it finds one of the vertices listed as ...
Definition: DGraph.java:3321
void reassignSymmetricLabels()
Marks the vertices of this graph with a string that is consistent for all vertices that belong to sym...
Definition: DGraph.java:1796
List< Edge > gEdges
The edges belonging to this graph.
Definition: DGraph.java:111
void replaceUnusedRCVsWithCapps(FragmentSpace fragSpace)
Removes unused ring-closing vertices.
Definition: DGraph.java:1754
void appendGraphOnGraph(List< Vertex > parentVertices, List< Integer > parentAPIdx, DGraph subGraph, Vertex childVertex, int childAPIdx, BondType bndType, boolean onAllSymmAPs)
Append a graph (incoming=I) onto this (receiving=R).
Definition: DGraph.java:5972
void setEdgeList(ArrayList< Edge > edges)
Definition: DGraph.java:915
boolean sameAs(DGraph other, StringBuilder reason)
Compare this and another graph ignoring the vertex IDs.
Definition: DGraph.java:3894
int getLevel(Vertex v)
Calculates the level of a vertex in this graph.
Definition: DGraph.java:5555
Vertex getParent(Vertex v)
Definition: DGraph.java:3397
void removeSymmetryRedundantIds(ArrayList< Long > list)
Remove all but one of the symmetry-related partners in a given list of vertex IDs.
Definition: DGraph.java:6658
void removeSymmetrySet(SymmetricVertexes ss)
Tries to determine the set of symmetric vertices in this graph based on finding compatible Vertexes t...
Definition: DGraph.java:848
void storeCurrentVertexIDs()
Copies the current vertexID of each vertex into a property of the vertex itself.
Definition: DGraph.java:7248
void appendGraphOnAP(Vertex parentVertex, int parentAPIdx, DGraph subGraph, Vertex childVertex, int childAPIdx, BondType bndType, Map< Vertex, SymmetricVertexes > newSymSets)
Append a subgraph (I) to this graph (R) specifying which vertex and attachment point to use for the c...
Definition: DGraph.java:6112
static void fixEdgeDirections(DGraph graph)
Flips edges in the graph so that the scaffold is the only source vertex.
Definition: DGraph.java:4962
DGraph getOutermostGraphOwner()
Definition: DGraph.java:7209
void removeCappingGroupsOn(Vertex vertex)
Remove capping groups on the given vertex of this graph.
Definition: DGraph.java:4313
List< Long > findVerticesIds(VertexQuery query, Logger logger)
Search a graph for vertices that match the criteria defined in a query vertex.
Definition: DGraph.java:6274
static DGraph fromJson(String json)
Reads a JSON string and returns an instance of this class.
Definition: DGraph.java:6951
List< Edge > getEdgesWithSrc(Vertex v)
Returns the list of edges that depart from the given vertex, i.e., edges where the srcAP is owned by ...
Definition: DGraph.java:1012
void addRing(Vertex vI, Vertex vJ)
Adds a chord between the given vertices, thus adding a ring in this graph.
Definition: DGraph.java:1275
List< Ring > getRings()
Definition: DGraph.java:999
DGraph extractSubgraph(Collection< Vertex > definedOn, Set< Edge > connectionToSubgraph, Set< Edge > connectionFromSubgraph)
Returns a clone of the subgraph defined by the a collection of vertices belonging to this graph.
Definition: DGraph.java:4787
boolean isVertexIDInRing(int vid)
Definition: DGraph.java:1152
void addSymmetricSetOfVertices(SymmetricVertexes symSet)
Adds a symmetric set of vertices to this graph.
Definition: DGraph.java:889
SymmetricVertexes getSymSetForVertex(Vertex v)
Returns the set of vertexes symmetric to the given one.
Definition: DGraph.java:861
void getParentTree(Vertex vertex, List< Vertex > parentTree)
Traverse the graph until it identifies the source of the directed path reachable from the given verte...
Definition: DGraph.java:3378
void addCappingGroups(FragmentSpace fragSpace)
Add a capping groups on free unused attachment points.
Definition: DGraph.java:4398
DGraph(List< Vertex > gVertices, List< Edge > gEdges, List< Ring > gRings)
Definition: DGraph.java:196
List< Edge > getEdgeList()
Definition: DGraph.java:992
DGraph(List< Vertex > gVertices, List< Edge > gEdges, List< Ring > gRings, List< SymmetricVertexes > symSets)
Definition: DGraph.java:207
void removeCappingGroups()
Remove all capping groups on this graph.
Definition: DGraph.java:4385
void cleanup()
Wipes the data in this graph.
Definition: DGraph.java:3597
boolean hasRings()
Check for rings in this graph.
Definition: DGraph.java:1120
void removeCappingGroupsFromChilds(List< Vertex > lstVerts)
Definition: DGraph.java:4371
Object[] checkConsistency(RunTimeParameters settings, boolean permissive)
Peeks into this graph to derive a preliminary chemical representation with SMILES and InChIKey.
Definition: DGraph.java:5613
List< Vertex > getMutableSites(List< MutationType > ignoredTypes)
A list of mutation sites from within this graph.
Definition: DGraph.java:6882
DefaultUndirectedGraph< Node, NodeConnection > jGraphKernel
JGraph representation used to detect DENOPTIM-isostructural graphs.
Definition: DGraph.java:162
ArrayList< Edge > getEdgesWithChild(int vid)
Definition: DGraph.java:3543
ArrayList< Vertex > findVertices(VertexQuery vrtxQuery, boolean purgeSym, Logger logger)
Filters a list of vertices according to a query.
Definition: DGraph.java:6311
boolean isVertexInRing(Vertex v)
Definition: DGraph.java:1168
List< AttachmentPoint > getSubgraphAPs(List< Vertex > subGraphB)
Searches for all AttachmentPoints that are owned by vertices in a subgraph but either available or us...
Definition: DGraph.java:7414
Candidate getCandidateOwner()
Returns the reference of the candidate item that is defined by this graph.
Definition: DGraph.java:257
List< SymmetricVertexes > symVertices
Definition: DGraph.java:132
void addRing(Ring ring)
Definition: DGraph.java:1258
ArrayList< Ring > getRingsInvolvingVertex(Vertex[] vs)
Returns the list of rings that include the given list of vertices in their fundamental cycle.
Definition: DGraph.java:1075
Map< Long, Long > renumberVerticesGetMap()
Reassign vertex IDs to a graph.
Definition: DGraph.java:5525
boolean hasSymmetryInvolvingVertex(Vertex v)
Definition: DGraph.java:301
static void fixEdgeDirections(Vertex v, Set< Long > visited)
Recursive utility method for fixEdgeDirections(graph).
Definition: DGraph.java:4974
boolean replaceVertex(Vertex vertex, int bbId, BBType bbt, LinkedHashMap< Integer, Integer > apIdMap, boolean symmetry, FragmentSpace fragSpace)
Replaced a given vertex belonging to this graph with a new vertex generated specifically for this pur...
Definition: DGraph.java:2511
ArrayList< Vertex > getUsedRCVertices()
Search for used ring closing vertices: vertices that contain only a RingClosingAttractor and are part...
Definition: DGraph.java:1235
boolean insertVertex(Edge edge, int bbId, BBType bbt, LinkedHashMap< AttachmentPoint, Integer > apMap, FragmentSpace fragSpace)
Inserts a given vertex in between two vertices connected by the given edge.
Definition: DGraph.java:2589
Edge getEdgeWithParent(long l)
Looks for an edge that points to a vertex with the given vertex id.
Definition: DGraph.java:3502
void getChildrenTree(Vertex vertex, List< Vertex > children, AtomicInteger branchIdGenerator, List< Integer > prevBranchId)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:3090
void removeEdge(Edge edge)
Removes an edge and update the free valences of the attachment points that were originally involved i...
Definition: DGraph.java:2849
void getChildTreeLimited(Vertex vertex, List< Vertex > children, boolean stopBeforeRCVs)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:3257
Template templateJacket
Reference to the Template embedding this graph.
Definition: DGraph.java:150
boolean removeBranchStartingAt(Vertex v, boolean symmetry)
Deletes the branch, i.e., the specified vertex and its children.
Definition: DGraph.java:5017
int getHeavyAtomsCount()
Calculate the number of atoms from the graph representation.
Definition: DGraph.java:4182
DGraph extractSubgraph(Collection< Vertex > definedOn)
Returns a clone of the subgraph defined by the a collection of vertices belonging to this graph.
Definition: DGraph.java:4768
boolean removeOrphanBranchStartingAt(Vertex v)
Deletes the branch, i.e., the specified vertex and its children.
Definition: DGraph.java:5076
List< Vertex > getMutableSites()
A list of mutation sites from within this graph.
Definition: DGraph.java:6858
String localMsg
A free-format string used to record simple properties in the graph.
Definition: DGraph.java:140
void addEdge(Edge edge)
Adds the edge to the list of edges belonging to this graph.
Definition: DGraph.java:1249
boolean replaceSingleSubGraph(List< Vertex > subGrpVrtxs, DGraph newSubGraph, LinkedHashMap< AttachmentPoint, AttachmentPoint > apMap)
Replaced the subgraph represented by a given collection of vertices that belong to this graph.
Definition: DGraph.java:2183
List< Template > getEmbeddingPath()
Find the path that one has to traverse to reach this graph from any template-embedding structure.
Definition: DGraph.java:7231
void addCappingGroups(List< Vertex > vertexAddedToThis, FragmentSpace fragSpace)
Add a capping group on the given vertices, if needed.
Definition: DGraph.java:4421
Template getTemplateJacket()
Definition: DGraph.java:7198
boolean removeChainUpToBranching(Vertex v, FragmentSpace fragSpace)
Mutates the graph by removing the chain where a given vertex is located up to the first branching (i....
Definition: DGraph.java:5107
List< Integer > getBranchIdOfVertexAtPosition(int i)
Returns the branch identifier.
Definition: DGraph.java:3170
void setLocalMsg(String msg)
Definition: DGraph.java:279
List< Vertex > getSelectedMutableSites(MutationType requestedType)
A list of mutation sites from within this graph.
Definition: DGraph.java:6905
void appendGraphOnGraph(Vertex parentVertex, int parentAPIdx, DGraph subGraph, Vertex childVertex, int childAPIdx, BondType bndType, Map< Vertex, SymmetricVertexes > newSymSets, boolean onAllSymmAPs)
Append a graph (incoming=I) onto this graph (receiving=R).
Definition: DGraph.java:6237
boolean isIsostructuralTo(DGraph other)
Checks if this graph is "DENOPTIM-isostructural" to the other one given.
Definition: DGraph.java:3809
DGraph extractSubgraph(Vertex seed, List< Vertex > limits, boolean stopBeforeRCVs)
Creates a new graph that corresponds to the subgraph of this graph when exploring the spanning tree f...
Definition: DGraph.java:4583
boolean hasOrEmbedsRings()
Check for rings in this graph and in any graph that is embedded at any level in any vertex of this gr...
Definition: DGraph.java:1134
void dfsEncodePaths(Vertex current, String currentPath, Set< Vertex > visited, Map< String, List< Vertex > > pathMap)
Performs a depth-first search (DFS) starting from a given Vertex to encode paths in the graph.
Definition: DGraph.java:487
boolean detectSymVertexSets()
Detects and groups symmetric sets of Vertexes in the graph based on unique identification and path en...
Definition: DGraph.java:368
ArrayList< Vertex > findVertices(VertexQuery vrtxQuery, Logger logger)
Filters a list of vertices according to a query.
Definition: DGraph.java:6294
This class represents the edge between two vertices.
Definition: Edge.java:38
AttachmentPoint getTrgAP()
Definition: Edge.java:115
void flipEdge()
Exchanges source and target vertices and respective APs of this edge.
Definition: Edge.java:292
long getSrcVertex()
Definition: Edge.java:122
AttachmentPoint getSrcAP()
Definition: Edge.java:94
long getTrgVertex()
Definition: Edge.java:143
BondType getBondType()
Definition: Edge.java:164
A query for edges: a list of properties that target edges should possess in order to match this query...
Definition: EdgeQuery.java:28
Class representing a continuously connected portion of chemical object holding attachment points.
Definition: Fragment.java:61
This class represents the closure of a ring in a spanning tree.
Definition: Ring.java:40
Vertex getTailVertex()
Definition: Ring.java:95
int getPositionOf(Vertex v)
Definition: Ring.java:415
void addVertex(Vertex v)
Append a DENOPTIMVertex to the list.
Definition: Ring.java:71
Vertex getVertexAtPosition(int i)
Definition: Ring.java:107
void setBondType(BondType bndType)
Set the bond type (i.e., bond order) of the chord connecting the head and the tail vertices.
Definition: Ring.java:158
List< Vertex > getVertices()
Definition: Ring.java:214
Vertex getHeadVertex()
Definition: Ring.java:83
A collection of AttachmentPoints that are related by a relation that we call "symmetry",...
boolean add(T item)
Adds an item to this list, if not already present.
A collection of Vertexs that are related by a relation that we call "symmetry", even though this clas...
void removeProjectionOfInnerAP(AttachmentPoint oldInnerAP)
Removes the mapping of the given inner AP from this template's surface, if such mapping exists.
Definition: Template.java:399
void setInnerGraph(DGraph innerGraph)
Definition: Template.java:298
void updateInnerApID(AttachmentPoint oldInnerAP, AttachmentPoint newInnerAP)
Replaces a given link between APs on the surface of this template (i.e., outerAP) and the correspondi...
Definition: Template.java:377
void addInnerToOuterAPMapping(AttachmentPoint newInnerAP)
Adds the projection of an AP in the template's inner graph (i.e., innerAP) to the list of APs visible...
Definition: Template.java:348
ArrayList< AttachmentPoint > getAttachmentPoints()
Return the list of attachment points visible from outside the template, i.e., the so-called outer APs...
Definition: Template.java:458
void clearIAtomContainer()
Removes the molecular representation.
Definition: Template.java:600
void setContractLevel(ContractLevel contract)
Imposes the given contract to this template.
Definition: Template.java:214
AttachmentPoint getOuterAPFromInnerAP(AttachmentPoint innerAP)
Definition: Template.java:842
AttachmentPoint getInnerAPFromOuterAP(AttachmentPoint outerAP)
Definition: Template.java:822
A vertex is a data structure that has an identity and holds a list of AttachmentPoints.
Definition: Vertex.java:62
ArrayList< Vertex > getChildrenThroughout()
Looks into the edges that use any of the APs that belong to this vertex and returns the list of verti...
Definition: Vertex.java:1145
abstract Vertex clone()
Returns a deep-copy of this vertex.
void setMutationTypes(List< MutationType > lst)
Definition: Vertex.java:882
int getBuildingBlockId()
Returns the index of the building block that should correspond to the position of the building block ...
Definition: Vertex.java:305
Edge getEdgeToParent()
Looks into the edges that use any of the APs that belong to this vertex and returns the edge that has...
Definition: Vertex.java:1060
void setVertexId(long vertexId2)
Definition: Vertex.java:282
int getFreeAPCountThroughout()
Counts the number of attachment points that are availability throughout the graph level,...
Definition: Vertex.java:431
int getIndexOfAP(AttachmentPoint ap)
Returns the position of the given AP in the list of APs of this vertex.
Definition: Vertex.java:1037
String toString()
Produces a human readable, short string to represent the vertex by its vertex ID, building block ID (...
Definition: Vertex.java:632
Vertex getParent()
Looks into the edges that use any of the APs that belong to this vertex and returns the vertex which ...
Definition: Vertex.java:1084
Vertex.BBType getBuildingBlockType()
Definition: Vertex.java:319
DGraph getGraphOwner()
Returns the graph this vertex belongs to or null.
Definition: Vertex.java:852
ArrayList< Vertex > getChilddren()
Looks into the edges that use any of the APs that belong to this vertex and returns the list of verti...
Definition: Vertex.java:1173
abstract List< AttachmentPoint > getAttachmentPoints()
Object getProperty(Object property)
Definition: Vertex.java:1224
boolean sameAs(Vertex other)
Compares this and another vertex ignoring vertex IDs.
Definition: Vertex.java:670
int getCappedAPCountThroughout()
Counts the number of attachment points that are used by BBType#CAP vertex.
Definition: Vertex.java:514
void setProperty(Object key, Object property)
Definition: Vertex.java:1236
ArrayList< AttachmentPoint > getFreeAPThroughout()
Gets attachment points that are availability throughout the graph level, i.e., checks also across the...
Definition: Vertex.java:403
AttachmentPoint getAP(int i)
Get attachment point i on this vertex.
Definition: Vertex.java:1008
static Vertex newVertexFromLibrary(int bbId, Vertex.BBType bbt, FragmentSpace fragSpace)
Builds a new molecular fragment kind of vertex.
Definition: Vertex.java:215
Edge getEdgeWith(Vertex other)
Finds the edge between this and the other vertex, if it exists.
Definition: Vertex.java:1507
Query for searching vertices.
ClosableChain represents a chain of fragments (chain links) that is closable (or candidate closable).
This is a tool to identify and manage vertices' connections not included in the DGraph,...
boolean checkChelatesGraph(DGraph molGraph, List< Ring > ringsSet)
Evaluates the combination of a DENOPTIMGraph and a set of DENOPTIMRings and decides whether it's a pr...
ArrayList< List< Ring > > getPossibleCombinationOfRings(IAtomContainer mol, DGraph molGraph)
Identifies all possible ring closing paths and returns them as list of DENOPTIMRings ready to be appe...
This object represents a path in a DGraph.
List< Vertex > getVertecesPath()
Returns the list of verteces involved.
The RingClosingAttractor represent the available valence/connection that allows to close a ring.
static final Map< String, String > RCATYPEMAP
Recognized types of RingClosingAttractor and compatible types.
Parameters and setting related to handling ring closures.
boolean buildChelatesMode
Flag activating procedures favoring formation of chelates.
This class represents a subgraph feature that defined the structure of a graph.
Definition: Node.java:32
int compare(Node other)
Definition: Node.java:76
static final String REFTOVERTEXKERNEL
Property if Vertex used to store the reference to the corresponding Node.
Definition: Node.java:47
Utility methods for input/output.
static void writeGraphToJSON(File file, DGraph graph)
Writes the graph to JSON file.
Class for de/serializing DENOPTIM graphs from/to JSON format.
Tool to build build three-dimensional (3D) tree-like molecular structures from DGraph.
void setAlignBBsIn3D(boolean align)
Sets the flag that controls whether building blocks have to be aligned according to the AP vectors or...
IAtomContainer convertGraphTo3DAtomContainer(DGraph graph)
Created a three-dimensional molecular representation from a given DGraph.
Collection of parameters controlling the behavior of the software.
RunTimeParameters getParameters(ParametersType type)
Logger getLogger()
Get the name of the program specific logger.
static< T > void unionOfIntersectingSets(List< Set< T > > list)
Takes the union of any two sets in this list that intersect.
Tool to convert string into graphs and into molecular representation.
static DefaultUndirectedGraph< Vertex, UndirectedEdge > getJGraphFromGraph(DGraph dg)
Converts a DGraph into a simplified JGraphT DefaultUndirectedGraph.
static DefaultUndirectedGraph< Node, NodeConnection > getJGraphKernelFromGraph(DGraph dg)
Converts a DGraph into a simplified JGraphT DefaultUndirectedGraph.
Definition of a graph editing task.
Definition: GraphEdit.java:38
Utilities for graphs.
Definition: GraphUtils.java:40
static synchronized void ensureVertexIDConsistency(long l)
Method used to ensure consistency between internal atomic integer and vertex id from imported graphs.
Definition: GraphUtils.java:55
static synchronized long getUniqueVertexIndex()
Unique counter for the number of graph vertices generated.
Definition: GraphUtils.java:97
static synchronized int getUniqueGraphIndex()
Unique counter for the number of graphs generated.
Utilities for molecule conversion.
static String getInChIKeyForMolecule(IAtomContainer mol, Logger logger)
Generates the InChI key for the given atom container.
static int getNumberOfRotatableBonds(IAtomContainer mol)
Count number of rotatable bonds.
static String getSMILESForMolecule(IAtomContainer mol, Logger logger)
Returns the SMILES representation of the molecule.
static double getMolecularWeight(IAtomContainer mol)
static String getSymbolOrLabel(IAtom atm)
Gets either the elemental symbol (for standard atoms) of the label (for pseudo-atoms).
static int getHeavyAtomCount(IAtomContainer mol)
The heavy atom count.
This class is the equivalent of the Pair data structure used in C++ Although AbstractMap....
Definition: ObjectPair.java:30
Tool box for definition and management of the rotational space, which is given by the list of rotatab...
static ArrayList< ObjectPair > defineRotatableBonds(IAtomContainer mol, String defRotBndsFile, boolean addIterfragBonds, boolean excludeRings, Logger logger)
Define the rotational space (also torsional space) for a given molecule.
Identifier for the format of string representations of a graph.
Definition: DGraph.java:167
Possible chemical bond types an edge can represent.
Definition: Edge.java:303
Enum specifying to what extent the template's inner graph can be changed.
Definition: Template.java:104
FREE
Inner graphs are free to change within the confines of the required AttachmentPoints.
Definition: Template.java:109
The type of building block.
Definition: Vertex.java:87
Flag declaring the type of Vertex implementation.
Definition: Vertex.java:173
FS_PARAMS
Parameters pertaining the definition of the fragment space.
RC_PARAMS
Parameters pertaining to ring closures in graphs.
Types of mutation defined in relation to what happens to the target vertex (i.e., the actual mutation...