$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.Arrays;
28import java.util.Collection;
29import java.util.Collections;
30import java.util.Comparator;
31import java.util.HashMap;
32import java.util.HashSet;
33import java.util.Iterator;
34import java.util.LinkedHashMap;
35import java.util.List;
36import java.util.Map;
37import java.util.Map.Entry;
38import java.util.Queue;
39import java.util.Set;
40import java.util.concurrent.atomic.AtomicInteger;
41import java.util.function.Function;
42import java.util.logging.Level;
43import java.util.logging.Logger;
44import java.util.stream.Collectors;
45import java.util.stream.Stream;
46
47import org.jgrapht.alg.isomorphism.VF2GraphIsomorphismInspector;
48import org.jgrapht.graph.DefaultUndirectedGraph;
49import org.openscience.cdk.graph.ConnectivityChecker;
50import org.openscience.cdk.interfaces.IAtom;
51import org.openscience.cdk.interfaces.IAtomContainer;
52
53import com.google.gson.Gson;
54import com.google.gson.GsonBuilder;
55import com.google.gson.JsonArray;
56import com.google.gson.JsonDeserializationContext;
57import com.google.gson.JsonDeserializer;
58import com.google.gson.JsonElement;
59import com.google.gson.JsonObject;
60import com.google.gson.JsonParseException;
61import com.google.gson.JsonSerializationContext;
62import com.google.gson.JsonSerializer;
63
64import denoptim.constants.DENOPTIMConstants;
65import denoptim.exception.DENOPTIMException;
66import denoptim.fragspace.FragmentSpace;
67import denoptim.fragspace.FragmentSpaceParameters;
68import denoptim.graph.APClass.APClassDeserializer;
69import denoptim.graph.Edge.BondType;
70import denoptim.graph.Template.ContractLevel;
71import denoptim.graph.Vertex.BBType;
72import denoptim.graph.Vertex.DENOPTIMVertexDeserializer;
73import denoptim.graph.rings.ClosableChain;
74import denoptim.graph.rings.CyclicGraphHandler;
75import denoptim.graph.rings.PathSubGraph;
76import denoptim.graph.rings.RingClosingAttractor;
77import denoptim.graph.rings.RingClosureParameters;
78import denoptim.graph.simplified.Node;
79import denoptim.graph.simplified.NodeConnection;
80import denoptim.graph.simplified.UndirectedEdge;
81import denoptim.io.DenoptimIO;
82import denoptim.json.DENOPTIMgson;
83import denoptim.json.DENOPTIMgson.DENOPTIMExclusionStrategyNoAPMap;
84import denoptim.molecularmodeling.ThreeDimTreeBuilder;
85import denoptim.programs.RunTimeParameters;
86import denoptim.programs.RunTimeParameters.ParametersType;
87import denoptim.utils.GeneralUtils;
88import denoptim.utils.GraphConversionTool;
89import denoptim.utils.GraphEdit;
90import denoptim.utils.GraphUtils;
91import denoptim.utils.MoleculeUtils;
92import denoptim.utils.MutationType;
93import denoptim.utils.ObjectPair;
94import denoptim.utils.Randomizer;
95import denoptim.utils.RotationalSpaceUtils;
96
97
103public class DGraph implements Cloneable
104{
108 List<Vertex> gVertices;
109
113 List<Edge> gEdges;
114
118 List<Ring> gRings;
119
123 List<ClosableChain> closableChains;
124
125 /*
126 * Unique graph id
127 */
129
130 /*
131 * store the set of symmetric vertex ids at each level. This is only
132 * applicable for symmetric graphs
133 */
134 private List<SymmetricVertexes> symVertices;
135
141 //TODO: rename to Provenance
142 String localMsg;
143
148
153
157 private DefaultUndirectedGraph<Vertex, UndirectedEdge>
158 jGraph = null;
159
163 private DefaultUndirectedGraph<Node, NodeConnection>
165
169 public enum StringFormat {JSON, GRAPHENC}
170
174 private AtomicInteger apCounter = new AtomicInteger(1);
175
180 private static final String SYM_ID = "symmetryKey";
181
182//------------------------------------------------------------------------------
183
184 public DGraph(List<Vertex> gVertices, List<Edge> gEdges)
185 {
186 this.gVertices = gVertices;
187 for (Vertex v : this.gVertices)
188 v.setGraphOwner(this);
189 this.gEdges = gEdges;
190 gRings = new ArrayList<>();
191 closableChains = new ArrayList<>();
192 symVertices = new ArrayList<>();
193 localMsg = "";
194 }
195
196//------------------------------------------------------------------------------
197
198 public DGraph(List<Vertex> gVertices, List<Edge> gEdges, List<Ring> gRings)
199 {
200 this(gVertices, gEdges);
201 this.gRings = gRings;
202 closableChains = new ArrayList<>();
203 symVertices = new ArrayList<>();
204 localMsg = "";
205 }
206
207//------------------------------------------------------------------------------
208
209 public DGraph(List<Vertex> gVertices, List<Edge> gEdges, List<Ring> gRings,
210 List<SymmetricVertexes> symSets)
211 {
212 this(gVertices, gEdges, gRings);
213 closableChains = new ArrayList<>();
214 this.symVertices = symSets;
215 localMsg = "";
216 }
217
218//------------------------------------------------------------------------------
219
220 public DGraph(List<Vertex> gVertices, List<Edge> gEdges, List<Ring> gRings,
221 List<ClosableChain> closableChains,
222 List<SymmetricVertexes> symVertices)
223 {
225 this.closableChains = closableChains;
226 localMsg = "";
227 }
228
229//------------------------------------------------------------------------------
230
231 public DGraph()
232 {
233 gVertices = new ArrayList<>();
234 gEdges = new ArrayList<>();
235 gRings = new ArrayList<>();
236 closableChains = new ArrayList<>();
237 symVertices = new ArrayList<>();
238 localMsg = "";
239 }
240
241//------------------------------------------------------------------------------
242
248 {
249 this.candidate = candidate;
250 }
251
252//------------------------------------------------------------------------------
253
260 {
261 return candidate;
262 }
263
264//------------------------------------------------------------------------------
265
266 public void setGraphId(int id)
267 {
268 graphId = id;
269 }
270
271//------------------------------------------------------------------------------
272
273 public int getGraphId()
274 {
275 return graphId;
276 }
277
278//------------------------------------------------------------------------------
279
280 //TODO: rename to Provenance
281 public void setLocalMsg(String msg)
282 {
283 localMsg = msg;
284 }
285
286//------------------------------------------------------------------------------
287
288 //TODO: rename to Provenance
289 public String getLocalMsg()
290 {
291 return localMsg;
292 }
293
294//------------------------------------------------------------------------------
295
296 public boolean hasSymmetricAP()
297 {
298 return (!symVertices.isEmpty());
299 }
300
301//------------------------------------------------------------------------------
302
304 {
305 boolean res = false;
307 {
308 if (ss.contains(v))
309 {
310 res = true;
311 break;
312 }
313 }
314 return res;
315 }
316
317//------------------------------------------------------------------------------
318
324 {
325 return symVertices.size();
326 }
327
328//------------------------------------------------------------------------------
329
334 public Iterator<SymmetricVertexes> getSymSetsIterator()
335 {
336 return symVertices.iterator();
337 }
338
339//------------------------------------------------------------------------------
340
345 public List<Vertex> getSymVerticesForVertex(Vertex v)
346 {
347 List<Vertex> lst = new ArrayList<Vertex>();
349 {
350 if (ss.contains(v))
351 {
352 ss.stream().forEach(i -> lst.add((Vertex) i));
353 }
354 }
355 return lst;
356 }
357
358//------------------------------------------------------------------------------
371 {
372 int initialSize = symVertices.size();
373 List<Vertex> uniqueVertices = new ArrayList<>();
374 Map<String, List<Vertex>> pathMap = new HashMap<>();
375 Set<Vertex> visited = new HashSet<>();
376 Vertex scaffold = null;
377
378 AtomicInteger vrtxIdCounter = new AtomicInteger();
379 AtomicInteger apIdCounter = new AtomicInteger();
380
381 for (Vertex vertex : getVertexList())
382 {
383 if (vertex.getBuildingBlockType() == BBType.SCAFFOLD) {
384 if (scaffold == null) scaffold = vertex;
385 }
386 boolean isVertexNew = true;
387 Vertex matchedVertex = null;
388
389 // Check if the vertex is the same as other in the unique vertices
390 for (Vertex uniqueVertex : uniqueVertices)
391 {
392 // Equality condition
393 if (vertex.sameAs(uniqueVertex))
394 {
395 isVertexNew = false;
396 matchedVertex = uniqueVertex;
397 break;
398 }
399 }
400 if (isVertexNew)
401 {
402 // Create unique key for the vertex
403 int vertexKey = vrtxIdCounter.getAndIncrement();
404 vertex.setProperty(SYM_ID, vertexKey);
405 // Create unique key for each AP of the vertex
406 Map<AttachmentPoint, Integer> apKeys = new HashMap<>();
407 for (AttachmentPoint ap : vertex.getAttachmentPoints())
408 {
409 // symAPs share the same symmetry key
410 SymmetricAPs symAPs = vertex.getSymmetricAPs(ap);
411 if (!symAPs.isEmpty())
412 {
413 Integer sharedKey = apKeys.get(symAPs.get(0));
414
415 if (sharedKey == null) {
416 sharedKey = apIdCounter.getAndIncrement();
417 apKeys.put(symAPs.get(0), sharedKey);
418 }
419 for (AttachmentPoint symAp : symAPs) {
420 symAp.setProperty(SYM_ID, sharedKey);
421 }
422
423 } else {
424
425 int apKey = apIdCounter.getAndIncrement();
426 ap.setProperty(SYM_ID, apKey);
427 }
428
429 }
430 // Add the vertex to the list of unique vertices
431 uniqueVertices.add(vertex);
432
433 } else {
434
435 // The vertex is not new, so we copy properties from the
436 // matched vertex
437 vertex.setProperty(SYM_ID, matchedVertex.getProperty(SYM_ID));
438
439 // Ensure APs are synchronized between the current vertex
440 // and the matched vertex
441 for (int i = 0; i < vertex.getAttachmentPoints().size(); i++) {
442 AttachmentPoint currentAP =
443 vertex.getAttachmentPoints().get(i);
444 AttachmentPoint matchedAP =
445 matchedVertex.getAttachmentPoints().get(i);
446 // Since sameAs checks APs order, AP indices align
447 currentAP.setProperty(SYM_ID,matchedAP.getProperty(SYM_ID));
448 }
449 }
450 }
451
452 if (scaffold == null) {
453 throw new DENOPTIMException("No scaffold vertex found in the graph.");
454 }
455
456 // Get all path with Depth First Search (DFS) algorithm
457 dfsEncodePaths(scaffold, "", visited, pathMap);
458
459 // Detect symmetric sets based on path encodings
460 for (Map.Entry<String, List<Vertex>> entry : pathMap.entrySet()) {
461 List<Vertex> symVertices = entry.getValue();
462 if (symVertices.size() > 1)
463 {
465 }
466 }
467
468 return (symVertices.size()-initialSize)>0;
469
470 }
471//------------------------------------------------------------------------------
489 private void dfsEncodePaths(Vertex current,
490 String currentPath,
491 Set<Vertex> visited,
492 Map<String, List<Vertex>> pathMap) throws DENOPTIMException {
493
494 if (visited.contains(current))
495 {
496 return;
497 }
498 visited.add(current);
499
500 Integer vertexKey = (Integer) current.getProperty(SYM_ID);
501 currentPath += vertexKey.toString();
502
503 // Store the current path in pathMap
504 pathMap.computeIfAbsent(currentPath, k -> new ArrayList<>()).add(current);
505
506 // Recursively encode paths for each child vertex
507 for (AttachmentPoint ap : current.getAttachmentPoints()) {
508
509 // Check if the AP is making an edge
510 if (ap.getEdgeUser()!=null &&
511 !visited.contains(ap.getEdgeUser().getTrgAP().getOwner()))
512 {
513 Edge edge = ap.getEdgeUser();
514 // Get target AP
515 AttachmentPoint trAp = edge.getTrgAP();
516 // Get child vertex
517 Vertex child = trAp.getOwner();
518 Integer apKey = (Integer) ap.getProperty(SYM_ID);
519
520 // Ensure the apKey is valid
521 if (apKey != null) {
522 dfsEncodePaths(child,
523 currentPath + apKey.toString(),
524 visited,
525 pathMap);
526 } else {
527 throw new DENOPTIMException("Error: AP encoding not found "
528 + "for " + ap);
529 }
530 }
531 }
532 }
533
534//------------------------------------------------------------------------------
557// public boolean detectSymVertexSets() throws DENOPTIMException
558// {
559// int initialSize = symVertices.size();
560//
561// // This is to hold vertexes in a staging area (symVrtxsFromAnyBranch)
562// // without adding them to a SymmetricVertexes right away.
563// Set<Vertex> alreadyAssignedVrtxs = new HashSet<Vertex>();
564//
565// // The sym vertexes on vrtx can have sym counterpart
566// // that are attached to vertexes sym to vrtx. Prepare a storage to
567// // collect all sym counterparts from any of vertexes sym to vrtx
568// Map<SymmetricAPs,List<Vertex>> symVrtxsFromAnyBranch =
569// new HashMap<SymmetricAPs,List<Vertex>>();
570// for (Vertex vrtx : getVertexList())
571// {
572// // NB: if there is a symmetric relation involving vrtx, then
573// // vrtx is in the set returned by the following lines
574// List<Vertex> vrtxsSymToVrtx = new ArrayList<Vertex>();
575// for (List<Vertex> tmpSymSets : symVrtxsFromAnyBranch.values())
576// {
577// if (tmpSymSets.contains(vrtx))
578// {
579// vrtxsSymToVrtx.addAll(tmpSymSets);
580// }
581// }
582// if (vrtxsSymToVrtx.size()==0)
583// vrtxsSymToVrtx.add(vrtx);
584//
585// for (Vertex symToVrtx : vrtxsSymToVrtx)
586// {
587// Map<SymmetricAPs,List<Vertex>> symChildenSetsOnSymToVrtxs =
588// findSymmetrySetsOfChildVertexes(symToVrtx,
589// alreadyAssignedVrtxs);
590//
591// for (SymmetricAPs key : symChildenSetsOnSymToVrtxs.keySet())
592// {
593// // Find any mapping with previously recorded SymmetricAPs
594// boolean foundSymmetricBranch = false;
595// for (SymmetricAPs keyOnMaster : key.getAllSameAs(
596// symVrtxsFromAnyBranch.keySet()))
597// {
598// foundSymmetricBranch = true;
599//
600// // Here we must NOT consider the already assigned ones!
601// if (areApsUsedBySymmetricUsers(key.get(0),
602// keyOnMaster.get(0), new HashSet<Vertex>()))
603// {
604// // the previously recorded branch and
605// // this one are consistent
606// symVrtxsFromAnyBranch.get(keyOnMaster).addAll(
607// symChildenSetsOnSymToVrtxs.get(key));
608// } else {
609// // branches correspond to two different sets of
610// // symmetric vertexes. So, we treat the new branch
611// // independently
612// foundSymmetricBranch = false;
613// }
614// }
615// if (!foundSymmetricBranch)
616// {
617// // Effectively, in the first iteration of the loop
618// // we will always end up here
619// List<Vertex> lst = new ArrayList<Vertex>();
620// lst.addAll(symChildenSetsOnSymToVrtxs.get(key));
621// symVrtxsFromAnyBranch.put(key, lst);
622// }
623// }
624// }
625// }
626//
627//
628// for (Map.Entry<SymmetricAPs,
629// List<Vertex>> entry : symVrtxsFromAnyBranch.entrySet())
630// {
631//
632// List<Vertex> symVertexes = entry.getValue();
633// SymmetricAPs key = entry.getKey();
634// if (symVertexes.size() < 2) {
635// // We get rid of placeholders for vertexes that use APs that
636// // are not part of a symmetriAPs, but could have been part
637// // of symmetric subgraphs
638// continue;
639// } else {
640//
641// Map<Vertex, List<Vertex>> vertexChildrenMap = new HashMap<>();
642// // Get children tree for each vertex in the symmetric set
643// for (Vertex vertex : symVertexes) {
644// List<Vertex> children = new ArrayList<>();
645// getChildrenTree(vertex, children);
646// vertexChildrenMap.put(vertex, children);
647// }
648//
649// boolean allInOneBranch = false;
650// Set<Vertex> toRemove = new HashSet<>();
651// for (Vertex parent : vertexChildrenMap.keySet()) {
652// List<Vertex> children = vertexChildrenMap.get(parent);
653// boolean allChildren = true;
654// for (Vertex other : symVertexes) {
655// if (other != parent && !children.contains(other)) {
656// allChildren = false;
657// break;
658// }
659// }
660// if (allChildren) {
661// allInOneBranch = true;
662// break;
663// }
664// // Mark children for removal if they are contained in any
665// // parent's children tree
666// for (Vertex child : children) {
667// if (symVertexes.contains(child) && child != parent) {
668// toRemove.add(child);
669// }
670// }
671// }
672// if (allInOneBranch) {
673// // All vertices are in the same branch, skip the set
674// continue;
675//
676// } else if (!toRemove.isEmpty()) {
677// // Remove only the child vertices.
678// symVertexes.removeAll(toRemove);
679// }
680// }
681// alreadyAssignedVrtxs.addAll(symVertexes);
682// addSymmetricSetOfVertices(new SymmetricVertexes(symVertexes));
683// }
684//
685// return (symVertices.size()-initialSize)>0;
686// }
687
688//------------------------------------------------------------------------------
689
691// Vertex vrtx, Set<Vertex> alreadyAssignedVrtxs)
692// {
693// Map<SymmetricAPs,List<Vertex>> symSetsOfChildVrtxs =
694// new HashMap<SymmetricAPs,List<Vertex>>();
695//
696// Set<AttachmentPoint> doneAPs = new HashSet<AttachmentPoint>();
697// for (SymmetricAPs symAPs : vrtx.getSymmetricAPSets())
698// {
699// // First condition: all symmetric APs must be in use
700// boolean addSymAPsAreUsed = true;
701// for (AttachmentPoint ap : symAPs)
702// {
703// if (ap.isAvailableThroughout())
704// {
705// addSymAPsAreUsed = false;
706// break;
707// }
708// }
709// if (!addSymAPsAreUsed)
710// continue;
711//
712// // Now consider what vertex is attached to the symmetric APs
713// AttachmentPoint firstAp = symAPs.get(0);
714//
715// boolean setSymmetryRelation = true;
716// List<Vertex> symVertexes = new ArrayList<Vertex>();
717// symVertexes.add(firstAp.getLinkedAPThroughout().getOwner());
718// for (AttachmentPoint ap : symAPs)
719// {
720// doneAPs.add(ap);
721//
722// if (firstAp==ap)
723// continue;
724//
725// setSymmetryRelation = areApsUsedBySymmetricUsers(firstAp, ap,
726// alreadyAssignedVrtxs);
727// if (!setSymmetryRelation)
728// break;
729//
730// // OK: this user of AP is symmetric to the user on firstAP
731// symVertexes.add(ap.getLinkedAPThroughout().getOwner());
732// }
733//
734// if (setSymmetryRelation)
735// {
736// symSetsOfChildVrtxs.put(symAPs,symVertexes);
737// alreadyAssignedVrtxs.addAll(symVertexes);
738// }
739// }
740//
741// // Here we account for the possibility that vertex without sym APs
742// // is part of a subgraph the is symmetrically reproduced elsewhere.
743// // This is a common pattern in chemistry.
744// // To this end we create dummy symmetric sets of APs that contain
745// // only one APs, and use them as placeholder in case the same AP-user
746// // is found on symmetric branches.
747// for (AttachmentPoint ap : vrtx.getAttachmentPoints())
748// {
749// if (doneAPs.contains(ap) || ap.isAvailableThroughout())
750// continue;
751//
752// Vertex user = ap.getLinkedAPThroughout().getOwner();
753// if (alreadyAssignedVrtxs.contains(user))
754// continue;
755//
756// // Create an artifact of SymmetricAPs that contains one entry
757// SymmetricAPs soloSymAps = new SymmetricAPs();
758// soloSymAps.add(ap);
759//
760// // Well, this contains only one entry, but for consistency we still
761// // use a list.
762// List<Vertex> symVertexes = new ArrayList<Vertex>();
763// symVertexes.add(user);
764//
765// symSetsOfChildVrtxs.put(soloSymAps,symVertexes);
766// alreadyAssignedVrtxs.addAll(symVertexes);
767// }
768// return symSetsOfChildVrtxs;
769// }
770//
771//------------------------------------------------------------------------------
772
773// /**
774// * Checks if the {@link Vertex}s that are attached to two given
775// * {@link AttachmentPoint}s apA and apB satisfy these conditions:
776// * <ul>
777// * <li>the linked APs must return true from
778// * {@link AttachmentPoint#sameAs(AttachmentPoint)}</li>
779// * <li>the {@link Vertex} owner of apB is not contained in the set of
780// * already-assigned vertexes (the 3rd argument)</li>
781// * <li>the {@link Vertex}a attached to apA andapB must be return satisfy
782// * {@link Vertex#sameAs(Vertex)}</li>
783// * <li>if such vertexes are instances of {@link Fragment}, then they must
784// * satisfy {@link Fragment#isIsomorphicTo(Vertex)}.</li>
785// * </ul>
786// * These conditions, when satisfied for a pair of used and symmetric
787// * {@link AttachmentPoint}s apA and apB should suffice to assign the
788// * two user {@link Vertex}s to the same {@link SymmetricVertexes} set.
789// * @param apA one attachment point in the pair.
790// * @param apB the other attachment point in the pair.
791// * @param alreadyAssignedVrtxs a set of vertexes that have been already
792// * assigned to {@link SymmetricVertexes} set.
793// * @return
794// */
795// public static boolean areApsUsedBySymmetricUsers(AttachmentPoint apA,
796// AttachmentPoint apB, Set<Vertex> alreadyAssignedVrtxs)
797// {
798// AttachmentPoint apUserOfApA = apA.getLinkedAPThroughout();
799// Vertex userOfApA = apUserOfApA.getOwner();
800// boolean userOfApAIsFragment = Fragment.class.isInstance(userOfApA);
801//
802// // 1st condition: (fast failing) the linked AP must have
803// // the same features. This is faster than checking vertex
804// // isomorphism.
805// AttachmentPoint apUserOfApB = apB.getLinkedAPThroughout();
806// if (!apUserOfApA.sameAs(apUserOfApB))
807// {
808// return false;
809// }
810//
811// // 2nd condition: (fast-failing) the linked vertexes
812// // must be unassigned
813// Vertex userOfApB = apUserOfApB.getOwner();
814// if (alreadyAssignedVrtxs.contains(userOfApB))
815// {
816// return false;
817// }
818//
819// // 3rd condition: (not fast, not too slow) the linked
820// // vertexes must be have same features
821// if (!userOfApB.sameAs(userOfApA))
822// {
823// return false;
824// }
825//
826// // 4th condition: (slow) the linked vertexes
827// // are fragments that have been generated on the fly, so
828// // they do not have an assigned building block ID. We must
829// // therefore compare their internal structure.
830// if (userOfApAIsFragment)
831// {
832// // At this point we know the two vertexes are instances
833// // of the same class.
834// Fragment frgUserOfApA = (Fragment) userOfApA;
835// Fragment frgUserOfApB = (Fragment) userOfApB;
836// if (!frgUserOfApA.isIsomorphicTo(frgUserOfApB))
837// {
838// return false;
839// }
840// }
841// return true;
842// }
843
844//------------------------------------------------------------------------------
845
851 {
852 symVertices.remove(ss);
853 }
854
855//------------------------------------------------------------------------------
856
864 {
866 {
867 if (ss.contains(v))
868 {
869 return ss;
870 }
871 }
872 return new SymmetricVertexes();
873 }
874
875//------------------------------------------------------------------------------
876
877 public void setSymmetricVertexSets(List<SymmetricVertexes> symVertices)
878 {
879 this.symVertices.clear();
880 this.symVertices.addAll(symVertices);
881 }
882
883//------------------------------------------------------------------------------
884
892 throws DENOPTIMException
893 {
894 for (SymmetricVertexes oldSS : symVertices)
895 {
896 if (!Collections.disjoint(oldSS, symSet))
897 {
898 throw new DENOPTIMException("Adding " + symSet + " while "
899 + "there is already one that contains some of the same "
900 + "items");
901 }
902 }
903 symVertices.add(symSet);
904 }
905
906//------------------------------------------------------------------------------
907
908 public void setVertexList(ArrayList<Vertex> vertices)
909 {
910 gVertices = vertices;
911 jGraph = null;
912 jGraphKernel = null;
913 }
914
915//------------------------------------------------------------------------------
916
917 public void setEdgeList(ArrayList<Edge> edges)
918 {
919 gEdges = edges;
920 jGraph = null;
921 jGraphKernel = null;
922 }
923
924//------------------------------------------------------------------------------
925
926 public void setRings(ArrayList<Ring> rings)
927 {
928 gRings = rings;
929 jGraph = null;
930 jGraphKernel = null;
931 }
932
933//------------------------------------------------------------------------------
934
935 public void setCandidateClosableChains(ArrayList<ClosableChain> closableChains)
936 {
937 this.closableChains = closableChains;
938 }
939
940//------------------------------------------------------------------------------
941
942 public List<ClosableChain> getClosableChains()
943 {
944 return closableChains;
945 }
946
947//------------------------------------------------------------------------------
948
953 public List<Vertex> getVertexAnyLevel()
954 {
955 List<Vertex> list = new ArrayList<Vertex>();
956 list.addAll(gVertices);
957 for (Vertex v : gVertices)
958 {
959 if (v instanceof Template)
960 {
961 list.addAll(((Template) v).getInnerGraph().getVertexAnyLevel());
962 }
963 }
964 return list;
965 }
966
967//------------------------------------------------------------------------------
968
973 public List<Vertex> getVertexList()
974 {
975 return gVertices;
976 }
977
978//------------------------------------------------------------------------------
979
997 {
998 switch (gVertices.size())
999 {
1000 case 0:
1001 return null;
1002 case 1:
1003 return getVertexAtPosition(0);
1004 }
1006 for (Edge e : this.getEdgeList())
1007 {
1008 if (e.getTrgAP().getOwner() == v0)
1009 {
1010 ArrayList<Vertex> parentTree = new ArrayList<>();
1011 getParentTree(v0,parentTree);
1012 return parentTree.get(parentTree.size()-1);
1013 }
1014 }
1015 return v0;
1016 }
1017
1018//------------------------------------------------------------------------------
1019
1020 public List<Edge> getEdgeList()
1021 {
1022 return gEdges;
1023 }
1024
1025//------------------------------------------------------------------------------
1026
1027 public List<Ring> getRings()
1028 {
1029 return gRings;
1030 }
1031
1032//------------------------------------------------------------------------------
1033
1040 public List<Edge> getEdgesWithSrc(Vertex v)
1041 {
1042 List<Edge> edges = new ArrayList<Edge>();
1043 for (Edge e : this.getEdgeList())
1044 {
1045 if (e.getSrcAP().getOwner() == v)
1046 {
1047 edges.add(e);
1048 }
1049 }
1050 return edges;
1051 }
1052
1053//------------------------------------------------------------------------------
1054
1061 public List<Edge> getEdgesWithTrg(Vertex v)
1062 {
1063 List<Edge> edges = new ArrayList<Edge>();
1064 for (Edge e : this.getEdgeList())
1065 {
1066 if (e.getTrgAP().getOwner() == v)
1067 {
1068 edges.add(e);
1069 }
1070 }
1071 return edges;
1072 }
1073
1074//------------------------------------------------------------------------------
1075
1082 public ArrayList<Ring> getRingsInvolvingVertex(Vertex v)
1083 {
1084 ArrayList<Ring> rings = new ArrayList<Ring>();
1085 for (Ring r : gRings)
1086 {
1087 if (r.contains(v))
1088 {
1089 rings.add(r);
1090 }
1091 }
1092 return rings;
1093 }
1094
1095//------------------------------------------------------------------------------
1096
1103 public ArrayList<Ring> getRingsInvolvingVertex(Vertex[] vs)
1104 {
1105 ArrayList<Ring> rings = new ArrayList<Ring>();
1106 for (Ring r : gRings)
1107 {
1108 boolean matchesAll = true;
1109 for (int i=0; i<vs.length; i++)
1110 {
1111 if (!r.contains(vs[i]))
1112 {
1113 matchesAll = false;
1114 break;
1115 }
1116 }
1117 if (matchesAll)
1118 {
1119 rings.add(r);
1120 }
1121 }
1122 return rings;
1123 }
1124
1125//------------------------------------------------------------------------------
1126
1127 public ArrayList<Ring> getRingsInvolvingVertexID(int vid)
1128 {
1129 ArrayList<Ring> rings = new ArrayList<Ring>();
1130 for (Ring r : gRings)
1131 {
1132 if (r.containsID(vid))
1133 {
1134 rings.add(r);
1135 }
1136 }
1137 return rings;
1138 }
1139
1140//------------------------------------------------------------------------------
1141
1148 public boolean hasRings()
1149 {
1150 return gRings.size() > 0;
1151 }
1152
1153//------------------------------------------------------------------------------
1154
1160 public boolean isConnected()
1161 {
1162 // edge case: empty graph is connected
1163 if (gVertices.isEmpty())
1164 {
1165 return true;
1166 }
1167 Set<Vertex> visited = exploreGraph(gVertices.get(0), new HashSet<Vertex>());
1168 return visited.size() == gVertices.size();
1169 }
1170
1171//------------------------------------------------------------------------------
1172
1180 public boolean hasOrEmbedsRings()
1181 {
1182 if (gRings.size() > 0)
1183 return true;
1184 for (Vertex v : gVertices)
1185 {
1186 if (!(v instanceof Template))
1187 continue;
1188
1189 Template t = (Template) v;
1191 return true;
1192 }
1193 return false;
1194 }
1195
1196//------------------------------------------------------------------------------
1197
1198 public boolean isVertexIDInRing(int vid)
1199 {
1200 boolean result = false;
1201 for (Ring r : gRings)
1202 {
1203 if (r.containsID(vid))
1204 {
1205 result = true;
1206 break;
1207 }
1208 }
1209 return result;
1210 }
1211
1212//------------------------------------------------------------------------------
1213
1214 public boolean isVertexInRing(Vertex v)
1215 {
1216 boolean result = false;
1217 for (Ring r : gRings)
1218 {
1219 if (r.contains(v))
1220 {
1221 result = true;
1222 break;
1223 }
1224 }
1225 return result;
1226 }
1227
1228//------------------------------------------------------------------------------
1229
1236 public ArrayList<Vertex> getRCVertices()
1237 {
1238 ArrayList<Vertex> rcvLst = new ArrayList<Vertex>();
1239 for (Vertex v : gVertices)
1240 {
1241 if (v.isRCV())
1242 {
1243 rcvLst.add(v);
1244 }
1245 }
1246 return rcvLst;
1247 }
1248
1249//------------------------------------------------------------------------------
1250
1258 public ArrayList<Vertex> getFreeRCVertices()
1259 {
1260 ArrayList<Vertex> rcvLst = getRCVertices();
1261 ArrayList<Vertex> free = new ArrayList<Vertex>();
1262 for (Vertex v : rcvLst)
1263 {
1264 if (!isVertexInRing(v))
1265 {
1266 free.add(v);
1267 }
1268 }
1269 return free;
1270 }
1271
1272//------------------------------------------------------------------------------
1273
1281 public ArrayList<Vertex> getUsedRCVertices()
1282 {
1283 ArrayList<Vertex> used = new ArrayList<Vertex>();
1284 used.addAll(getRCVertices());
1285 used.removeAll(getFreeRCVertices());
1286 return used;
1287 }
1288
1289//------------------------------------------------------------------------------
1290
1295 public void addEdge(Edge edge)
1296 {
1297 gEdges.add(edge);
1298 jGraph = null;
1299 jGraphKernel = null;
1300 }
1301
1302//------------------------------------------------------------------------------
1303
1304 public void addRing(Ring ring)
1305 {
1306 gRings.add(ring);
1307 jGraph = null;
1308 jGraphKernel = null;
1309 }
1310
1311//------------------------------------------------------------------------------
1312
1321 public void addRing(Vertex vI, Vertex vJ)
1322 throws DENOPTIMException
1323 {
1324 // Presently we assume that RCVs are single-bonded to their parents, so
1325 // we assume the direction of any edge to a RCV:
1326 BondType bndTypI = vI.getEdgeToParent().getBondType();
1327 BondType bndTypJ = vJ.getEdgeToParent().getBondType();
1328 // This assumption can be replaced by more general assumption that RCVs
1329 // are single-bonded:
1330 /*
1331 if (vI.getAP(0) != null)
1332 {
1333 bndTypI = vI.getAP(0).getBondType();
1334 }
1335 if (vJ.getAP(0) != null)
1336 {
1337 bndTypJ = vJ.getAP(0).getBondType();
1338 }
1339 */
1340
1341 if (bndTypI != bndTypJ)
1342 {
1343 String s = "Attempt to close rings is not compatible "
1344 + "to the different bond type specified by the "
1345 + "head and tail APs: (" + bndTypI + "!="
1346 + bndTypJ + " for vertices " + vI + " "
1347 + vJ + ")";
1348 throw new DENOPTIMException(s);
1349 }
1350 addRing(vI,vJ,bndTypI);
1351 jGraph = null;
1352 jGraphKernel = null;
1353 }
1354
1355//------------------------------------------------------------------------------
1356
1364 public void addRing(Vertex vI, Vertex vJ, BondType bndTyp)
1365 {
1366 PathSubGraph path = null;
1367 try {
1368 path = new PathSubGraph(vI,vJ);
1369 } catch (DENOPTIMException e) {
1370 e.printStackTrace();
1371 }
1372 ArrayList<Vertex> arrLst = new ArrayList<Vertex>();
1373 arrLst.addAll(path.getVertecesPath());
1374 Ring ring = new Ring(arrLst);
1375 ring.setBondType(bndTyp);
1376 this.addRing(ring);
1377 jGraph = null;
1378 jGraphKernel = null;
1379 }
1380
1381//------------------------------------------------------------------------------
1382
1391 public void addVertex(Vertex vertex) throws DENOPTIMException
1392 {
1393 if (containsVertexID(vertex.getVertexId()))
1394 throw new DENOPTIMException("Vertex must have a VertexID that is "
1395 + "unique within the graph. VertexID '"
1396 + vertex.getVertexId()+ "' already present in graph "
1397 + getGraphId());
1398 vertex.setGraphOwner(this);
1399 gVertices.add(vertex);
1400 jGraph = null;
1401 jGraphKernel = null;
1402 }
1403
1404//------------------------------------------------------------------------------
1405
1413 public void removeVertex(Vertex vertex)
1414 {
1415 if (!gVertices.contains(vertex))
1416 {
1417 return;
1418 }
1419
1420 vertex.resetGraphOwner();
1421 long vid = vertex.getVertexId();
1422
1423 // delete also any ring involving the removed vertex
1424 if (isVertexInRing(vertex))
1425 {
1426 ArrayList<Ring> rToRm = getRingsInvolvingVertex(vertex);
1427 for (Ring r : rToRm)
1428 {
1429 removeRing(r);
1430 }
1431 }
1432
1433 // remove edges involving the removed vertex
1434 ArrayList<Edge> eToDel = new ArrayList<>();
1435 for (int i=0; i<gEdges.size(); i++)
1436 {
1437 Edge edge = gEdges.get(i);
1438 if (vid == edge.getTrgVertex())
1439 {
1440 eToDel.add(edge);
1441 }
1442 // NB: the following allows to break the spanning tree
1443 if (vid == edge.getSrcVertex())
1444 {
1445 eToDel.add(edge);
1446 }
1447 }
1448 for (Edge e : eToDel)
1449 {
1450 this.removeEdge(e);
1451 }
1452
1453 //delete the removed vertex from symmetric sets, but leave other vertices
1454 List<SymmetricVertexes> ssToRemove = new ArrayList<SymmetricVertexes>();
1456 {
1457 if (ss.contains(vertex))
1458 {
1459 if (ss.size() < 3)
1460 {
1461 ssToRemove.add(ss);
1462 }
1463 else
1464 {
1465 ss.remove(vertex);
1466 }
1467 }
1468 }
1469 symVertices.removeAll(ssToRemove);
1470
1471 // remove the vertex from the graph
1472 gVertices.remove(vertex);
1473
1474 jGraph = null;
1475 jGraphKernel = null;
1476 }
1477
1478//------------------------------------------------------------------------------
1479
1489 public boolean removeVertexAndWeld(Vertex vertex,
1490 FragmentSpace fragSpace) throws DENOPTIMException
1491 {
1492 if (!gVertices.contains(vertex))
1493 {
1494 return false;
1495 }
1496
1497 List<Vertex> symSites = getSymVerticesForVertex(vertex);
1498 if (symSites.size() == 0)
1499 {
1500 symSites.add(vertex);
1501 } else {
1502 //TODO-V3 flip coin to decide if this should be a symmetric operation or not
1503 }
1504 for (Vertex oldLink : symSites)
1505 {
1507 if (!removeSingleVertexAndWeld(oldLink, fragSpace))
1508 {
1509 return false;
1510 }
1511 }
1512 // Reject deletions that cause the collapse of a 3-atom ring into a
1513 // loop (i.e., 1-atom ring) or multiple connection (i.e., a 3-atom ring)
1514 for (Ring r : gRings)
1515 {
1516 // 3 = 1 actual vertex + 2 RCVs
1517 if (r.getSize()!=3)
1518 continue;
1519
1520 AttachmentPoint apH = r.getHeadVertex().getEdgeToParent()
1521 .getSrcAPThroughout();
1522 AttachmentPoint apT = r.getTailVertex().getEdgeToParent()
1523 .getSrcAPThroughout();
1524
1525 if (apH.hasSameSrcAtom(apT) || apH.hasConnectedSrcAtom(apT))
1526 return false;
1527 }
1528 return true;
1529 }
1530
1531//------------------------------------------------------------------------------
1532
1541 public boolean removeSingleVertexAndWeld(Vertex vertex,
1542 FragmentSpace fragSpace) throws DENOPTIMException
1543 {
1544 if (!gVertices.contains(vertex))
1545 {
1546 return false;
1547 }
1548 if (vertex == getSourceVertex())
1549 {
1550 // Make sure there is something to weld, or give up. This to avoid
1551 // trying to remove the scaffold vertex (i.e., a vertex that has no
1552 // parents in this graph and the APs of which are only user as
1553 // source APs)
1554 boolean foundLinkToParent = false;
1555 for (AttachmentPoint ap : vertex.getAttachmentPoints())
1556 {
1557 if (ap.isAvailable() && !ap.isAvailableThroughout())
1558 {
1559 if (!ap.isSrcInUserThroughout())
1560 foundLinkToParent = true;
1561 }
1562 }
1563 if (!foundLinkToParent)
1564 return false;
1565
1566 // When we try to remove the only vertex inside a template, we
1567 // are removing the template itself
1568 if (gVertices.size()==1 && templateJacket!=null)
1569 {
1571 templateJacket, fragSpace);
1572 }
1573 }
1574
1575 // Get all APs that we'll try to weld into the parent
1576 ArrayList<AttachmentPoint> needyAPsOnChildren =
1577 new ArrayList<AttachmentPoint>();
1578 // And all APs where we could weld onto
1579 ArrayList<AttachmentPoint> freeAPsOnParent =
1580 new ArrayList<AttachmentPoint>();
1581 // vertex.getAPsFromChilddren(); //No, because it enter templates
1582 Map<AttachmentPoint,AttachmentPoint> apOnOldToNeedyAP =
1583 new HashMap<AttachmentPoint,AttachmentPoint>();
1584 for (AttachmentPoint apOnOld : vertex.getAttachmentPoints())
1585 {
1586 if (!apOnOld.isAvailableThroughout())
1587 {
1588 if (apOnOld.isSrcInUserThroughout())
1589 {
1590 // Links that depart from vertex
1591 AttachmentPoint needyAP =
1592 apOnOld.getLinkedAPThroughout();
1593 // NB: here do not use getSrcThroughout because it would
1594 // enter trg templates rather than staying on their surface.
1595 needyAPsOnChildren.add(needyAP);
1596 apOnOldToNeedyAP.put(apOnOld, needyAP);
1597 } else {
1598 AttachmentPoint apOnParent =
1599 apOnOld.getLinkedAPThroughout();
1600 // NB: here do not use getSrcThroughout because it would
1601 // enter src templates rather than staying on their surface.
1602 freeAPsOnParent.add(apOnParent);
1603 freeAPsOnParent.addAll(apOnParent.getOwner()
1605 }
1606 }
1607 }
1608
1609 // Get all possible parentAPs-childAPs mappings
1610 List<APMapping> mappings = fragSpace.mapAPClassCompatibilities(
1611 freeAPsOnParent, needyAPsOnChildren, 500);
1612 if (mappings.size() == 0)
1613 {
1614 // No APClass-compatible possibility of removing the link.
1615 return false;
1616 }
1617
1618 // Score mapping to prioritise those that preserve rings.
1619 // This to differentiate from the combination of DELETE+EXTEND operation
1620 // which cannot preserve rings.
1621 List<Integer> preferences = new ArrayList<Integer>();
1622 // Score rings in this level's graph
1623 for (int i=0; i<needyAPsOnChildren.size(); i++)
1624 {
1625 AttachmentPoint needyAP = needyAPsOnChildren.get(i);
1626 preferences.add(0);
1627
1628 Vertex ownerOfNeedy = needyAP.getOwner();
1629 for (Ring r : ownerOfNeedy.getGraphOwner()
1630 .getRingsInvolvingVertex(ownerOfNeedy))
1631 {
1632 // NB: here we stay at the level of the graph owning ownerOfNeedy
1633 Vertex lastBeforeOwnerOfNeedy =
1634 needyAP.getLinkedAP().getOwner();
1635 if (r.contains(lastBeforeOwnerOfNeedy))
1636 {
1637 preferences.set(i, preferences.get(i) + 1);
1638 }
1639 }
1640 }
1641
1642 // Choose best scoring mapping
1643 int maxScore = Integer.MIN_VALUE;
1644 APMapping bestScoringMapping = null;
1645 for (APMapping apm : mappings)
1646 {
1647 int score = 0;
1648 for (AttachmentPoint ap : apm.values())
1649 {
1650 score = score + preferences.get(needyAPsOnChildren.indexOf(ap));
1651 }
1652 if (score > maxScore)
1653 {
1654 maxScore = score;
1655 bestScoringMapping = apm;
1656 }
1657 }
1658
1659 APMapping bestScoringMappingReverse = new APMapping();
1660 for (Entry<AttachmentPoint, AttachmentPoint> e :
1661 bestScoringMapping.entrySet())
1662 {
1663 bestScoringMappingReverse.put(e.getValue(), e.getKey());
1664 }
1665
1666 // Update rings involving vertex directly (i.e., in this graph)
1667 ArrayList<Ring> rToEdit = getRingsInvolvingVertex(vertex);
1668 ArrayList<Ring> ringsToRemove = new ArrayList<Ring>();
1669 for (Ring r : rToEdit)
1670 {
1671 r.removeVertex(vertex);
1672 if (r.getSize() < 3)
1673 ringsToRemove.add(r);
1674 }
1675 for (Ring r : ringsToRemove)
1676 {
1677 removeRing(r);
1678 }
1679
1680 // Remove edges to/from old vertex, while keeping track of edits to do
1681 // in a hypothetical jacket template (if such template exists)
1682 LinkedHashMap<AttachmentPoint,AttachmentPoint> newInReplaceOldInInTmpl =
1683 new LinkedHashMap<AttachmentPoint,AttachmentPoint>();
1684 List<AttachmentPoint> oldAPToRemoveFromTmpl =
1685 new ArrayList<AttachmentPoint>();
1686 for (AttachmentPoint oldAP : vertex.getAttachmentPoints())
1687 {
1688 if (oldAP.isAvailable())
1689 {
1690 // NB: if this graph is embedded in a template, free/available
1691 // APs at this level (and sources at the vertex we are removing)
1692 // are mapped on the jacket templates' surface, and must be
1693 // removed.
1694 if (templateJacket!=null)
1695 {
1696 if (!oldAP.isAvailableThroughout())
1697 {
1698 AttachmentPoint lAP =
1699 oldAP.getLinkedAPThroughout();
1700 if (bestScoringMapping.keySet().contains(lAP))
1701 {
1702 newInReplaceOldInInTmpl.put(
1703 bestScoringMapping.get(lAP), oldAP);
1704 } else if (bestScoringMapping.values().contains(lAP))
1705 {
1706 newInReplaceOldInInTmpl.put(
1707 bestScoringMappingReverse.get(lAP), oldAP);
1708 } else {
1709 oldAPToRemoveFromTmpl.add(oldAP);
1710 }
1711 } else {
1712 oldAPToRemoveFromTmpl.add(oldAP);
1713 }
1714 }
1715 } else {
1716 removeEdge(oldAP.getEdgeUser());
1717 }
1718 }
1719
1720 // Update pointers in symmetric sets in this graph level
1721 // NB: this deals only with the symmetric relations of the removed vertex
1722 // The symm. relations of other removed child vertices are dealt with
1723 // when removing those vertices.
1724 List<SymmetricVertexes> ssToRemove = new ArrayList<SymmetricVertexes>();
1725 Iterator<SymmetricVertexes> ssIter = getSymSetsIterator();
1726 while (ssIter.hasNext())
1727 {
1728 SymmetricVertexes ss = ssIter.next();
1729 if (ss.contains(vertex))
1730 {
1731 ss.remove(vertex);
1732 }
1733 if (ss.size() < 2)
1734 ssToRemove.add(ss);
1735 }
1736 symVertices.removeAll(ssToRemove);
1737
1738 // Remove the vertex
1739 getVertexList().remove(vertex);
1740 vertex.resetGraphOwner();
1741
1742 // Add new edges (within the graph owning the removed vertex)
1743 List<AttachmentPoint> reconnettedApsOnChilds =
1744 new ArrayList<AttachmentPoint>();
1745 for (Entry<AttachmentPoint,AttachmentPoint> e :
1746 bestScoringMapping.entrySet())
1747 {
1748 AttachmentPoint apOnParent = e.getKey();
1749 AttachmentPoint apOnChild = e.getValue();
1750 if (containsVertex(apOnChild.getOwner())
1751 && containsVertex(apOnParent.getOwner()))
1752 {
1753 Edge edge = new Edge(apOnParent,apOnChild,
1754 apOnParent.getAPClass().getBondType());
1755 addEdge(edge);
1756 reconnettedApsOnChilds.add(apOnChild);
1757 } else {
1758 if (templateJacket!=null)
1759 {
1760 if (containsVertex(apOnParent.getOwner()))
1761 {
1763 newInReplaceOldInInTmpl.get(apOnParent), //AP on old vertex
1764 apOnParent);
1765 reconnettedApsOnChilds.add(apOnChild);
1766 }
1767 if (containsVertex(apOnChild.getOwner()))
1768 {
1770 newInReplaceOldInInTmpl.get(apOnChild), //AP on old vertex
1771 apOnChild);
1772 reconnettedApsOnChilds.add(apOnChild);
1773 }
1774 // The case where neither is contained in 'this' cannot
1775 // occur because of the initial checks that identify
1776 // attempts to remove the only vertex inside a template.
1777 } else {
1778 DENOPTIMException de = new DENOPTIMException("AP '"
1779 + apOnChild + "' seems connected to a template, "
1780 + "no template was found. Possible bug!");
1781 throw de;
1782 }
1783 }
1784 }
1785
1786 // update the mapping of this vertex's APs in the jacket template
1787 if (templateJacket!=null)
1788 {
1789 // Remove all APs that existed only in the old vertex
1790 for (AttachmentPoint apOnOld : oldAPToRemoveFromTmpl)
1791 {
1793 }
1794 }
1795
1796 // Remove branches of child-APs that were not mapped/done
1797 for (AttachmentPoint apOnChild : needyAPsOnChildren)
1798 {
1799 if (!reconnettedApsOnChilds.contains(apOnChild))
1800 {
1801 removeOrphanBranchStartingAt(apOnChild.getOwner());
1802 }
1803 }
1804
1805 jGraph = null;
1806 jGraphKernel = null;
1807
1808 return !this.containsVertex(vertex);
1809 }
1810
1811//------------------------------------------------------------------------------
1812
1820 public void removeVertexAndSymmetricOnes(Vertex v, boolean symmetry)
1821 {
1822 if (hasSymmetryInvolvingVertex(v) && symmetry)
1823 {
1825 for (Vertex sv : ss)
1826 {
1827 removeVertex(sv);
1828 }
1829 symVertices.remove(ss);
1830 }
1831 else
1832 {
1833 removeVertex(v);
1834 }
1835 }
1836
1837//------------------------------------------------------------------------------
1838
1847 throws DENOPTIMException
1848 {
1849 List<Vertex> rcvToReplace = new ArrayList<Vertex>();
1850 List<AttachmentPoint> apToCap = new ArrayList<AttachmentPoint>();
1851 for (Vertex v : getRCVertices())
1852 {
1853 if (getRingsInvolvingVertex(v).size()==0
1854 && v.getEdgeToParent()!=null)
1855 {
1856 rcvToReplace.add(v);
1857 apToCap.add(v.getEdgeToParent().getSrcAP());
1858 }
1859 }
1860 for (int i=0; i<rcvToReplace.size(); i++)
1861 {
1862 Vertex v = rcvToReplace.get(i);
1863 removeVertex(v);
1864
1865 AttachmentPoint apOnParent = apToCap.get(i);
1866 APClass cappAPClass = fragSpace.getAPClassOfCappingVertex(
1867 apOnParent.getAPClass());
1868
1869 if (cappAPClass != null)
1870 {
1871 Vertex capVrt = fragSpace.getCappingVertexWithAPClass(
1872 cappAPClass);
1873 capVrt.setVertexId(v.getVertexId());
1874 appendVertexOnAP(apOnParent, capVrt.getAP(0));
1875 }
1876 }
1877 }
1878
1879//------------------------------------------------------------------------------
1880
1889 {
1890 //Remove previous labeling
1891 for (Vertex v : gVertices)
1892 v.removeProperty(DENOPTIMConstants.VRTSYMMSETID);
1893
1894 Iterator<SymmetricVertexes> ssIter = getSymSetsIterator();
1895 int i = 0;
1896 while (ssIter.hasNext())
1897 {
1898 SymmetricVertexes ss = ssIter.next();
1899 String symmLabel = ss.hashCode() + "-" + i;
1900 for (Vertex v : ss)
1901 {
1902 v.setProperty(DENOPTIMConstants.VRTSYMMSETID, symmLabel);
1903 }
1904 i++;
1905 }
1906 for (Vertex v : gVertices)
1907 {
1908 i++;
1909 if (!v.hasProperty(DENOPTIMConstants.VRTSYMMSETID))
1910 v.setProperty(DENOPTIMConstants.VRTSYMMSETID, v.hashCode()+"-"+i);
1911 }
1912 }
1913
1914//------------------------------------------------------------------------------
1915
1921 {
1922 Map<String,List<Vertex>> collectedLabels = new HashMap<>();
1923 for (Vertex v : gVertices)
1924 {
1925 if (v.hasProperty(DENOPTIMConstants.VRTSYMMSETID))
1926 {
1927 String label = v.getProperty(
1928 DENOPTIMConstants.VRTSYMMSETID).toString();
1929 if (collectedLabels.containsKey(label))
1930 {
1931 collectedLabels.get(label).add(v);
1932 } else {
1933 List<Vertex> lst = new ArrayList<Vertex>();
1934 lst.add(v);
1935 collectedLabels.put(label, lst);
1936 }
1937 v.removeProperty(DENOPTIMConstants.VRTSYMMSETID);
1938 }
1939 }
1940
1941 for (String label : collectedLabels.keySet())
1942 {
1943 List<Vertex> symmvertices = collectedLabels.get(label);
1944
1945 if (symmvertices.size()>1)
1946 {
1947 SymmetricVertexes ss = null;
1948 for (Vertex v : symmvertices)
1949 {
1951 {
1952 ss = getSymSetForVertex(v);
1953 break;
1954 }
1955 }
1956
1957 if (ss != null)
1958 {
1959 for (Vertex v : symmvertices)
1960 ss.add(v);
1961
1962 } else {
1963 ss = new SymmetricVertexes();
1964 for (Vertex v : symmvertices)
1965 ss.add(v);
1966 try
1967 {
1969 } catch (DENOPTIMException e)
1970 {
1971 //this can never happen because we are testing for
1972 // preliminary existence of an id in the existing sets.
1973 }
1974 }
1975 }
1976 }
1977 }
1978
1979//------------------------------------------------------------------------------
1980
2002 public boolean replaceSubGraph(List<Vertex> subGrpVrtxs,
2003 DGraph incomingGraph,
2004 LinkedHashMap<AttachmentPoint,AttachmentPoint> apMap,
2005 FragmentSpace fragSpace) throws DENOPTIMException
2006 {
2007 for (Vertex vToRemove : subGrpVrtxs)
2008 {
2009 if (!gVertices.contains(vToRemove))
2010 {
2011 return false;
2012 }
2013 }
2014
2015 // Capping groups are removed and, if needed, re-added back
2016 subGrpVrtxs.stream().filter(v -> v.getBuildingBlockType()==BBType.CAP)
2017 .forEach(v -> this.removeVertex(v));
2018 subGrpVrtxs.removeIf(v -> v.getBuildingBlockType()==BBType.CAP);
2019 if (subGrpVrtxs.size() == 0)
2020 {
2021 throw new DENOPTIMException("Capping groups cannot be the only "
2022 + "vertex in a subgraph to replace.");
2023 }
2024
2025 // Refresh the symmetry set labels so that clones of the branch inherit
2026 // the same symmetry set labels.
2027 incomingGraph.reassignSymmetricLabels();
2028
2030
2031 // Verify that also the surrounding of vertices in the lists is
2032 // consistent between subGrpVrtxs and verticesToRemove. Even if the
2033 // two are consistent, there can still be differences in the childs.
2034 List<List<Vertex>> compatibleSymSubGrps = new ArrayList<List<Vertex>>();
2035 for (List<Vertex> symmetricSubGrpVrtx : getSymmetricSubGraphs(subGrpVrtxs))
2036 {
2037 boolean skip = false;
2038 for (int iv=0; iv<subGrpVrtxs.size(); iv++)
2039 {
2040 if (skip)
2041 break;
2042 Vertex oriVs = subGrpVrtxs.get(iv);
2043 Vertex symVs = symmetricSubGrpVrtx.get(iv);
2044 List<Vertex> oriVsChildren = oriVs.getChilddren();
2045 List<Vertex> symVsChildren = symVs.getChilddren();
2046
2047 // NB: oriVsChildren does not include CAPs from the
2048 // initial subgraph, while symVsChildren does include the
2049 // corresponding CAPs.
2050 oriVsChildren.removeIf(v -> v.getBuildingBlockType()==BBType.CAP);
2051 symVsChildren.removeIf(v -> v.getBuildingBlockType()==BBType.CAP);
2052 if (oriVsChildren.size()!=symVsChildren.size())
2053 {
2054 // we continue in the outer loop
2055 skip = true;
2056 continue;
2057 }
2058 for (int ic=0; ic<oriVsChildren.size(); ic++)
2059 {
2060 if (skip)
2061 break;
2062 // We have already checked those in the subgraph
2063 if (subGrpVrtxs.contains(oriVsChildren.get(ic)))
2064 continue;
2065 // We do allow the two child to be different vertices, but
2066 // we avoid having one CAP and one not. this because it will
2067 // lead to having free APs on the parent of the first and
2068 // busy APs on the parent of the second. This prevents
2069 // finding a mapping of the free APs.
2070 if (oriVsChildren.get(ic).getBuildingBlockType()
2071 != symVsChildren.get(ic).getBuildingBlockType())
2072 {
2073 skip = true;
2074 continue;
2075 }
2076 }
2077 }
2078 if (!skip)
2079 compatibleSymSubGrps.add(symmetricSubGrpVrtx);
2080 }
2081 if (compatibleSymSubGrps.size()==0)
2082 throw new DENOPTIMException("Failed to detect autosymmetry.");
2083
2084 for (List<Vertex> verticesToRemove : compatibleSymSubGrps)
2085 {
2086 // Prepare incoming graph
2087 DGraph graphToAdd = incomingGraph.clone();
2088 graphToAdd.renumberGraphVertices();
2089 List<Vertex> vertexAddedToThis = new ArrayList<Vertex>(
2090 graphToAdd.gVertices);
2091
2092 // Prepare subgraph (it already does not contain caps)
2093 removeCappingGroupsFromChilds(verticesToRemove);
2094
2095 // Prepare AP mapping projecting the one for subGrpVrtxs
2096 APMapping localApMap = new APMapping();
2097 for (Map.Entry<AttachmentPoint,AttachmentPoint> e : apMap.entrySet())
2098 {
2099 // WARNING! Assumption that subGrpVrtxs and verticesToRemove
2100 // are sorted accordingly to symmetry, which should be the case.
2101 int vrtPosOnOld = subGrpVrtxs.indexOf(e.getKey().getOwner());
2102 int apPosOnOld = e.getKey().getIndexInOwner();
2103 AttachmentPoint apOnOld = verticesToRemove.get(
2104 vrtPosOnOld).getAP(apPosOnOld);
2105
2106 int vrtPosOnNew = incomingGraph.indexOf(e.getValue().getOwner());
2107 int apPosOnNew = e.getValue().getIndexInOwner();
2108 AttachmentPoint apOnNew = graphToAdd.getVertexAtPosition(
2109 vrtPosOnNew).getAP(apPosOnNew);
2110 localApMap.put(apOnOld,apOnNew);
2111 }
2112
2113 if (!DGraph.replaceSingleSubGraph(localApMap, fragSpace))
2114 {
2115 return false;
2116 }
2117 addCappingGroups(vertexAddedToThis, fragSpace);
2118 }
2120 return true;
2121 }
2122
2123//------------------------------------------------------------------------------
2124
2137 public List<List<Vertex>> getSymmetricSubGraphs(
2138 List<Vertex> subGrpVrtxs) throws DENOPTIMException
2139 {
2140 if (subGrpVrtxs.stream().anyMatch(v -> v.getBuildingBlockType()==BBType.CAP))
2141 throw new DENOPTIMException("Capping groups must not be part of "
2142 + "symmetric subgraphs");
2143
2144 List<List<Vertex>> symSites = new ArrayList<List<Vertex>>();
2145
2146 if (subGrpVrtxs.size()==1)
2147 {
2148 for (Vertex sv : getSymVerticesForVertex(subGrpVrtxs.get(0)))
2149 {
2150 ArrayList<Vertex> lst = new ArrayList<Vertex>();
2151 lst.add(sv);
2152 symSites.add(lst);
2153 }
2154 if (symSites.size()==0)
2155 {
2156 symSites.add(subGrpVrtxs);
2157 }
2158 return symSites;
2159 }
2160
2161 // Identify the (sole) grand parent.
2162 List<Vertex> thoseWithoutParent = new ArrayList<Vertex>();
2163 for (Vertex v : subGrpVrtxs)
2164 {
2165 if (!subGrpVrtxs.contains(v.getParent()))
2166 thoseWithoutParent.add(v);
2167 }
2168 if (thoseWithoutParent.size()!=1)
2169 {
2170 throw new DENOPTIMException("SubGraph has more than one grand "
2171 + "parent.");
2172 }
2173 Vertex sourceOfSubGraph = thoseWithoutParent.get(0);
2174 int numSymmetricSubGraphs = getSymVerticesForVertex(sourceOfSubGraph).size();
2175 if (numSymmetricSubGraphs==0)
2176 {
2177 symSites.add(subGrpVrtxs);
2178 return symSites;
2179 }
2180
2181 // Identify the ends of the subgraph's spanning tree
2182 List<Vertex> thoseWithoutChildren = new ArrayList<Vertex>();
2183 for (Vertex v : subGrpVrtxs)
2184 {
2185 if (Collections.disjoint(v.getChilddren(),subGrpVrtxs))
2186 thoseWithoutChildren.add(v);
2187 }
2188
2189 // We want to verify that all the ends of the subgraph's spanning tree
2190 // have the same number of symmetric partners. This, while collecting
2191 // all ends that are outside the subgraph and are symmetric to any of
2192 // the ends belonging to the subgraph. The first, in fact, are the ends
2193 // of the symmetric subgraphs.
2194 Set<Vertex> upperLimits = new HashSet<Vertex>();
2195 Set<Vertex> doneBySymmetry = new HashSet<Vertex>();
2196 for (Vertex upperLimit : thoseWithoutChildren)
2197 {
2198 // We need to understand how many symmetric vertices are already
2199 // within the subgraph
2200 int numInSubGraphReplicas = 1;
2201
2202 if (doneBySymmetry.contains(upperLimit))
2203 continue;
2204
2205 // These are symmetric vertices that do belong to the subgraph
2206 Set<Vertex> symmSitesOnBranch = new HashSet<Vertex>(
2207 getSymVerticesForVertex(upperLimit));
2208 symmSitesOnBranch.retainAll(subGrpVrtxs);
2209 if (symmSitesOnBranch.size()>0)
2210 {
2211 numInSubGraphReplicas = symmSitesOnBranch.size();
2212 doneBySymmetry.addAll(symmSitesOnBranch);
2213 }
2214
2215 List<Vertex> lst = getSymVerticesForVertex(upperLimit);
2216 if (lst.size() != numInSubGraphReplicas*numSymmetricSubGraphs)
2217 {
2218 // The subgraph is not symmetrically reproduced.
2219 symSites.add(subGrpVrtxs);
2220 return symSites;
2221 }
2222 upperLimits.addAll(lst);
2223 }
2224
2225 for (Vertex symSources : getSymVerticesForVertex(sourceOfSubGraph))
2226 {
2227 List<Vertex> symSubGraph = new ArrayList<Vertex>();
2228 // The source of the symmetric subgraph is always the first!
2229 symSubGraph.add(symSources);
2230 getChildTreeLimited(symSources, symSubGraph, upperLimits);
2231 //NB: Capping groups are not supposed to be in the list.
2232 symSubGraph.removeIf(v -> v.getBuildingBlockType()==BBType.CAP);
2233 if (symSubGraph.size()!=subGrpVrtxs.size())
2234 {
2235 symSites = new ArrayList<List<Vertex>>();
2236 symSites.add(subGrpVrtxs);
2237 return symSites;
2238 }
2239 symSites.add(symSubGraph);
2240 }
2241
2242 return symSites;
2243 }
2244
2245//------------------------------------------------------------------------------
2246
2299 public static boolean replaceSingleSubGraph(APMapping apMapping,
2300 FragmentSpace fragSpace) throws DENOPTIMException
2301 {
2302 // Checks for consistency while identifying vertexes at the interface between
2303 // the two subgraphs.
2304 DGraph receivingGraph = null;
2305 DGraph incomingGraph = null;
2306 Set<Vertex> vertexesOfReceivingGraphToConnectToIncomingGraph = new HashSet<>();
2307 Set<Vertex> vertexesOfIncomingGraphToConnectToReceivingGraph = new HashSet<>();
2308 for (Map.Entry<AttachmentPoint,AttachmentPoint> e : apMapping.entrySet())
2309 {
2310 AttachmentPoint apOnFirtsGraph = e.getKey();
2311 AttachmentPoint apOnIncomingGraph = e.getValue();
2312
2313 // Checks for consistency: APs are mapped to the correct graph
2314 if (receivingGraph == null)
2315 {
2316 receivingGraph = apOnFirtsGraph.getOwner().getGraphOwner();
2317 } else if (receivingGraph != apOnFirtsGraph.getOwner().getGraphOwner())
2318 {
2319 throw new DENOPTIMException("The graph ownership of attachment point "
2320 + apOnFirtsGraph.getID() + " is not the same of the other key APs.");
2321 }
2322 if (incomingGraph == null)
2323 {
2324 incomingGraph = apOnIncomingGraph.getOwner().getGraphOwner();
2325 } else if (incomingGraph != apOnIncomingGraph.getOwner().getGraphOwner())
2326 {
2327 throw new DENOPTIMException("The incoming graph is not the same "
2328 + "for all incoming attachment points.");
2329 }
2330
2331 // collect all vertexes of receiving graph to connect to incoming graph
2332 if (!apOnFirtsGraph.isAvailable()) //stay within template boundaries
2333 {
2334 vertexesOfReceivingGraphToConnectToIncomingGraph.add(
2335 apOnFirtsGraph.getLinkedAP().getOwner());
2336 }
2337
2338 // collect all vertexes of incoming graph to connect to receiving graph
2339 vertexesOfIncomingGraphToConnectToReceivingGraph.add(
2340 apOnIncomingGraph.getOwner());
2341 }
2342
2343 if (receivingGraph == null)
2344 {
2345 throw new DENOPTIMException("The receiving graph is null.");
2346 }
2347 if (incomingGraph == null)
2348 {
2349 throw new DENOPTIMException("The incoming graph is null.");
2350 }
2351 if (incomingGraph.getTemplateJacket() != null)
2352 {
2353 throw new DENOPTIMException("The incoming graph is embedded in a template. "
2354 + "This is not supported.");
2355 }
2356
2357 // Explore receiving graphs to identify vertexes to remove
2358 Set<Vertex> verticesToRemoveFromReceivingGraph = new HashSet<>();
2359 Set<Vertex> verticesToRemoveFromIncomingGraph = new HashSet<>();
2360 for (Map.Entry<AttachmentPoint,AttachmentPoint> e : apMapping.entrySet())
2361 {
2362 AttachmentPoint apOnReceivingGraph = e.getKey();
2363 AttachmentPoint apOnIncomingGraph = e.getValue();
2364
2365 // On receiving graph the AP is on a vertex to delete
2366 Vertex vToDelOnRecGraph = apOnReceivingGraph.getOwner();
2367 verticesToRemoveFromReceivingGraph.add(vToDelOnRecGraph);
2368 DGraph.exploreGraph(vToDelOnRecGraph,
2369 vertexesOfReceivingGraphToConnectToIncomingGraph, // these stop the exploration
2370 verticesToRemoveFromReceivingGraph); // these are those visited by the exploration
2371
2372 // On incoming graph the AP is on a vertex to keep
2373 if (!apOnIncomingGraph.isAvailable()) //stay within template boundaries
2374 {
2375 Vertex vToRemoveOnIncoming = apOnIncomingGraph.getLinkedAP().getOwner();
2376 verticesToRemoveFromIncomingGraph.add(vToRemoveOnIncoming);
2377 DGraph.exploreGraph(vToRemoveOnIncoming,
2378 vertexesOfIncomingGraphToConnectToReceivingGraph, // these stop the exploration
2379 verticesToRemoveFromIncomingGraph); // these are those visited by the exploration
2380 }
2381 }
2382
2383 // Check that the AP mapping defines two confined subgraphs: no vertex is
2384 // both connected to the branch to delete AND to the branch to keep.
2385 for (Vertex vToDelOnRecGraph : verticesToRemoveFromReceivingGraph)
2386 {
2387 for (AttachmentPoint ap : vToDelOnRecGraph.getAttachmentPoints())
2388 {
2389 // NB: I write it like this so it is more readable: the order
2390 // in which we check these conditions matters!
2391 if (!ap.isAvailable())
2392 {
2393 if (vertexesOfReceivingGraphToConnectToIncomingGraph.contains(
2394 ap.getLinkedAP().getOwner()))
2395 {
2396 if (!apMapping.keySet().contains(ap))
2397 {
2398 throw new DENOPTIMException(
2399 "The AP mapping does not define confined subgraphs "
2400 + "for receiving graph " + receivingGraph.getGraphId()+".");
2401 }
2402 }
2403 }
2404 }
2405 }
2406 for (Vertex vToDelOnIncGraph : verticesToRemoveFromIncomingGraph)
2407 {
2408 for (AttachmentPoint ap : vToDelOnIncGraph.getAttachmentPoints())
2409 {
2410 // NB: I write it like this so it is more readable: the order
2411 // in which we check these conditions matters!
2412 if (!ap.isAvailable())
2413 {
2414 if (vertexesOfIncomingGraphToConnectToReceivingGraph.contains(
2415 ap.getLinkedAP().getOwner()))
2416 {
2417 if (!apMapping.values().contains(ap.getLinkedAP()))
2418 {
2419 throw new DENOPTIMException(
2420 "The AP mapping does not define confined subgraphs "
2421 + "for incoming graph " + incomingGraph.getGraphId()+".");
2422 }
2423 }
2424 }
2425 }
2426 }
2427
2428 // Keep track of the edge type currently used by either APs on the interface
2429 // between the two subgraphs.
2430 LinkedHashMap<AttachmentPoint,AttachmentPoint> linksToCreate = new LinkedHashMap<>();
2431 LinkedHashMap<AttachmentPoint,BondType> linkTypesToCreate = new LinkedHashMap<>();
2432 LinkedHashMap<AttachmentPoint,Boolean> linkDirectionToCreate = new LinkedHashMap<>();
2433 for (Map.Entry<AttachmentPoint,AttachmentPoint> e : apMapping.entrySet())
2434 {
2435 AttachmentPoint apOnReceivingGraph = e.getKey();
2436 AttachmentPoint apOnIncomingGraph = e.getValue();
2437
2438 if (apOnReceivingGraph.isAvailable() && apOnIncomingGraph.isAvailable())
2439 {
2440 continue;
2441 }
2442
2443 BondType bondTypeOnRecGraph = null;
2444 Boolean directionIsThisToIncoming = true;
2445 if (!apOnReceivingGraph.isAvailable())
2446 {
2447 bondTypeOnRecGraph = apOnReceivingGraph.getEdgeUser().getBondType();
2448 directionIsThisToIncoming = !apOnReceivingGraph.isSrcInUser();
2449 }
2450 BondType bondTypeOnIncoming = null;
2451 if (!apOnIncomingGraph.isAvailable())
2452 {
2453 bondTypeOnIncoming = apOnIncomingGraph.getEdgeUser().getBondType();
2454 }
2455 if (bondTypeOnRecGraph != null && bondTypeOnIncoming != null
2456 && bondTypeOnRecGraph != bondTypeOnIncoming)
2457 {
2458 throw new DENOPTIMException("The edge type on the interface "
2459 + "between the two subgraphs is not the : "
2460 + bondTypeOnRecGraph + " != " + bondTypeOnIncoming + ".");
2461 }
2462 linkTypesToCreate.put(apOnIncomingGraph, bondTypeOnRecGraph);
2463 linksToCreate.put(apOnIncomingGraph,apOnReceivingGraph.getLinkedAP());
2464 linkDirectionToCreate.put(apOnIncomingGraph,directionIsThisToIncoming);
2465 }
2466
2467 // Keep track of the rings on each of the two graphs
2468 List<Ring> ringFromReceivingGraph = new ArrayList<Ring>();
2469 for (Ring ring : receivingGraph.getRings())
2470 {
2471 if (verticesToRemoveFromReceivingGraph.contains(ring.getHeadVertex())
2472 || verticesToRemoveFromReceivingGraph.contains(ring.getTailVertex()))
2473 {
2474 continue;
2475 }
2476 ringFromReceivingGraph.add(ring);
2477 }
2478 List<Ring> ringFromIncomingGraph = new ArrayList<Ring>();
2479 for (Ring ring : incomingGraph.getRings())
2480 {
2481 if (verticesToRemoveFromIncomingGraph.contains(ring.getHeadVertex())
2482 || verticesToRemoveFromIncomingGraph.contains(ring.getTailVertex()))
2483 {
2484 continue;
2485 }
2486 ringFromIncomingGraph.add(ring);
2487 }
2488
2489 // Collect APs from the vertices that will be removed from receiving graph,
2490 // and that might be reflected onto the jacket template or used to make links
2491 // to the rest of the graph.
2492 List<AttachmentPoint> interfaceApsOnReceivingGraph = new ArrayList<AttachmentPoint>();
2493 for (Vertex vToDelOnReceivingGraph : verticesToRemoveFromReceivingGraph)
2494 {
2495 for (AttachmentPoint ap : vToDelOnReceivingGraph.getAttachmentPoints())
2496 {
2497 if (ap.isAvailable())
2498 {
2499 // being available, this AP might be reflected onto
2500 // jacket template, so we'll have to remove it from the template.
2501 interfaceApsOnReceivingGraph.add(ap);
2502 } else {
2503 Vertex user = ap.getLinkedAP().getOwner();
2504 if (!verticesToRemoveFromReceivingGraph.contains(user))
2505 {
2506 // this AP is used to make a link to the rest of the graph,
2507 // so we'll have to verify it is replaced by a new AP.
2508 interfaceApsOnReceivingGraph.add(ap);
2509 }
2510 }
2511 }
2512 }
2513 List<AttachmentPoint> interfaceApsOnIncomingGraph = new ArrayList<AttachmentPoint>();
2514 for (Vertex vFromIncomingGraph : incomingGraph.gVertices)
2515 {
2516 if (verticesToRemoveFromIncomingGraph.contains(vFromIncomingGraph))
2517 {
2518 continue;
2519 }
2520 for (AttachmentPoint ap : vFromIncomingGraph.getAttachmentPoints())
2521 {
2522 if (ap.isAvailable())
2523 {
2524 // being available, this AP might be reflected onto
2525 // jacket template
2526 interfaceApsOnIncomingGraph.add(ap);
2527 } else {
2528 Vertex user = ap.getLinkedAP().getOwner();
2529 if (verticesToRemoveFromIncomingGraph.contains(user))
2530 {
2531 interfaceApsOnIncomingGraph.add(ap);
2532 }
2533 }
2534 }
2535 }
2536
2537 // Keep track of the relation any free APs may have with a possible template
2538 // that embeds the graph.
2539 LinkedHashMap<AttachmentPoint,AttachmentPoint>
2540 inToOutAPForTemplateOnReceivingGraph = new LinkedHashMap<>();
2541 List<AttachmentPoint> oldAPToRemoveFromTmplOfReceivingGraph = new ArrayList<>();
2542 for (AttachmentPoint intphAPOnReceivingGraph : interfaceApsOnReceivingGraph)
2543 {
2544 if (intphAPOnReceivingGraph.isAvailable())
2545 {
2546 // NB: if receiving graph is embedded in a template, free/available
2547 // APs at this level are mapped on the templates' surface
2548 if (receivingGraph.templateJacket!=null)
2549 {
2550 if (intphAPOnReceivingGraph.isAvailableThroughout())
2551 {
2552 if (!apMapping.containsKey(intphAPOnReceivingGraph))
2553 {
2554 // An AP of the old link is going to be removed from the
2555 // template-jacket's list of APs
2556 oldAPToRemoveFromTmplOfReceivingGraph.add(intphAPOnReceivingGraph);
2557 } else {
2558 // This AP is not used, not even outside of the template
2559 // but for some reason the apMapping wants to keep it
2560 inToOutAPForTemplateOnReceivingGraph.put(
2561 apMapping.get(intphAPOnReceivingGraph),intphAPOnReceivingGraph);
2562 }
2563 } else {
2564 if (!apMapping.containsKey(intphAPOnReceivingGraph))
2565 {
2566 throw new DENOPTIMException("Cannot replace subgraph "
2567 + "if a used AP has no mapping.");
2568 } else {
2569 // This AP is not used, not even outside of the template
2570 // but for some reason the apMapping wants to keep it
2571 inToOutAPForTemplateOnReceivingGraph.put(
2572 apMapping.get(intphAPOnReceivingGraph),intphAPOnReceivingGraph);
2573 }
2574 }
2575 }
2576 }
2577 }
2578
2579 // Remove the vertexes to remove from the graphs
2580 for (Vertex v : verticesToRemoveFromReceivingGraph)
2581 {
2582 receivingGraph.removeVertex(v);
2583 }
2584 for (Vertex v : verticesToRemoveFromIncomingGraph)
2585 {
2586 incomingGraph.removeVertex(v);
2587 }
2588
2589 // we need to guarantee that new vertixe IDs are unique within a graph
2590 incomingGraph.renumberGraphVertices();
2591
2592 // finally introduce the new vertices from incoming graph into receiving graph
2593 for (Vertex incomingVrtx : incomingGraph.getVertexList())
2594 {
2595 receivingGraph.addVertex(incomingVrtx);
2596 }
2597
2598 // import edges from incoming graph
2599 for (Edge incomingEdge : incomingGraph.getEdgeList())
2600 {
2601 receivingGraph.addEdge(incomingEdge);
2602 }
2603
2604 // Do we import symmetric sets from incoming graph?
2605 // No, this method doesn't do it because we want to use it in situations
2606 // where we have to perform multiple replaceSubGraph operations and,
2607 // afterwards, use the symmetric labels to create symmetric sets that
2608 // might span across more than one of the subgraphs that were added.
2609
2610 // Remove all rings in the graph that will become the result: we are about to regenerate
2611 // rings according to the changes to the graph. We do this here to have the possibility
2612 // to create rings while creating the new links as from the AP mapping.
2613 for (Ring ring : ringFromReceivingGraph)
2614 {
2615 receivingGraph.removeRing(ring);
2616 }
2617
2618 // Create the new connections. Keep track of those that have been dealt with
2619 List<AttachmentPoint> doneApsOnNew = new ArrayList<AttachmentPoint>();
2620 for (AttachmentPoint apOnIncomingGraph : linksToCreate.keySet())
2621 {
2622 AttachmentPoint apOnReceivingGraph = linksToCreate.get(apOnIncomingGraph);
2623 boolean directionIsThisToIncoming = linkDirectionToCreate.get(
2624 apOnIncomingGraph);
2625 AttachmentPoint srcAP = apOnReceivingGraph;
2626 AttachmentPoint trgAP = apOnIncomingGraph;
2627 if (!directionIsThisToIncoming)
2628 {
2629 srcAP = apOnIncomingGraph;
2630 trgAP = apOnReceivingGraph;
2631 }
2632 // We must respect the assumption that RCVs are always the target vertex:
2633 if (srcAP.getOwner().isRCV())
2634 {
2635 if (trgAP.getOwner().isRCV())
2636 {
2637 throw new IllegalArgumentException("Two RCV vertices cannot "
2638 + "be both the source and the target of an edge. See RCVs "
2639 + srcAP.getOwner().getVertexId() + " and "
2640 + trgAP.getOwner().getVertexId() + ".");
2641 }
2642 AttachmentPoint tmp = srcAP;
2643 srcAP = trgAP;
2644 trgAP = tmp;
2645 }
2646 boolean makeLinkAsRing = false;
2647 Vertex srcVertex = srcAP.getOwner();
2648 Vertex trgVertex = trgAP.getOwner();
2649 if (srcVertex.isRCV() || trgVertex.isRCV())
2650 {
2651 // It remains possible to request operations that place RCVs in chains
2652 // that have no sense of existing (because RCVs are not expected to be
2653 // connected to other RCVs), but we avoid adding RCVs connected to other
2654 // RCVs. Therefore, is either of the APs belong to an RCV, we do make
2655 // an Edge instead of considering wherther th edge should be replaced
2656 // by a pair of newly added RCVs.
2657 makeLinkAsRing = false;
2658 } else {
2659 // To consider whether to use an edge or a ring, we need to know if
2660 // the two APs are already reachable from each other by a path of edges.
2661 PathSubGraph path = null;
2662 try {
2663 path = new PathSubGraph(srcVertex, trgVertex);
2664 } catch (DENOPTIMException e) {
2665 // No path connects the two APs, so we make an Edge
2666 makeLinkAsRing = false;
2667 }
2668 // NB: since the two APs are guaranteed to be on different vertices,
2669 // the path, if any, will always contain at least one edge.
2670 if (path != null)
2671 {
2672 // There is a path, so we make a ring instead of an Edge
2673 makeLinkAsRing = true;
2674 }
2675 }
2676 if (makeLinkAsRing)
2677 {
2678 Randomizer rng = fragSpace.getRandomizer();
2679 Vertex rcvToSrcAP = null;
2680 List<Vertex> candidateRCVsSrc = fragSpace.getRCVsForAPClass(srcAP.getAPClass());
2681 if (candidateRCVsSrc.size()>0)
2682 {
2683 rcvToSrcAP = rng.randomlyChooseOne(candidateRCVsSrc);
2684 } else {
2685 rcvToSrcAP = FragmentSpace.getPolarizedRCV(true);
2686 }
2687 receivingGraph.appendVertexOnAP(srcAP, rcvToSrcAP.getAP(0));
2688
2689 Vertex rcvToTrgAP = null;
2690 List<Vertex> candidateRCVsTrg = fragSpace.getRCVsForAPClass(trgAP.getAPClass());
2691 if (candidateRCVsTrg.size()>0)
2692 {
2693 rcvToTrgAP = rng.randomlyChooseOne(candidateRCVsTrg);
2694 } else {
2695 rcvToTrgAP = FragmentSpace.getPolarizedRCV(false);
2696 }
2697 receivingGraph.appendVertexOnAP(trgAP, rcvToTrgAP.getAP(0));
2698
2699 receivingGraph.addRing(rcvToSrcAP, rcvToTrgAP,
2700 linkTypesToCreate.get(apOnIncomingGraph));
2701 } else {
2702 Edge edge = new Edge(srcAP,trgAP,
2703 linkTypesToCreate.get(apOnIncomingGraph));
2704 receivingGraph.addEdge(edge);
2705 }
2706 doneApsOnNew.add(apOnIncomingGraph);
2707 }
2708
2709 // Regenerate rings for either of the two graphs, and those simple
2710 // rings that involve only a single RCV-RCV pair but may span across
2711 // more than one subgraph. This works because we search for paths resulting
2712 // only from edges, not from rings.
2713 List<Ring> doneRings = new ArrayList<Ring>();
2714 List<Ring> allRings = new ArrayList<>();
2715 allRings.addAll(ringFromReceivingGraph);
2716 allRings.addAll(ringFromIncomingGraph);
2717 for (Ring ring : allRings)
2718 {
2719 Vertex head = ring.getHeadVertex();
2720 Vertex tail = ring.getTailVertex();
2721 PathSubGraph path = null;
2722 try {
2723 path = new PathSubGraph(head, tail);
2724 } catch (DENOPTIMException e) {
2725 // No path connects the head and tail, so the ring is broken
2726 // but the connection needs to be restored as an edge
2728 }
2729 if (path != null)
2730 {
2731 // If the path is found then this ring belong entirely to one of the two subgraphs
2732 // and can be regenerated in the receiving graph
2733 receivingGraph.addRing(head,tail);
2734 }
2735 // Remove it from the todo list
2736 doneRings.add(ring);
2737 }
2738 for (Ring ring : doneRings) {
2739 allRings.remove(ring);
2740 ringFromReceivingGraph.remove(ring);
2741 ringFromIncomingGraph.remove(ring);
2742 }
2743
2744 // Identify redundant RCV-RCV pairs: those that pertain to the same ring,
2745 // so that one should be replaced by an edge
2746 for (Ring ring : allRings)
2747 {
2748 if (doneRings.contains(ring))
2749 {
2750 continue;
2751 }
2752
2753 // Make the adjacency reflecting the still-missingpossible ring chords
2754 // NB: we have removed RCV pairs that are already transformed into rings or edges
2755 Map<Vertex, List<Vertex>> adjacencyFromRingChords = new HashMap<>();
2756 for (Ring stillMissingRing : Stream.concat(
2757 ringFromReceivingGraph.stream(),
2758 ringFromIncomingGraph.stream()).toList())
2759 {
2760 Vertex head = stillMissingRing.getHeadVertex();
2761 Vertex tail = stillMissingRing.getTailVertex();
2762 adjacencyFromRingChords.computeIfAbsent(head, k -> new ArrayList<Vertex>()).add(tail);
2763 adjacencyFromRingChords.computeIfAbsent(tail, k -> new ArrayList<Vertex>()).add(head);
2764 }
2765
2766 Vertex head = ring.getHeadVertex();
2767 Vertex tail = ring.getTailVertex();
2768 PathSubGraph path = null;
2769 try {
2770 path = new PathSubGraph(head, tail, adjacencyFromRingChords);
2771 } catch (DENOPTIMException e) {
2772 // No path connects the head and tail, do the ring is broken
2773 // but the connection needs to be restored as an edge
2775 // Adjacency will reflect the edge, so we remove it from the list of ring-based adjacency
2776 ringFromReceivingGraph.remove(ring);
2777 ringFromIncomingGraph.remove(ring);
2778 }
2779 if (path != null)
2780 {
2781 // Here we have path that involves more than one RCV pair.
2782 for (int iV=1; iV<(path.getVertecesPath().size()-1); iV++)
2783 {
2784 Vertex v = path.getVertecesPath().get(iV);
2785 if (v.isRCV())
2786 {
2787 // This is a redundant RCV-RCV pair
2788 // Identify the corresponding ring
2789 for (Ring redundantRing : allRings)
2790 {
2791 Vertex redHead = redundantRing.getHeadVertex();
2792 Vertex redTail = redundantRing.getTailVertex();
2793 if (redHead == v || redTail == v)
2794 {
2795 // Replace redundant ring with actual edge
2796 receivingGraph.removeRing(redundantRing);
2797 AttachmentPoint apOnRedHead = redHead.getAP(0).getLinkedAP();
2798 AttachmentPoint apOnRedTail = redTail.getAP(0).getLinkedAP();
2799 receivingGraph.removeVertex(redHead);
2800 receivingGraph.removeVertex(redTail);
2801 receivingGraph.addEdge(new Edge(apOnRedHead, apOnRedTail,
2802 redundantRing.getBondType()));
2803 doneRings.add(redundantRing);
2804 // Remove it from the todo-lists here to reflect this into the next adjacency
2805 ringFromReceivingGraph.remove(ring);
2806 ringFromIncomingGraph.remove(ring);
2807 iV++; //skio next because it is the associated RCV
2808 break;
2809 }
2810 }
2811 }
2812 }
2813 receivingGraph.addRing(head,tail);
2814 }
2815 // Remove it from the todo list
2816 doneRings.add(ring);
2817 }
2818 for (Ring ring : doneRings) {
2819 allRings.remove(ring);
2820 }
2821
2822 // update the mapping of receiving graph's APs onto the jacket template
2823 if (receivingGraph.templateJacket != null)
2824 {
2825 receivingGraph.templateJacket.clearIAtomContainer();
2826 for (AttachmentPoint apOnReceivingGraph : inToOutAPForTemplateOnReceivingGraph.keySet())
2827 {
2828 receivingGraph.templateJacket.updateInnerApID(
2829 inToOutAPForTemplateOnReceivingGraph.get(apOnReceivingGraph),apOnReceivingGraph);
2830 doneApsOnNew.add(apOnReceivingGraph);
2831 }
2832
2833 // Project all remaining APs of new branch on the surface of template
2834 for (AttachmentPoint apOnIncGraph : interfaceApsOnIncomingGraph)
2835 {
2836 if (!doneApsOnNew.contains(apOnIncGraph))
2837 {
2838 receivingGraph.templateJacket.addInnerToOuterAPMapping(apOnIncGraph);
2839 }
2840 }
2841
2842 // Remove all APs that existed only in the old branch
2843 for (AttachmentPoint apOnOld : oldAPToRemoveFromTmplOfReceivingGraph)
2844 {
2845 receivingGraph.templateJacket.removeProjectionOfInnerAP(apOnOld);
2846 }
2847 }
2848
2849 receivingGraph.jGraph = null;
2850 receivingGraph.jGraphKernel = null;
2851
2852 for (AttachmentPoint apOnIncGraph : apMapping.values())
2853 {
2854 Vertex vrtxTakenFromIncGraph = apOnIncGraph.getOwner();
2855 if (!receivingGraph.containsVertex(vrtxTakenFromIncGraph))
2856 {
2857 return false;
2858 }
2859 }
2860 return true;
2861 }
2862
2863//------------------------------------------------------------------------------
2864
2868 private static void replaceChordWithEdge(Ring chord)
2869 {
2870 Vertex head = chord.getHeadVertex();
2871 Vertex tail = chord.getTailVertex();
2872
2873 DGraph graph = head.getGraphOwner();
2874 if (graph==null || graph!=tail.getGraphOwner())
2875 {
2876 throw new IllegalArgumentException("The two RCV to be converted "
2877 + "into an Edge must belong to the same graph.");
2878 }
2879 graph.removeRing(chord);
2880
2881 AttachmentPoint apOnRedHead = head.getAP(0).getLinkedAP();
2882 AttachmentPoint apOnRedTail = tail.getAP(0).getLinkedAP();
2883
2884 graph.removeVertex(head);
2885 graph.removeVertex(tail);
2886
2887 graph.addEdge(new Edge(apOnRedHead, apOnRedTail, chord.getBondType()));
2888 }
2889
2890//------------------------------------------------------------------------------
2891
2908 public boolean replaceVertex(Vertex vertex, int bbId, BBType bbt,
2909 LinkedHashMap<Integer, Integer> apIdMap, FragmentSpace fragSpace)
2910 throws DENOPTIMException
2911 {
2912 return replaceVertex(vertex, bbId, bbt, apIdMap, true, fragSpace);
2913 }
2914
2915//------------------------------------------------------------------------------
2916
2932 public boolean replaceVertex(Vertex vertex, int bbId, BBType bbt,
2933 LinkedHashMap<Integer, Integer> apIdMap, boolean symmetry,
2934 FragmentSpace fragSpace)
2935 throws DENOPTIMException
2936 {
2937 if (!gVertices.contains(vertex))
2938 {
2939 return false;
2940 }
2941
2942 List<Vertex> symSites = new ArrayList<Vertex>();
2943 if (symmetry)
2944 {
2945 symSites = getSymVerticesForVertex(vertex);
2946 }
2947 if (symSites.size() == 0)
2948 {
2949 symSites.add(vertex);
2950 }
2951
2954 GraphUtils.getUniqueVertexIndex(), bbId, bbt, fragSpace);
2955 DGraph incomingGraph = new DGraph();
2956 incomingGraph.addVertex(newLink);
2957 incomingGraph.reassignSymmetricLabels();
2958
2959 for (Vertex oldLink : symSites)
2960 {
2961 DGraph graphAdded = incomingGraph.clone();
2963 oldLink.getUnfilteredMutationTypes());
2964 graphAdded.renumberGraphVertices();
2965
2966 ArrayList<Vertex> oldVertex = new ArrayList<Vertex>();
2967 oldVertex.add(oldLink);
2968 APMapping apMap = new APMapping();
2969 for (Map.Entry<Integer,Integer> e : apIdMap.entrySet())
2970 {
2971 apMap.put(oldLink.getAP(e.getKey()),
2972 graphAdded.getVertexAtPosition(0).getAP(e.getValue()));
2973 }
2974
2975 if (!DGraph.replaceSingleSubGraph(apMap, fragSpace))
2976 {
2977 return false;
2978 }
2979 }
2981 return true;
2982 }
2983
2984//------------------------------------------------------------------------------
2985
3007 //NB: LinkedHashMap is used to retain reproducibility between runs.
3008
3009 public boolean insertVertex(Edge edge, int bbId, BBType bbt,
3010 LinkedHashMap<AttachmentPoint,Integer> apMap,
3011 FragmentSpace fragSpace)
3012 throws DENOPTIMException
3013 {
3014 if (!gEdges.contains(edge))
3015 {
3016 return false;
3017 }
3018
3019 List<Edge> symSites = new ArrayList<Edge> ();
3020 List<LinkedHashMap<AttachmentPoint,Integer>> symApMaps =
3021 new ArrayList<LinkedHashMap<AttachmentPoint,Integer>>();
3022 List<Vertex> symTrgvertices = getSymVerticesForVertex(
3023 edge.getTrgAP().getOwner());
3024 if (symTrgvertices.size() == 0)
3025 {
3026 symSites.add(edge);
3027 symApMaps.add(apMap);
3028 } else {
3029 for (Vertex trgVrtx : symTrgvertices)
3030 {
3031 Edge symEdge = trgVrtx.getEdgeToParent();
3032 symSites.add(symEdge);
3033
3034 LinkedHashMap<AttachmentPoint,Integer> locApMap = new
3035 LinkedHashMap<AttachmentPoint,Integer>();
3036 locApMap.put(symEdge.getSrcAP(), apMap.get(edge.getSrcAP()));
3037 locApMap.put(symEdge.getTrgAP(), apMap.get(edge.getTrgAP()));
3038 symApMaps.add(locApMap);
3039 }
3040 }
3041
3043 for (int i=0; i<symSites.size(); i++)
3044 {
3045 Edge symEdge = symSites.get(i);
3046 LinkedHashMap<AttachmentPoint,Integer> locApMap = symApMaps.get(i);
3047
3050 GraphUtils.getUniqueVertexIndex(), bbId, bbt, fragSpace);
3051 newSS.add(newLink);
3052 LinkedHashMap<AttachmentPoint,AttachmentPoint> apToApMap =
3053 new LinkedHashMap<AttachmentPoint,AttachmentPoint>();
3054 for (AttachmentPoint apOnGraph : locApMap.keySet())
3055 {
3056 apToApMap.put(apOnGraph, newLink.getAP(locApMap.get(apOnGraph)));
3057 }
3058 if (!insertSingleVertex(symEdge, newLink, apToApMap))
3059 {
3060 return false;
3061 }
3062 }
3063 if (newSS.size()>1)
3064 {
3066 }
3067 return true;
3068 }
3069
3070//------------------------------------------------------------------------------
3071
3089 public boolean insertSingleVertex(Edge edge, Vertex newLink,
3090 LinkedHashMap<AttachmentPoint,AttachmentPoint> apMap)
3091 throws DENOPTIMException
3092 {
3093 //TODO: for reproducibility the AP mapping should become an optional
3094 // parameter: if given we try to use it, if not given we GraphLinkFinder
3095 // will try to find a suitable mapping.
3096
3097 if (!gEdges.contains(edge) || gVertices.contains(newLink))
3098 {
3099 return false;
3100 }
3101
3102 // First keep track of the links that will be broken and re-created,
3103 // and also of the relation free APs may have with a possible template
3104 // that embeds this graph.
3105 AttachmentPoint orisEdgeSrc = edge.getSrcAP();
3106 AttachmentPoint orisEdgeTrg = edge.getTrgAP();
3107 Vertex srcVrtx = orisEdgeSrc.getOwner();
3108 Vertex trgVrtx = orisEdgeTrg.getOwner();
3109
3110 removeEdge(edge);
3111
3112 // Introduce the new vertex in the graph
3113 addVertex(newLink);
3114
3115 // Connect the new vertex to the graph
3116 Edge eSrcToLink = new Edge(orisEdgeSrc,
3117 apMap.get(orisEdgeSrc), edge.getBondType());
3118 addEdge(eSrcToLink);
3119 Edge eLinkToTrg = new Edge(apMap.get(orisEdgeTrg),
3120 orisEdgeTrg, edge.getBondType());
3121 addEdge(eLinkToTrg);
3122
3123 // update any affected ring
3124 if (isVertexInRing(srcVrtx) && isVertexInRing(trgVrtx))
3125 {
3126 ArrayList<Ring> rToEdit = new ArrayList<Ring>();
3127 rToEdit.addAll(getRingsInvolvingVertex(srcVrtx));
3128 rToEdit.retainAll(getRingsInvolvingVertex(trgVrtx));
3129 for (Ring r : rToEdit)
3130 {
3131 r.insertVertex(newLink,srcVrtx,trgVrtx);
3132 }
3133 }
3134
3135 // NB: if this graph is embedded in a template, new free/available
3136 // APs introduced with the new link need to be mapped on the surface of
3137 // the template
3138 if (templateJacket != null)
3139 {
3140 for (AttachmentPoint ap : newLink.getAttachmentPoints())
3141 {
3142 if (ap.isAvailable())
3143 {
3145 }
3146 }
3147 }
3148
3149 jGraph = null;
3150 jGraphKernel = null;
3151
3152 return !gEdges.contains(edge) && this.containsVertex(newLink);
3153 }
3154
3155//------------------------------------------------------------------------------
3156
3164 {
3165 return ((pos >= gVertices.size()) || pos < 0) ? null :
3166 gVertices.get(pos);
3167 }
3168
3169//------------------------------------------------------------------------------
3170
3180 {
3181 if (gVertices.contains(v))
3182 return true;
3183
3184 for (Vertex vrt : gVertices)
3185 {
3186 if (vrt instanceof Template)
3187 {
3188 Template t = (Template) vrt;
3190 return true;
3191 }
3192 }
3193 return false;
3194 }
3195
3196
3197//------------------------------------------------------------------------------
3198
3206 public boolean containsVertex(Vertex v)
3207 {
3208 return gVertices.contains(v);
3209 }
3210
3211//------------------------------------------------------------------------------
3212
3218 public int indexOf(Vertex v)
3219 {
3220 return gVertices.indexOf(v);
3221 }
3222
3223//------------------------------------------------------------------------------
3224
3231 public Vertex getVertexWithId(long vid)
3232 {
3233 Vertex v = null;
3234 int idx = indexOfVertexWithID(vid);
3235 if (idx != -1)
3236 v = gVertices.get(idx);
3237 return v;
3238 }
3239
3240//------------------------------------------------------------------------------
3241
3247 public int indexOfVertexWithID(long vid)
3248 {
3249 int idx = -1;
3250 for (int i=0; i<gVertices.size(); i++)
3251 {
3252 Vertex v = gVertices.get(i);
3253 if (v.getVertexId() == vid)
3254 {
3255 idx = i;
3256 break;
3257 }
3258 }
3259 return idx;
3260 }
3261
3262//------------------------------------------------------------------------------
3263
3269 public void removeEdge(Edge edge)
3270 {
3271 if (gEdges.contains(edge))
3272 {
3273 AttachmentPoint srcAP = edge.getSrcAP();
3274 AttachmentPoint trgAP = edge.getTrgAP();
3275 srcAP.setUser(null);
3276 trgAP.setUser(null);
3277
3278 gEdges.remove(edge);
3279 }
3280 jGraph = null;
3281 jGraphKernel = null;
3282 }
3283
3284//------------------------------------------------------------------------------
3285
3286 public void removeRing(Ring ring)
3287 {
3288 if (gRings.contains(ring))
3289 {
3290 gRings.remove(ring);
3291 }
3292 jGraph = null;
3293 jGraphKernel = null;
3294 }
3295
3296//------------------------------------------------------------------------------
3297
3298 public Edge getEdgeAtPosition(int pos)
3299 {
3300 if ((pos >= gEdges.size()) || pos < 0)
3301 return null;
3302 return gEdges.get(pos);
3303 }
3304
3305//------------------------------------------------------------------------------
3306
3307 public int getEdgeCount()
3308 {
3309 return gEdges.size();
3310 }
3311
3312//------------------------------------------------------------------------------
3313
3314 public int getRingCount()
3315 {
3316 return gRings.size();
3317 }
3318
3319//------------------------------------------------------------------------------
3320
3321 public int getVertexCount()
3322 {
3323 return gVertices.size();
3324 }
3325
3326//------------------------------------------------------------------------------
3327
3328 @Override
3329 public String toString()
3330 {
3331 StringBuilder sb = new StringBuilder(512);
3332
3333 sb.append(graphId).append(" ");
3334
3335 for (int i=0; i<gVertices.size(); i++)
3336 {
3337 sb.append(gVertices.get(i).toString()).append(",");
3338 }
3339
3340 sb.append(" ");
3341
3342 for (int i=0; i<gEdges.size(); i++)
3343 {
3344 sb.append(gEdges.get(i).toString()).append(",");
3345 }
3346
3347 sb.append(" ");
3348
3349 for (int i=0; i<gRings.size(); i++)
3350 {
3351 sb.append(gRings.get(i).toString()).append(" ");
3352 }
3353
3354 for (int i=0; i<symVertices.size(); i++)
3355 {
3356 sb.append(symVertices.get(i).toString()).append(" ");
3357 }
3358
3359 return sb.toString();
3360 }
3361
3362//------------------------------------------------------------------------------
3363
3373 @Deprecated
3374 public int getBondingAPIndex(Vertex srcVert, int dapidx,
3375 Vertex dstVert)
3376 {
3377 int n = getEdgeCount();
3378 for (int i = 0; i < n; i++)
3379 {
3380 Edge edge = getEdgeList().get(i);
3381
3382 // get the vertex ids
3383 long v1_id = edge.getSrcVertex();
3384 long v2_id = edge.getTrgVertex();
3385
3386 int dap_idx_v1 = edge.getSrcAPID();
3387
3388 if (srcVert.getVertexId() == v1_id && v2_id == dstVert.getVertexId()
3389 && dap_idx_v1 == dapidx)
3390 {
3391 return edge.getTrgAPID();
3392 }
3393 }
3394
3395 return -1;
3396 }
3397
3398//------------------------------------------------------------------------------
3399
3406 public ArrayList<Vertex> getChildVertices(Vertex vertex)
3407 {
3408 return vertex.getChilddren();
3409 }
3410
3411//------------------------------------------------------------------------------
3412
3421 public void getChildrenTree(Vertex vertex, List<Vertex> children)
3422 {
3423 List<Vertex> lst = getChildVertices(vertex);
3424 if (lst.isEmpty())
3425 {
3426 return;
3427 }
3428 for (Vertex child : lst)
3429 {
3430 if (!children.contains(child))
3431 {
3432 children.add(child);
3433 getChildrenTree(child, children);
3434 }
3435 }
3436 }
3437
3438//------------------------------------------------------------------------------
3439
3454 public void getChildrenTree(Vertex vertex, List<Vertex> children,
3455 boolean markBranches)
3456 {
3457 if (!markBranches)
3458 {
3459 getChildrenTree(vertex, children);
3460 return;
3461 }
3462
3463 AtomicInteger branchIdGenerator = new AtomicInteger(0);
3464 List<Integer> thisBranchId = new ArrayList<Integer>();
3465 thisBranchId.add(branchIdGenerator.getAndIncrement());
3466
3467 vertex.setProperty(DENOPTIMConstants.GRAPHBRANCHID, thisBranchId);
3468
3469 List<Vertex> lst = getChildVertices(vertex);
3470 if (lst.isEmpty())
3471 {
3472 return;
3473 }
3474 for (Vertex child : lst)
3475 {
3476 if (!children.contains(child))
3477 {
3478 children.add(child);
3479 if (lst.size()==1)
3480 {
3481 child.setProperty(DENOPTIMConstants.GRAPHBRANCHID,
3482 thisBranchId);
3483 getChildrenTree(child, children, branchIdGenerator,
3484 thisBranchId);
3485 } else {
3486 List<Integer> newBranchId = new ArrayList<>(thisBranchId);
3487 newBranchId.add(branchIdGenerator.getAndIncrement());
3488 child.setProperty(DENOPTIMConstants.GRAPHBRANCHID,
3489 newBranchId);
3490 getChildrenTree(child, children, branchIdGenerator,
3491 newBranchId);
3492 }
3493 }
3494 }
3495 }
3496
3497//------------------------------------------------------------------------------
3498
3511 public void getChildrenTree(Vertex vertex, List<Vertex> children,
3512 AtomicInteger branchIdGenerator, List<Integer> prevBranchId)
3513 {
3514 List<Vertex> lst = getChildVertices(vertex);
3515 if (lst.isEmpty())
3516 {
3517 return;
3518 }
3519 for (Vertex child : lst)
3520 {
3521 if (!children.contains(child))
3522 {
3523 children.add(child);
3524 if (lst.size()==1)
3525 {
3526 child.setProperty(DENOPTIMConstants.GRAPHBRANCHID,
3527 prevBranchId);
3528 getChildrenTree(child, children, branchIdGenerator,
3529 prevBranchId);
3530 } else {
3531 List<Integer> newBranchId = new ArrayList<>(prevBranchId);
3532 newBranchId.add(branchIdGenerator.getAndIncrement());
3533 child.setProperty(DENOPTIMConstants.GRAPHBRANCHID,
3534 newBranchId);
3535 getChildrenTree(child, children, branchIdGenerator,
3536 newBranchId);
3537 }
3538 }
3539 }
3540 }
3541
3542//------------------------------------------------------------------------------
3543
3556 public void getChildrenTree(Vertex vertex,
3557 List<Vertex> children, int numLayers, boolean stopBeforeRCVs)
3558 {
3559 if (numLayers==0)
3560 {
3561 return;
3562 }
3563 List<Vertex> lst = getChildVertices(vertex);
3564 if (lst.isEmpty())
3565 {
3566 return;
3567 }
3568 for (Vertex child : lst)
3569 {
3570 if (children.contains(child))
3571 continue;
3572
3573 if (stopBeforeRCVs && child.isRCV())
3574 continue;
3575
3576 children.add(child);
3577 getChildrenTree(child, children, numLayers-1, stopBeforeRCVs);
3578 }
3579 }
3580
3581//------------------------------------------------------------------------------
3582
3591 public List<Integer> getBranchIdOfVertexAtPosition(int i)
3592 {
3594 }
3595
3596//------------------------------------------------------------------------------
3597
3607 @SuppressWarnings("unchecked")
3608 public List<Integer> getBranchIdOfVertex(Vertex v)
3609 {
3610 if (!gVertices.contains(v))
3611 return null;
3612
3613 return (List<Integer>) v.getProperty(DENOPTIMConstants.GRAPHBRANCHID);
3614 }
3615
3616//------------------------------------------------------------------------------
3617
3629 {
3630 List<Integer> lst = getBranchIdOfVertex(v);
3631 String s = "";
3632 for (Integer i : lst)
3633 s = s + i + "_";
3634 return s;
3635 }
3636
3637//------------------------------------------------------------------------------
3638
3650 public boolean directedPathExists(Vertex src, Vertex trg)
3651 {
3652 List<Integer> bIdSrc = getBranchIdOfVertex(src);
3653 List<Integer> bIdTrg = getBranchIdOfVertex(trg);
3654 if (bIdSrc==null || bIdTrg==null)
3655 return false;
3656 if (bIdSrc.size()>bIdTrg.size())
3657 return false;
3658 int sharedSubBranches = 0;
3659 for (int i=0; i<bIdSrc.size(); i++)
3660 {
3661 if (bIdSrc.get(i)==bIdTrg.get(i))
3662 sharedSubBranches++;
3663 }
3664 return sharedSubBranches==bIdSrc.size();
3665 }
3666
3667//------------------------------------------------------------------------------
3668
3678 public void getChildTreeLimited(Vertex vertex,
3679 List<Vertex> children, boolean stopBeforeRCVs)
3680 {
3681 List<Vertex> lst = getChildVertices(vertex);
3682 if (lst.isEmpty())
3683 {
3684 return;
3685 }
3686 for (Vertex child : lst)
3687 {
3688 if (children.contains(child))
3689 continue;
3690
3691 if (stopBeforeRCVs && child.isRCV())
3692 continue;
3693
3694 children.add(child);
3695 getChildTreeLimited(child, children, stopBeforeRCVs);
3696 }
3697 }
3698
3699//------------------------------------------------------------------------------
3700
3710 public void getChildTreeLimited(Vertex vertex,
3711 List<Vertex> children, Set<Vertex> limits)
3712 {
3713 List<Vertex> lst = getChildVertices(vertex);
3714 if (lst.isEmpty())
3715 {
3716 return;
3717 }
3718 for (Vertex child : lst)
3719 {
3720 if (!children.contains(child))
3721 {
3722 children.add(child);
3723 if (!limits.contains(child))
3724 getChildTreeLimited(child, children, limits);
3725 }
3726 }
3727 }
3728
3729//------------------------------------------------------------------------------
3730
3742 public void getChildTreeLimited(Vertex vertex,
3743 List<Vertex> children, List<Vertex> limitsInClone,
3744 boolean stopBeforeRCVs)
3745 {
3746 List<Vertex> lst = getChildVertices(vertex);
3747 if (lst.isEmpty())
3748 {
3749 return;
3750 }
3751 for (Vertex child : lst)
3752 {
3753 if (children.contains(child))
3754 continue;
3755
3756 if (stopBeforeRCVs && child.isRCV())
3757 continue;
3758
3759 children.add(child);
3760 if (!limitsInClone.contains(child))
3761 getChildTreeLimited(child, children, limitsInClone, stopBeforeRCVs);
3762 }
3763 }
3764
3765//------------------------------------------------------------------------------
3766
3773 public Vertex getDeepestAmongThese(List<Vertex> list)
3774 {
3775 Vertex deepest = null;
3776 int shortest = Integer.MAX_VALUE;
3777 for (Vertex vertex : list)
3778 {
3779 List<Vertex> parentTree = new ArrayList<Vertex>();
3780 getParentTree(vertex, parentTree);
3781 if (parentTree.size()<shortest)
3782 {
3783 shortest = parentTree.size();
3784 deepest = vertex;
3785 }
3786 }
3787 return deepest;
3788 }
3789
3790//------------------------------------------------------------------------------
3791
3799 public void getParentTree(Vertex vertex,
3800 List<Vertex> parentTree)
3801 {
3802 Vertex parent = getParent(vertex);
3803 if (parent == null)
3804 {
3805 return;
3806 }
3807 if (parentTree.contains(parent))
3808 {
3809 // Cyclic graphs are not allowed!
3810 throw new IllegalArgumentException();
3811 }
3812 parentTree.add(parent);
3813 getParentTree(parent, parentTree);
3814 }
3815
3816//------------------------------------------------------------------------------
3817
3819 {
3820 Edge edge = v.getEdgeToParent();
3821 if (edge != null)
3822 {
3823 return edge.getSrcAP().getOwner();
3824 }
3825 return null;
3826 }
3827
3828//------------------------------------------------------------------------------
3829
3835 @Override
3836 public DGraph clone()
3837 {
3838 // When cloning, the VertexID remains the same so we'll have two
3839 // deep-copies of the same vertex having the same VertexID
3840 ArrayList<Vertex> cListVrtx = new ArrayList<>();
3841 Map<Long, Vertex> vidsInClone = new HashMap<Long, Vertex>();
3842 for (Vertex vOrig : gVertices)
3843 {
3844 Vertex vClone = vOrig.clone();
3845 cListVrtx.add(vClone);
3846 vidsInClone.put(vClone.getVertexId(), vClone);
3847 }
3848
3849 ArrayList<Edge> cListEdges = new ArrayList<>();
3850 for (Edge e : gEdges)
3851 {
3852 long srcVrtxId = e.getSrcVertex();
3853 int srcApId = this.getVertexWithId(srcVrtxId).getIndexOfAP(
3854 e.getSrcAP());
3855
3856 long trgVrtxId = e.getTrgVertex();
3857 int trgApId = this.getVertexWithId(trgVrtxId).getIndexOfAP(
3858 e.getTrgAP());
3859
3860 AttachmentPoint srcAPClone = vidsInClone.get(
3861 srcVrtxId).getAP(srcApId);
3862 AttachmentPoint trgAPClone = vidsInClone.get(
3863 trgVrtxId).getAP(trgApId);
3864
3865 cListEdges.add(new Edge(srcAPClone, trgAPClone,
3866 e.getBondType()));
3867 }
3868
3869 DGraph clone = new DGraph(cListVrtx, cListEdges);
3870
3871 // Copy the list but using the references to the cloned vertices
3872 ArrayList<Ring> cListRings = new ArrayList<>();
3873 for (Ring ring : gRings)
3874 {
3875 Ring cRing = new Ring();
3876 for (int iv=0; iv<ring.getSize(); iv++)
3877 {
3878 Vertex origVrtx = ring.getVertexAtPosition(iv);
3879 cRing.addVertex(
3880 clone.getVertexWithId(origVrtx.getVertexId()));
3881 }
3882 cRing.setBondType(ring.getBondType());
3883 cListRings.add(cRing);
3884 }
3885 clone.setRings(cListRings);
3886
3887 // The chainLinks are made of primitives, so it's just fine
3888 ArrayList<ClosableChain> cListClosableChains =
3889 new ArrayList<>();
3890 for (ClosableChain cc : closableChains)
3891 {
3892 cListClosableChains.add(cc.clone());
3893 }
3894 clone.setCandidateClosableChains(cListClosableChains);
3895
3896
3897 List<SymmetricVertexes> cSymVertices = new ArrayList<>();
3899 {
3900 SymmetricVertexes clonedSS = new SymmetricVertexes();
3901 for (Vertex origVrt : ss)
3902 {
3903 clonedSS.add(clone.gVertices.get(gVertices.indexOf(origVrt)));
3904 }
3905 cSymVertices.add(clonedSS);
3906 }
3907 clone.setSymmetricVertexSets(cSymVertices);
3908
3911
3912 return clone;
3913 }
3914
3915//------------------------------------------------------------------------------
3916
3924 {
3925 Vertex v = getVertexWithId(l);
3926 if (v == null)
3927 {
3928 return null;
3929 }
3930 return v.getEdgeToParent();
3931 }
3932
3933//------------------------------------------------------------------------------
3934
3941 public ArrayList<Integer> getIndexOfEdgesWithChild(int vid)
3942 {
3943 ArrayList<Integer> lstEdges = new ArrayList<>();
3944 for (int j=0; j<getEdgeCount(); j++)
3945 {
3946 Edge edge = getEdgeAtPosition(j);
3947
3948 if (edge.getSrcVertex() == vid)
3949 {
3950 lstEdges.add(j);
3951 }
3952 }
3953 return lstEdges;
3954 }
3955
3956//------------------------------------------------------------------------------
3957
3964 public ArrayList<Edge> getEdgesWithChild(int vid)
3965 {
3966 ArrayList<Edge> lstEdges = new ArrayList<>();
3967 for (int j=0; j<getEdgeCount(); j++)
3968 {
3969 Edge edge = getEdgeAtPosition(j);
3970
3971 if (edge.getSrcVertex() == vid)
3972 {
3973 lstEdges.add(edge);
3974 }
3975 }
3976 return lstEdges;
3977 }
3978
3979//------------------------------------------------------------------------------
3980
3984 public long getMaxVertexId()
3985 {
3986 long mval = Long.MIN_VALUE;
3987 for (Vertex v : gVertices) {
3988 mval = Math.max(mval, v.getVertexId());
3989 }
3990 return mval;
3991 }
3992
3993//------------------------------------------------------------------------------
3994
3999 public boolean containsVertexID(long l)
4000 {
4001 boolean result = false;
4002 for (Vertex v : gVertices)
4003 {
4004 if (l == v.getVertexId())
4005 {
4006 result = true;
4007 break;
4008 }
4009 }
4010 return result;
4011 }
4012
4013//------------------------------------------------------------------------------
4014
4018 public void cleanup()
4019 {
4020 if (gVertices != null)
4021 {
4022 gVertices.clear();
4023 }
4024 if (gEdges != null)
4025 {
4026 gEdges.clear();
4027 }
4028 if (gRings != null)
4029 {
4030 gRings.clear();
4031 }
4032 if (symVertices != null)
4033 {
4034 symVertices.clear();
4035 }
4036 if (closableChains != null)
4037 {
4038 closableChains.clear();
4039 }
4040 jGraph = null;
4041 jGraphKernel = null;
4042 }
4043
4044//------------------------------------------------------------------------------
4045
4046 /*
4047 * NB: this javadoc string is reproduced in the user manual HTML file.
4048 * In case of modifications, please keep the two sources compatible by
4049 * reproducing the modification on both sites.
4050 */
4051
4103 public boolean isIsomorphicTo(DGraph other) {
4104 if (this.jGraph == null)
4105 {
4106 this.jGraph = GraphConversionTool.getJGraphFromGraph(this);
4107 }
4108 if (other.jGraph == null)
4109 {
4110 other.jGraph = GraphConversionTool.getJGraphFromGraph(other);
4111 }
4112
4113 // Simple but slow because it ignores symmetry
4114 /*
4115 Comparator<DENOPTIMVertex> vComp = (v1, v2) -> {
4116 // Vertex.sameAs returns boolean, so we need to produce
4117 // an int to allow comparison.
4118 StringBuilder sb = new StringBuilder();
4119 boolean areSame = v1.sameAs(v2, sb);
4120
4121 if (areSame) {
4122 return 0;
4123 } else {
4124 return Integer.compare(v1.getBuildingBlockId(),
4125 v2.getBuildingBlockId());
4126 }
4127 };
4128 */
4129
4130 Comparator<Vertex> vComp = new Comparator<Vertex>() {
4131
4132 Map<Vertex,Set<Vertex>> symmetryShortCuts =
4133 new HashMap<Vertex,Set<Vertex>>();
4134
4135 @Override
4136 public int compare(Vertex v1, Vertex v2) {
4137
4138 // exploit symmetric relations between vertices
4139 if (symmetryShortCuts.containsKey(v1)
4140 && symmetryShortCuts.get(v1).contains(v2))
4141 {
4142 return 0;
4143 }
4144
4145 // Vertex.sameAs returns boolean, so we need to produce
4146 // an int to allow comparison.
4147 StringBuilder sb = new StringBuilder();
4148 if (v1.sameAs(v2, sb))
4149 {
4150 Set<Vertex> symToV2 = new HashSet<Vertex>();
4151 symToV2.addAll(v2.getGraphOwner().getSymSetForVertex(v2));
4152 Set<Vertex> symToV1 = new HashSet<Vertex>();
4153 symToV1.addAll(v1.getGraphOwner().getSymSetForVertex(v1));
4154 for (Vertex v1s : symToV1)
4155 {
4156 if (symmetryShortCuts.containsKey(v1s))
4157 {
4158 symmetryShortCuts.get(v1s).addAll(symToV2);
4159 } else {
4160 symmetryShortCuts.put(v1s,symToV2);
4161 }
4162 }
4163 return 0;
4164 } else {
4165 // We must return something different than zero
4166 if (Integer.compare(v1.getBuildingBlockId(),
4167 v2.getBuildingBlockId())!=0)
4168 return Integer.compare(v1.getBuildingBlockId(),
4169 v2.getBuildingBlockId());
4170 if (Integer.compare(v1.hashCode(),
4171 v2.hashCode())!=0)
4172 return Integer.compare(v1.hashCode(),
4173 v2.hashCode());
4174 return Integer.compare(v1.getBuildingBlockId()+v1.hashCode(),
4175 v2.getBuildingBlockId()+v2.hashCode());
4176 }
4177 }
4178 };
4179
4180 Comparator<UndirectedEdge> eComp =
4182
4183 // NB: these two were created to evaluate the simplest and fasted
4184 // possible scenario. It turns out that for a graph like the following
4185 // one the time spent to do automorphism (i.e., isomorphism with itself)
4186 // can only be improved by 20% when using these two simplest and
4187 // useless (i.e., inaccurate) comparators. Instead the above, and useful
4188 // comparators do introduce some computational demands, but are less
4189 // detrimental than having to address a wide multitude of possible
4190 // mappings: this seems to be the liming factor, rather than the
4191 // implementation of the comparators.
4192
4193 // Example of challenging, yet simple graph:
4194 //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]]
4195
4196 /*
4197 Comparator<UndirectedEdgeRelation> eCompDummy = (e1, e2) -> {
4198 return Integer.compare(e1.hashCode(),e2.hashCode());
4199 };
4200 Comparator<DENOPTIMVertex> vCompDummy = (v1, v2) -> {
4201 return Integer.compare(v1.getBuildingBlockId(),
4202 v2.getBuildingBlockId());
4203 };
4204 */
4205
4206 VF2GraphIsomorphismInspector<Vertex, UndirectedEdge> vf2 =
4207 new VF2GraphIsomorphismInspector<>(this.jGraph, other.jGraph,
4208 vComp, eComp);
4209
4210 return vf2.isomorphismExists();
4211 }
4212
4213//------------------------------------------------------------------------------
4214
4230 public boolean isIsostructuralTo(DGraph other) {
4231 if (this.jGraphKernel == null)
4232 {
4233 this.jGraphKernel = GraphConversionTool.getJGraphKernelFromGraph(this);
4234 }
4235 if (other.jGraphKernel == null)
4236 {
4237 other.jGraphKernel = GraphConversionTool.getJGraphKernelFromGraph(other);
4238 }
4239
4240 Comparator<Node> vComp = new Comparator<Node>() {
4241
4242 Map<Node,Set<Node>> symmetryShortCuts =
4243 new HashMap<Node,Set<Node>>();
4244
4245 @Override
4246 public int compare(Node v1, Node v2) {
4247
4248 // exploit symmetric relations between vertices
4249 if (symmetryShortCuts.containsKey(v1)
4250 && symmetryShortCuts.get(v1).contains(v2))
4251 {
4252 return 0;
4253 }
4254
4255 int result = v1.compare(v2);
4256 if (result==0)
4257 {
4258 Vertex dv1 = v1.getDNPVertex();
4259 Vertex dv2 = v2.getDNPVertex();
4260 if (dv1==null && dv2==null)
4261 {
4262 return result;
4263 }
4264
4265 Set<Node> symToV2 = new HashSet<Node>();
4266 for (Vertex sv : dv2.getGraphOwner().getSymSetForVertex(dv2))
4267 {
4268 symToV2.add((Node) sv.getProperty(
4270 }
4271
4272 Set<Node> symToV1 = new HashSet<Node>();
4273 for (Vertex sv : dv1.getGraphOwner().getSymSetForVertex(dv1))
4274 {
4275 symToV1.add((Node) sv.getProperty(
4277 }
4278
4279 for (Node v1s : symToV1)
4280 {
4281 if (symmetryShortCuts.containsKey(v1s))
4282 {
4283 symmetryShortCuts.get(v1s).addAll(symToV2);
4284 } else {
4285 symmetryShortCuts.put(v1s,symToV2);
4286 }
4287 }
4288 return 0;
4289 }
4290 return result;
4291 }
4292 };
4293
4294 Comparator<NodeConnection> eComp = NodeConnection::compare;
4295
4296 VF2GraphIsomorphismInspector<Node, NodeConnection> vf2 =
4297 new VF2GraphIsomorphismInspector<>(this.jGraphKernel,
4298 other.jGraphKernel, vComp, eComp);
4299
4300 return vf2.isomorphismExists();
4301 }
4302
4303//------------------------------------------------------------------------------
4304
4315 public boolean sameAs(DGraph other, StringBuilder reason)
4316 {
4317 if (this.getEdgeCount() != other.getEdgeCount())
4318 {
4319 reason.append("Different number of edges ("+this.getEdgeCount()+":"
4320 +other.getEdgeCount()+")");
4321 return false;
4322 }
4323
4324 if (this.getVertexCount() != other.getVertexCount())
4325 {
4326 reason.append("Different number of vertices ("+this.getVertexCount()+":"
4327 +other.getVertexCount()+")");
4328 return false;
4329 }
4330
4331 if (this.getSymmetricSetCount() != other.getSymmetricSetCount())
4332 {
4333 reason.append("Different number of symmetric sets ("
4334 + this.getSymmetricSetCount() + ":"
4335 + other.getSymmetricSetCount() + ")");
4336 return false;
4337 }
4338
4339 if (this.getRingCount() != other.getRingCount())
4340 {
4341 reason.append("Different number of Rings ("+this.getRingCount()+":"
4342 +other.getRingCount()+")");
4343 return false;
4344 }
4345
4346 //Pairwise correspondence of vertices
4347 Map<Vertex,Vertex> vertexMap =
4348 new HashMap<Vertex,Vertex>();
4349
4350 vertexMap.put(this.getVertexAtPosition(0),other.getVertexAtPosition(0));
4351
4352 //WARNING: assuming that the first vertex in the vertex list is the root
4353 // and also that there are no disconnections. Both assumptions are
4354 // reasonable for graphs.
4355 try {
4356 if (!compareGraphNodes(this.getVertexAtPosition(0), this,
4357 other.getVertexAtPosition(0), other,
4358 vertexMap,reason))
4359 {
4360 return false;
4361 }
4362 } catch (DENOPTIMException e) {
4363 e.printStackTrace();
4364 reason.append("Exception");
4365 return false;
4366 }
4367
4368 //Check Symmetric sets
4369 Iterator<SymmetricVertexes> ssIter = this.getSymSetsIterator();
4370 while (ssIter.hasNext())
4371 {
4372 SymmetricVertexes ssT = ssIter.next();
4373
4375 vertexMap.get(ssT.get(0)));
4376 if (ssO.size() == 0)
4377 {
4378 // ssO is empty because no SymmetricSet was found that
4379 // contains the given vertex. This means the two graphs
4380 // are different
4381 reason.append("Symmetric set not found for vertex ("
4382 + ssT.get(0) + ")");
4383 return false;
4384 }
4385
4386 if (ssT.size() != ssO.size())
4387 {
4388 reason.append("Different number of symmetric sets on vertex "
4389 + ssT.get(0) + "("+ssT.size()+":"+ssO.size()+")");
4390 return false;
4391 }
4392
4393 Set<Vertex> mappedVrtxFromThis = new HashSet<>();
4394 ssT.stream().forEach(v -> mappedVrtxFromThis.add(vertexMap.get(v)));
4395
4396 Set<Vertex> vrtxFromOther = new HashSet<>();
4397 ssO.stream().forEach(v -> vrtxFromOther.add(v));
4398 if (!vrtxFromOther.equals(mappedVrtxFromThis))
4399 {
4400 reason.append("Difference in symmetric set " + ssT + " vs " + ssO);
4401 return false;
4402 }
4403 }
4404
4405 //Check Rings
4406 for (Ring rT : this.getRings())
4407 {
4408 Vertex vhT = rT.getHeadVertex();
4409 Vertex vtT = rT.getTailVertex();
4410 boolean hasRing = other
4411 .getRingsInvolvingVertex(vertexMap.get(vhT))
4412 .stream()
4413 .anyMatch(rO -> sameAsRings(reason, vertexMap, rT, vhT,
4414 vtT, rO));
4415 if (!hasRing) {
4416 return false;
4417 }
4418 }
4419
4420 return true;
4421 }
4422
4423//------------------------------------------------------------------------------
4424
4425 private boolean sameAsRings(StringBuilder reason, Map<Vertex,
4426 Vertex> vertexMap, Ring rT, Vertex vhT,
4427 Vertex vtT, Ring rO) {
4428 if (rT.getSize() != rO.getSize()) {
4429 reason.append("Different ring size (").append(rT.getSize())
4430 .append(":").append(rO.getSize()).append(")");
4431 return false;
4432 }
4433
4434 if (rO.getHeadVertex() == vertexMap.get(vhT)
4435 && rO.getTailVertex() == vertexMap.get(vtT)) {
4436 for (int i = 1; i < rT.getSize(); i++) {
4437 if (vertexMap.get(rT.getVertexAtPosition(i))
4438 != rO.getVertexAtPosition(i)) {
4439 reason.append("Rings differ (A) (").append(rT).append(":")
4440 .append(rO).append(")");
4441 return false;
4442 }
4443 }
4444 } else if (rO.getHeadVertex() == vertexMap.get(vtT)
4445 && rO.getTailVertex() == vertexMap.get(vhT)) {
4446 for (int i = 1; i < rT.getSize(); i++) {
4447 int j = rO.getSize() - i - 1;
4448 if (vertexMap.get(rT.getVertexAtPosition(i))
4449 != rO.getVertexAtPosition(j)) {
4450 reason.append("Rings differ (B) (").append(rT).append(":")
4451 .append(rO).append(")");
4452 return false;
4453 }
4454 }
4455 } else {
4456 reason.append("Rings differ (C) (").append(rT).append(":")
4457 .append(rO).append(")");
4458 return false;
4459 }
4460 return true;
4461 }
4462
4463//------------------------------------------------------------------------------
4464
4475 public static boolean compareGraphNodes(Vertex thisV,
4476 DGraph thisG,
4477 Vertex otherV,
4478 DGraph otherG) throws DENOPTIMException
4479 {
4480 Map<Vertex, Vertex> map = new HashMap<>();
4481 map.put(thisV, otherV);
4482 return compareGraphNodes(thisV, thisG, otherV, otherG, map,
4483 new StringBuilder());
4484 }
4485
4486//------------------------------------------------------------------------------
4487
4499 private static boolean compareGraphNodes(Vertex seedOnA,
4500 DGraph gA, Vertex seedOnB, DGraph gB,
4501 Map<Vertex,Vertex> vertexMap, StringBuilder reason)
4502 throws DENOPTIMException
4503 {
4504 if (!seedOnA.sameAs(seedOnB, reason))
4505 {
4506 reason.append("Different vertex ("+seedOnA+":"+seedOnB+")");
4507 return false;
4508 }
4509
4510 List<Edge> edgesFromThis = gA.getEdgesWithSrc(seedOnA);
4511 List<Edge> edgesFromOther = gB.getEdgesWithSrc(seedOnB);
4512 if (edgesFromThis.size() != edgesFromOther.size())
4513 {
4514 reason.append("Different number of edges from vertex "+seedOnA+" ("
4515 +edgesFromThis.size()+":"
4516 +edgesFromOther.size()+")");
4517 return false;
4518 }
4519
4520 // pairwise correspondence between child vertices
4521 ArrayList<Vertex[]> pairs = new ArrayList<Vertex[]>();
4522
4523 for (Edge et : edgesFromThis)
4524 {
4525 boolean found = false;
4526 Edge eo = null;
4527 StringBuilder innerSb = new StringBuilder();
4528 int otherEdgeI = 0;
4529 for (Edge e : edgesFromOther)
4530 {
4531 innerSb.append(" Edge"+otherEdgeI+":");
4532 if (et.sameAs(e,innerSb))
4533 {
4534 found = true;
4535 eo = e;
4536 break;
4537 }
4538 }
4539 if (!found)
4540 {
4541 reason.append("Edge not found in other("+et+"). "
4542 + "Edges in othes: "+innerSb.toString());
4543 return false;
4544 }
4545
4546 //Check: this should never be true
4547 if (vertexMap.keySet().contains(
4548 gA.getVertexWithId(et.getTrgVertex())))
4549 {
4550 throw new DENOPTIMException("More than one attempt to set vertex map.");
4551 }
4552 vertexMap.put(gA.getVertexWithId(et.getTrgVertex()),
4553 gB.getVertexWithId(eo.getTrgVertex()));
4554
4555 Vertex[] pair = new Vertex[]{
4556 gA.getVertexWithId(et.getTrgVertex()),
4557 gB.getVertexWithId(eo.getTrgVertex())};
4558 pairs.add(pair);
4559 }
4560
4561 //Recursion on child vertices
4562 for (Vertex[] pair : pairs)
4563 {
4564 Vertex v = pair[0];
4565 Vertex o = pair[1];
4566 boolean localRes = compareGraphNodes(v, gA, o, gB,vertexMap,
4567 reason);
4568 if (!localRes)
4569 {
4570 return false;
4571 }
4572 }
4573
4574 return true;
4575 }
4576
4577//------------------------------------------------------------------------------
4578
4585 public boolean containsAtoms()
4586 {
4587 for (Vertex v : getVertexList())
4588 {
4589 if (v.containsAtoms())
4590 {
4591 return true;
4592 }
4593 }
4594 return false;
4595 }
4596
4597//------------------------------------------------------------------------------
4598
4604 {
4605 int n = 0;
4606 for (Vertex v : getVertexList())
4607 {
4608 n += v.getHeavyAtomsCount();
4609 }
4610 return n;
4611 }
4612
4613//------------------------------------------------------------------------------
4614
4620 public ArrayList<AttachmentPoint> getAttachmentPoints()
4621 {
4622 ArrayList<AttachmentPoint> lstAPs =
4623 new ArrayList<AttachmentPoint>();
4624 for (Vertex v : gVertices)
4625 {
4626 lstAPs.addAll(v.getAttachmentPoints());
4627 }
4628 return lstAPs;
4629 }
4630
4631//------------------------------------------------------------------------------
4632
4638 public ArrayList<AttachmentPoint> getAvailableAPs()
4639 {
4640 ArrayList<AttachmentPoint> lstFreeAPs =
4641 new ArrayList<AttachmentPoint>();
4643 {
4644 if (ap.isAvailable())
4645 {
4646 lstFreeAPs.add(ap);
4647 }
4648 }
4649 return lstFreeAPs;
4650 }
4651
4652//------------------------------------------------------------------------------
4653
4661 public List<AttachmentPoint> getAvailableAPsThroughout()
4662 {
4663 ArrayList<AttachmentPoint> lstFreeAPs =
4664 new ArrayList<AttachmentPoint>();
4666 {
4667 if (ap.isAvailableThroughout())
4668 {
4669 lstFreeAPs.add(ap);
4670 }
4671 }
4672 return lstFreeAPs;
4673 }
4674
4675//------------------------------------------------------------------------------
4676
4686 {
4687 AttachmentPoint ap = null;
4688 for (AttachmentPoint apCand : getAttachmentPoints())
4689 {
4690 if (apCand.getID() == id)
4691 {
4692 ap = apCand;
4693 break;
4694 }
4695 }
4696 return ap;
4697 }
4698
4699//------------------------------------------------------------------------------
4700
4701 protected int getUniqueAPIndex()
4702 {
4703 return apCounter.getAndIncrement();
4704 }
4705
4706//------------------------------------------------------------------------------
4707
4714 public boolean graphNeedsCappingGroups(FragmentSpace fragSpace)
4715 {
4716 for (Vertex v : getVertexList()) {
4717 for (AttachmentPoint ap : v.getAttachmentPoints()) {
4718 if (ap.isAvailable() && fragSpace.getAPClassOfCappingVertex(
4719 ap.getAPClass()) !=null
4720 ) {
4721 return true;
4722 }
4723 }
4724 }
4725 return false;
4726 }
4727
4728//------------------------------------------------------------------------------
4729
4734 public void removeCappingGroupsOn(Vertex vertex)
4735 {
4736 ArrayList<Vertex> toDel = new ArrayList<Vertex>();
4737 for (Vertex vtx : this.getChildVertices(vertex))
4738 {
4739 if (vtx instanceof Fragment == false)
4740 {
4741 continue;
4742 }
4743 // capping groups have fragment type 2
4744 if (((Fragment) vtx).getBuildingBlockType() == BBType.CAP
4745 && !isVertexInRing(vtx))
4746 {
4747 toDel.add(vtx);
4748 }
4749 }
4750
4751 for (Vertex v : toDel)
4752 {
4753 removeVertex(v);
4754 }
4755 }
4756
4757//------------------------------------------------------------------------------
4758
4764 public void removeCappingGroups(List<Vertex> lstVerts)
4765 {
4766 List<Long> rvids = new ArrayList<>();
4767 for (int i=0; i<lstVerts.size(); i++)
4768 {
4769 Vertex vtx = lstVerts.get(i);
4770 if (vtx instanceof Fragment == false)
4771 {
4772 continue;
4773 }
4774
4775 if (((Fragment) vtx).getBuildingBlockType() == BBType.CAP
4776 && !isVertexInRing(vtx))
4777 {
4778 rvids.add(vtx.getVertexId());
4779 }
4780 }
4781
4782 // remove the vids from the vertex lst
4783 for (int i=0; i<rvids.size(); i++)
4784 {
4785 long vid = rvids.get(i);
4787 }
4788 }
4789
4790//------------------------------------------------------------------------------
4791
4792 public void removeCappingGroupsFromChilds(List<Vertex> lstVerts)
4793 {
4794 for (Vertex v : lstVerts)
4795 {
4797 }
4798 }
4799
4800//------------------------------------------------------------------------------
4801
4807 {
4808 removeCappingGroups(new ArrayList<Vertex>(gVertices));
4809 }
4810
4811//------------------------------------------------------------------------------
4812
4820 {
4821 if (!fragSpace.useAPclassBasedApproach())
4822 return;
4823 addCappingGroups(new ArrayList<Vertex>(gVertices), fragSpace);
4824 }
4825
4826//------------------------------------------------------------------------------
4827
4842 public void addCappingGroups(List<Vertex> vertexAddedToThis,
4843 FragmentSpace fragSpace) throws DENOPTIMException
4844 {
4845 if (!fragSpace.useAPclassBasedApproach())
4846 return;
4847
4848 for (Vertex curVertex : vertexAddedToThis)
4849 {
4850 // no capping of a capping group. Since capping groups are expected
4851 // to have only one AP, there should never be a capping group with
4852 // a free AP.
4853 if (curVertex.getBuildingBlockType() == Vertex.BBType.CAP)
4854 {
4855 continue;
4856 }
4857
4858 for (AttachmentPoint curDap : curVertex.getAttachmentPoints())
4859 {
4860 if (curDap.isAvailableThroughout())
4861 {
4862 APClass apcCap = fragSpace.getAPClassOfCappingVertex(
4863 curDap.getAPClass());
4864 if (apcCap != null)
4865 {
4866 int bbIdCap = fragSpace.getCappingFragment(apcCap);
4867
4868 if (bbIdCap != -1)
4869 {
4872 bbIdCap, BBType.CAP, fragSpace);
4873 DGraph molGraph = curDap.getOwner()
4874 .getGraphOwner();
4875 if (molGraph == null)
4876 throw new Error("Cannot add capping "
4877 + "groups to a vertex that does not "
4878 + "belong to a graph.");
4879 molGraph.appendVertexOnAP(curDap, capVrtx.getAP(0));
4880 }
4881 else
4882 {
4883 String msg = "Capping is required but no proper "
4884 + "capping fragment found with APCalss "
4885 + apcCap;
4886 throw new Error(msg);
4887 }
4888 }
4889 }
4890 }
4891 }
4892 }
4893
4894//------------------------------------------------------------------------------
4895
4908 public DGraph extractSubgraph(int index)
4909 throws DENOPTIMException
4910 {
4911 return extractSubgraph(this.getVertexAtPosition(index));
4912 }
4913
4914//------------------------------------------------------------------------------
4915
4928 throws DENOPTIMException
4929 {
4930 return extractSubgraph(seed, Integer.MAX_VALUE, false);
4931 }
4932
4933//------------------------------------------------------------------------------
4934
4953 public DGraph extractSubgraph(Vertex seed, int numLayers,
4954 boolean stopBeforeRCVs) throws DENOPTIMException
4955 {
4956 if (!this.gVertices.contains(seed))
4957 {
4958 throw new DENOPTIMException("Attempt to extract a subgraph giving "
4959 + "a seed vertex that is not contained in this graph.");
4960 }
4961 DGraph subGraph = this.clone();
4962 Vertex seedClone = subGraph.getVertexAtPosition(
4963 this.indexOf(seed));
4964
4965 ArrayList<Vertex> subGrpVrtxs = new ArrayList<Vertex>();
4966 subGrpVrtxs.add(seedClone);
4967 subGraph.getChildrenTree(seedClone, subGrpVrtxs, numLayers, stopBeforeRCVs);
4968 ArrayList<Vertex> toRemove = new ArrayList<Vertex>();
4969 for (Vertex v : subGraph.gVertices)
4970 {
4971 if (!subGrpVrtxs.contains(v))
4972 {
4973 toRemove.add(v);
4974 }
4975 }
4976
4977 for (Vertex v : toRemove)
4978 {
4979 subGraph.removeVertex(v);
4980 }
4981
4982 return subGraph;
4983 }
4984
4985//------------------------------------------------------------------------------
4986
5005 List<Vertex> limits, boolean stopBeforeRCVs)
5006 throws DENOPTIMException
5007 {
5008 if (!this.gVertices.contains(seed))
5009 {
5010 throw new DENOPTIMException("Attempt to extract a subgraph giving "
5011 + "a seed vertex that is not contained in this graph.");
5012 }
5013
5014 if (limits.size()==0)
5015 {
5016 return extractSubgraph(seed, stopBeforeRCVs);
5017 }
5018
5019 DGraph subGraph = this.clone();
5020 Vertex seedClone = subGraph.getVertexAtPosition(
5021 this.indexOf(seed));
5022
5023 List<Vertex> limitsInClone = new ArrayList<Vertex>();
5024 for (Vertex v : limits)
5025 limitsInClone.add(subGraph.getVertexAtPosition(this.indexOf(v)));
5026
5027 ArrayList<Vertex> subGrpVrtxs = new ArrayList<Vertex>();
5028 subGrpVrtxs.add(seedClone);
5029 subGraph.getChildTreeLimited(seedClone, subGrpVrtxs, limitsInClone,
5030 stopBeforeRCVs);
5031
5032 ArrayList<Vertex> toRemove = new ArrayList<Vertex>();
5033 for (Vertex v : subGraph.gVertices)
5034 {
5035 if (!subGrpVrtxs.contains(v))
5036 {
5037 toRemove.add(v);
5038 }
5039 }
5040 for (Vertex v : toRemove)
5041 {
5042 subGraph.removeVertex(v);
5043 }
5044
5045 return subGraph;
5046 }
5047
5048//------------------------------------------------------------------------------
5049
5057 public static void exploreGraph(Vertex seed,
5058 Set<Vertex> limits, Set<Vertex> visited)
5059 {
5060 for (AttachmentPoint ap : seed.getAttachmentPoints())
5061 {
5062 AttachmentPoint userAP = ap.getLinkedAP();
5063 if (userAP != null)
5064 {
5065 Vertex userVertex = userAP.getOwner();
5066 if (limits.contains(userVertex))
5067 {
5068 continue;
5069 }
5070 if (!visited.contains(userVertex))
5071 {
5072 visited.add(userVertex);
5073 exploreGraph(userVertex, limits, visited);
5074 }
5075 }
5076 }
5077 }
5078
5079//------------------------------------------------------------------------------
5080
5090 public static Set<Vertex> exploreGraph(Vertex seed, Set<Vertex> limits)
5091 {
5092 Set<Vertex> visitedVertexes = new HashSet<Vertex>();
5093 visitedVertexes.add(seed);
5094 exploreGraph(seed, limits, visitedVertexes);
5095 return visitedVertexes;
5096 }
5097
5098//------------------------------------------------------------------------------
5099
5114 public DGraph extractSubgraph(Vertex seed, boolean stopBeforeRCVs)
5115 throws DENOPTIMException
5116 {
5117 if (!this.gVertices.contains(seed))
5118 {
5119 throw new DENOPTIMException("Attempt to extract a subgraph giving "
5120 + "a seed vertex that is not contained in this graph.");
5121 }
5122
5123 DGraph subGraph = this.clone();
5124 Vertex seedClone = subGraph.getVertexAtPosition(
5125 this.indexOf(seed));
5126
5127 ArrayList<Vertex> subGrpVrtxs = new ArrayList<Vertex>();
5128 subGrpVrtxs.add(seedClone);
5129 subGraph.getChildTreeLimited(seedClone, subGrpVrtxs, stopBeforeRCVs);
5130
5131 ArrayList<Vertex> toRemove = new ArrayList<Vertex>();
5132 for (Vertex v : subGraph.gVertices)
5133 {
5134 if (!subGrpVrtxs.contains(v))
5135 {
5136 toRemove.add(v);
5137 }
5138 }
5139 for (Vertex v : toRemove)
5140 {
5141 subGraph.removeVertex(v);
5142 }
5143
5144 return subGraph;
5145 }
5146
5147//------------------------------------------------------------------------------
5148
5157 public List<DGraph> extractPattern(GraphPattern pattern)
5158 throws DENOPTIMException
5159 {
5160 return extractPattern(pattern, false).keySet().stream().collect(
5161 Collectors.toList());
5162 }
5163
5164//------------------------------------------------------------------------------
5165
5188 public Map<DGraph,ObjectPair> extractPattern(GraphPattern pattern,
5189 boolean recordConnectivity) throws DENOPTIMException
5190 {
5191 if (pattern != GraphPattern.RING) {
5192 throw new IllegalArgumentException("Graph pattern " + pattern +
5193 " not supported.");
5194 }
5195
5196 List<Set<Vertex>> disjointMultiCycleVertices = this
5197 .getRings()
5198 .stream()
5199 .map(Ring::getVertices)
5200 .map(HashSet::new)
5201 .collect(Collectors.toList());
5202
5203 GeneralUtils.unionOfIntersectingSets(disjointMultiCycleVertices);
5204
5205 Map<DGraph,ObjectPair> subGraphsAndConnections = new LinkedHashMap<>();
5206 for (Set<Vertex> fusedRing : disjointMultiCycleVertices) {
5207 if (recordConnectivity)
5208 {
5209 Set<Edge> connectionToSubgraph = new HashSet<Edge>();
5210 Set<Edge> connectionFromSubgraph = new HashSet<Edge>();
5211 DGraph subGraph = extractSubgraph(fusedRing, connectionToSubgraph,
5212 connectionFromSubgraph);
5213 ObjectPair connections = new ObjectPair(connectionToSubgraph,
5214 connectionFromSubgraph);
5215 subGraphsAndConnections.put(subGraph, connections);
5216 } else {
5217 DGraph subGraph = extractSubgraph(fusedRing);
5218 subGraphsAndConnections.put(subGraph, null);
5219 }
5220 }
5221
5222 for (DGraph g : subGraphsAndConnections.keySet()) {
5223 g.storeCurrentVertexIDs();
5224 g.renumberGraphVertices();
5226 }
5227
5228 return subGraphsAndConnections;
5229 }
5230
5231 //------------------------------------------------------------------------------
5232
5239 public DGraph extractSubgraph(Collection<Vertex> definedOn)
5240 {
5241 DGraph subgraph = extractSubgraph(definedOn, null, null);
5242 return subgraph;
5243 }
5244
5245//------------------------------------------------------------------------------
5246
5258 public DGraph extractSubgraph(Collection<Vertex> definedOn,
5259 Set<Edge> connectionToSubgraph,
5260 Set<Edge> connectionFromSubgraph)
5261 {
5262
5263 DGraph subgraph = this.clone();
5264
5265 Set<Vertex> complement = subgraph
5266 .getVertexList()
5267 .stream()
5268 .filter(u -> definedOn
5269 .stream()
5270 .allMatch(v -> v.getVertexId() != u.getVertexId())
5271 ).collect(Collectors.toSet());
5272
5273 Set<Long> vrtxIDsInComplement = complement.stream()
5274 .map(v -> v.getVertexId())
5275 .collect(Collectors.toSet());
5276
5277 if (connectionToSubgraph!=null && connectionFromSubgraph!=null)
5278 {
5279 for (Vertex v : definedOn)
5280 {
5281 for (Edge e : this.getEdgeList())
5282 {
5283 if (e.getSrcAP().getOwner() == v &&
5284 vrtxIDsInComplement.contains(e.getTrgVertex()))
5285 {
5286 connectionFromSubgraph.add(e);
5287 }
5288
5289 if (e.getTrgAP().getOwner() == v &&
5290 vrtxIDsInComplement.contains(e.getSrcVertex()))
5291 {
5292 connectionToSubgraph.add(e);
5293 }
5294 }
5295 }
5296 }
5297
5298 for (Vertex v : complement) {
5299 subgraph.removeVertex(v);
5300 }
5301
5302 return subgraph;
5303 }
5304
5305//------------------------------------------------------------------------------
5306
5317 FragmentSpace fragSpace) throws DENOPTIMException
5318 {
5319 return embedPatternsInTemplates(pattern, fragSpace, ContractLevel.FREE);
5320 }
5321
5322//------------------------------------------------------------------------------
5323
5338 FragmentSpace fragSpace, ContractLevel contract)
5339 throws DENOPTIMException
5340 {
5341 // We will return a modified clone of this graph
5342 DGraph graph = this.clone();
5343 // We use IDs to find the mapping of APs between cloned graphs. So, must
5344 // ensure the IDs of APs are unique within the graph.
5345 graph.ensureUniqueApIDs();
5346
5347 // Identify the subgraphs to be replaced by templates
5348 Map<DGraph,ObjectPair> subGraphsAndLinks = graph.extractPattern(
5349 pattern, true);
5350
5351 // Replace the subgraphs with the templates
5352 for (Map.Entry<DGraph,ObjectPair> entry : subGraphsAndLinks.entrySet())
5353 {
5354 // WARNING: while the subgraph is a clone of 'graph', the sets
5355 // contain referenced to the edges of 'graph'.
5356 DGraph subGraph = entry.getKey();
5357
5358 // Make template
5359 BBType tmplType = subGraph.hasScaffoldTypeVertex() ?
5360 BBType.SCAFFOLD :
5362 Template tmpl = new Template(tmplType);
5363 tmpl.setInnerGraph(subGraph);
5364 tmpl.setContractLevel(contract);
5365
5366 // Recover info on which APs of the original subgraph (i.e., APs in
5367 // 'graph') correspond to APs on the template.
5368 LinkedHashMap<AttachmentPoint, AttachmentPoint> apMapOrigToTmpl =
5369 new LinkedHashMap<AttachmentPoint, AttachmentPoint>();
5370 @SuppressWarnings("unchecked")
5371 Set<Edge> edsToSubgrph = (Set<Edge>) entry.getValue().getFirst();
5372 for (Edge e : edsToSubgrph)
5373 {
5374 AttachmentPoint apOnOrig = e.getTrgAP();
5375 AttachmentPoint apOnTmpl = tmpl.getOuterAPFromInnerAP(
5376 subGraph.getAPWithId(apOnOrig.getID()));
5377 apMapOrigToTmpl.put(apOnOrig, apOnTmpl);
5378 }
5379 @SuppressWarnings("unchecked")
5380 Set<Edge> edsFromSubGrph = (Set<Edge>) entry.getValue().getSecond();
5381 for (Edge e : edsFromSubGrph)
5382 {
5383 AttachmentPoint apOnOrig = e.getSrcAP();
5384 AttachmentPoint apOnTmpl = tmpl.getOuterAPFromInnerAP(
5385 subGraph.getAPWithId(apOnOrig.getID()));
5386 apMapOrigToTmpl.put(apOnOrig, apOnTmpl);
5387 }
5388
5389 // Identify the vertexes in the subgraph replaced by the template
5390 List<Vertex> toReplaceByTemplate = new ArrayList<>();
5391 for (Vertex embeddedVrtx : subGraph.gVertices)
5392 {
5393 long vIdInThis = (long) embeddedVrtx.getProperty(
5395 toReplaceByTemplate.add(graph.getVertexWithId(vIdInThis));
5396 }
5397
5398 // Do the actual replacement of original subgraph with the template
5399 DGraph singleVertedGraph = new DGraph();
5400 singleVertedGraph.addVertex(tmpl);
5401 graph.replaceSubGraph(toReplaceByTemplate, singleVertedGraph,
5402 apMapOrigToTmpl, fragSpace);
5403 }
5404
5405 return graph;
5406 }
5407
5408//------------------------------------------------------------------------------
5409
5417 private static void reorderVertexList(DGraph g)
5418 {
5419 Vertex newScaffold = g.getSourceVertex();
5420 if (newScaffold == null) {
5421 return;
5422 }
5423 DGraph.setScaffold(newScaffold);
5425 }
5426
5427//------------------------------------------------------------------------------
5428
5433 private static void fixEdgeDirections(DGraph graph)
5434 {
5435 Vertex src = graph.getSourceVertex();
5436 fixEdgeDirections(src, new HashSet<>());
5437 }
5438
5439//------------------------------------------------------------------------------
5440
5445 private static void fixEdgeDirections(Vertex v,
5446 Set<Long> visited)
5447 {
5448 visited.add(v.getVertexId());
5449 int visitedVertexEncounters = 0;
5450 for (int i = 0; i < v.getNumberOfAPs(); i++) {
5451 AttachmentPoint ap = v.getAP(i);
5452 Edge edge = ap.getEdgeUser();
5453 if (edge != null) {
5454 long srcVertex = edge.getSrcVertex();
5455 boolean srcIsVisited = srcVertex != v.getVertexId()
5456 && visited.contains(srcVertex);
5457
5458 visitedVertexEncounters += srcIsVisited ? 1 : 0;
5459 if (visitedVertexEncounters >= 2) {
5460 throw new IllegalArgumentException("Invalid graph. "
5461 + "Contains a cycle.");
5462 }
5463
5464 boolean edgeIsWrongWay = edge.getTrgVertex()
5465 == v.getVertexId() && !srcIsVisited;
5466 if (edgeIsWrongWay) {
5467 edge.flipEdge();
5468 }
5469 if (!srcIsVisited) {
5470 fixEdgeDirections(edge.getTrgAP().getOwner(), visited);
5471 }
5472 }
5473 }
5474 }
5475
5476//------------------------------------------------------------------------------
5477
5488 public boolean removeBranchStartingAt(Vertex v, boolean symmetry)
5489 throws DENOPTIMException
5490 {
5491 boolean res = true;
5492 if (hasSymmetryInvolvingVertex(v) && symmetry)
5493 {
5494 for (Vertex sv : getSymSetForVertex(v))
5495 {
5496 boolean res2 = removeBranchStartingAt(sv);
5497 if (!res2)
5498 {
5499 res = res2;
5500 }
5501 }
5502 }
5503 else
5504 {
5505 res = removeBranchStartingAt(v);
5506 }
5507 return res;
5508 }
5509
5510//------------------------------------------------------------------------------
5511
5522 throws DENOPTIMException
5523 {
5524 Edge edgeToParent = v.getEdgeToParent();
5525 if (edgeToParent != null)
5526 {
5527 removeEdge(edgeToParent);
5528 }
5530 }
5531
5532//------------------------------------------------------------------------------
5533
5548 throws DENOPTIMException
5549 {
5550 // now get the vertices attached to v
5551 ArrayList<Vertex> children = new ArrayList<Vertex>();
5552 getChildrenTree(v, children);
5553
5554 // delete the children vertices and associated edges
5555 for (Vertex c : children) {
5556 removeVertex(c);
5557 }
5558
5559 // finally delete the vertex and associated edges
5560 removeVertex(v);
5561
5562 return getVertexWithId(v.getVertexId()) == null;
5563 }
5564
5565//------------------------------------------------------------------------------
5566
5579 FragmentSpace fragSpace) throws DENOPTIMException
5580 {
5581 List<Ring> rings = getRingsInvolvingVertex(v);
5582 if (rings.isEmpty())
5583 {
5584 return false;
5585 }
5586
5587 // Identify the RCVs defining the chord that might become an edge
5588 // The corresponding ring is the "frame" we'll use throughout this
5589 // operation, and is the smallest ring that is closest to the appointed
5590 // vertex.
5591 Ring frame = null;
5592 Vertex[] replacedByEdge = new Vertex[2];
5593 int minDist = Integer.MAX_VALUE;
5594 BondType bt = null;
5595 for (Ring r : rings)
5596 {
5597 int dist = Math.min(r.getDistance(r.getHeadVertex(),v),
5598 r.getDistance(r.getTailVertex(),v));
5599 if (dist < minDist)
5600 {
5601 minDist = dist;
5602 frame = r;
5603 replacedByEdge[0] = r.getHeadVertex();
5604 replacedByEdge[1] = r.getTailVertex();
5605 bt = r.getBondType();
5606 }
5607 }
5608
5609 // Find out where branching vertices are along the frame ring
5610 boolean frameHasBranching = false;
5611 List<Integer> branchingPositions = new ArrayList<Integer>();
5612 int posOfFocusVrtInRing = frame.getPositionOf(v);
5613 for (int i=0; i<frame.getSize(); i++)
5614 {
5615 Vertex vi = frame.getVertexAtPosition(i);
5616 // We consider the scaffold as a branching point, i.e., it will never be removed
5618 {
5619 branchingPositions.add(i);
5620 continue;
5621 }
5622 long oNonCap = vi.getAttachmentPoints().size()
5625 if (oNonCap > 2)
5626 {
5627 branchingPositions.add(i);
5628 frameHasBranching = true;
5629 }
5630 }
5631
5632 // Make sure this ring is not all there is in this graph.
5633 if (rings.size()==1 && !frameHasBranching)
5634 {
5635 return false;
5636 }
5637
5638 // Identify the end points of chain that gets removed, i.e., the chain
5639 // containing V and is between branchingDownstreamId and
5640 // branchingUpstreamId gets removed.
5641 int branchingDownstreamId = -1;
5642 for (int i=0; i<frame.getSize(); i++)
5643 {
5644 int iTranslated = i + posOfFocusVrtInRing;
5645 if (iTranslated >= frame.getSize())
5646 iTranslated = iTranslated - frame.getSize();
5647 if (branchingPositions.contains(iTranslated))
5648 {
5649 branchingDownstreamId = iTranslated;
5650 break;
5651 }
5652 }
5653 int branchingUpstreamId = -1;
5654 for (int i=(frame.getSize()-1); i>-1; i--)
5655 {
5656 int iTranslated = i + posOfFocusVrtInRing;
5657 if (iTranslated >= frame.getSize())
5658 iTranslated = iTranslated - frame.getSize();
5659 if (branchingPositions.contains(iTranslated))
5660 {
5661 branchingUpstreamId = iTranslated;
5662 break;
5663 }
5664 }
5665
5666 // Now, collect the vertices along the ring based on whether they
5667 // will be removed or remain (possible with a change of edge direction
5668 // and replacement of an RCV pair by edge)
5669 List<Vertex> remainingChain = new ArrayList<Vertex>();
5670 for (int i=0; i<frame.getSize(); i++)
5671 {
5672 int iTranslated = i + branchingDownstreamId;
5673 if (iTranslated >= frame.getSize())
5674 iTranslated = iTranslated - frame.getSize();
5675 remainingChain.add(frame.getVertexAtPosition(iTranslated));
5676 if (iTranslated == branchingUpstreamId)
5677 {
5678 break;
5679 }
5680 }
5681 List<Vertex> toRemoveChain = new ArrayList<Vertex>();
5682 for (int i=0; i<frame.getSize(); i++)
5683 {
5684 int iTranslated = i + branchingUpstreamId + 1; //exclude branch point
5685 if (iTranslated >= frame.getSize())
5686 iTranslated = iTranslated - frame.getSize();
5687 toRemoveChain.add(frame.getVertexAtPosition(iTranslated));
5688 if (iTranslated == (branchingDownstreamId - 1)) //exclude branch point
5689 {
5690 break;
5691 }
5692 }
5693
5694 // Need to exclude the case where the chain to remove consists only of
5695 // the RCVs because it would lead to loss of the chord and creation of
5696 // cyclic graph. Also, proceeding without making the edge would simply
5697 // correspond to removing the chord.
5698 if (toRemoveChain.size() == 2)
5699 {
5700 int countOrRCVs = 0;
5701 for (Vertex vtr : toRemoveChain)
5702 {
5703 if (vtr.isRCV())
5704 countOrRCVs++;
5705 }
5706 if (countOrRCVs == 2)
5707 {
5708 return false;
5709 }
5710 }
5711
5712 // To understand if we need to reverse some edges, we identify the
5713 // deepest vertex level-wise. It may or may not be a scaffold!!!
5714 int deepestLevel = Integer.MAX_VALUE;
5715 Vertex deepestVrtRemainingChain = null;
5716 for (Vertex vint : remainingChain)
5717 {
5718 int lvl = getLevel(vint);
5719 if (lvl < deepestLevel)
5720 {
5721 deepestLevel = lvl;
5722 deepestVrtRemainingChain = vint;
5723 }
5724 }
5725
5726 // Check if we need to transform a pair of RCVs into an edge, and
5727 // identify APs used by the edge that replaces the to-be-removed RCVs.
5728 // I do not see how the chain can possibly contain only one of the
5729 // RCVs, so I assume that if one RCV is there, then the other is too.
5730 if (remainingChain.contains(replacedByEdge[0]))
5731 {
5732 AttachmentPoint apSrcOfNewEdge = replacedByEdge[0]
5734 AttachmentPoint apTrgOfNewEdge = replacedByEdge[1]
5736
5737 // Remove the RCVs that will be replaced by an edge
5738 removeVertex(replacedByEdge[0]);
5739 remainingChain.remove(replacedByEdge[0]);
5740 removeVertex(replacedByEdge[1]);
5741 remainingChain.remove(replacedByEdge[1]);
5742
5743 // And make the new edge. The direction can be anything. Later, we
5744 // decide if we need to reverse it.
5745 //NB: the compatibility between the APs should be granted by the
5746 // previous existence of the chord. so no need to check
5747 // apSrcOfNewEdge.getAPClass().isCPMapCompatibleWith(
5748 // apTrgOfNewEdge.getAPClass()))
5749 addEdge(new Edge(apSrcOfNewEdge, apTrgOfNewEdge, bt));
5750 } else {
5751 // We remove the frame already, otherwise we will try to recreate
5752 // such ring from RCVs and waste time with it.
5753 removeRing(frame);
5754 }
5755
5756 // Now, inspect the paths from the deepest vertex and outwards, to
5757 // find out where to start reversing edges.
5758 List<Vertex> chainToReverseA = new ArrayList<Vertex>();
5759 List<Vertex> chainToReverseB = new ArrayList<Vertex>();
5760 for (int i=(remainingChain.indexOf(deepestVrtRemainingChain)+1);
5761 i<remainingChain.size(); i++)
5762 {
5763 Vertex vPrev = remainingChain.get(i-1);
5764 Vertex vHere = remainingChain.get(i);
5765 if (!vPrev.getChilddren().contains(vHere))
5766 {
5767 // in an healthy spanning tree, once we find the first reversed
5768 // edge, all the following edges will also have to be reversed.
5769 if (chainToReverseA.size()==0)
5770 chainToReverseA.add(vPrev);
5771 chainToReverseA.add(vHere);
5772 }
5773 }
5774 for (int i=(remainingChain.indexOf(deepestVrtRemainingChain)-1);i>-1;i--)
5775 {
5776 Vertex vPrev = remainingChain.get(i+1);
5777 Vertex vHere = remainingChain.get(i);
5778 if (!vPrev.getChilddren().contains(vHere))
5779 {
5780 if (chainToReverseB.size()==0)
5781 chainToReverseB.add(vPrev);
5782 chainToReverseB.add(vHere);
5783 }
5784 }
5785
5786 // These are to remember all chords that will have to be recreated
5787 LinkedHashMap<Vertex,Vertex> chordsToRecreate =
5788 new LinkedHashMap<Vertex,Vertex>();
5789 LinkedHashMap<Vertex,BondType> chordsToRecreateBB =
5790 new LinkedHashMap<Vertex,BondType>();
5791
5792 // Change direction of those edges that have to be reversed as a
5793 // consequence of the change in the spanning tree.
5794 if (chainToReverseA.size()+chainToReverseB.size() > 1)
5795 {
5796 List<Vertex> chainToWorkOn = null;
5797 for (int ic=0; ic<2; ic++)
5798 {
5799 if (ic == 1)
5800 chainToWorkOn = chainToReverseA;
5801 else
5802 chainToWorkOn = chainToReverseB;
5803
5804 for (int i=1; i<chainToWorkOn.size(); i++)
5805 {
5806 Vertex vHere = chainToWorkOn.get(i);
5807 Vertex vPrev = chainToWorkOn.get(i-1);
5808 List<Ring> ringsToRecreate = new ArrayList<>();
5809 for (Ring r : getRingsInvolvingVertex(vHere))
5810 {
5811 ringsToRecreate.add(r);
5812 chordsToRecreate.put(r.getHeadVertex(),
5813 r.getTailVertex());
5814 chordsToRecreateBB.put(r.getHeadVertex(),
5815 r.getBondType());
5816 }
5817 for (Ring r : ringsToRecreate)
5818 {
5819 removeRing(r);
5820 }
5821
5822 Edge edgeToPrevious = vHere.getEdgeWith(vPrev);
5823 if (edgeToPrevious == null)
5824 {
5825 // Since we have already made the new edge this should
5826 // never happen.
5827 String debugFile = "debug_"+v.getVertexId()+".json";
5828 DenoptimIO.writeGraphToJSON(new File(debugFile), this);
5829 throw new DENOPTIMException("Unconnected vertices "
5830 + vHere.getVertexId() + " and "
5831 + vPrev.getVertexId() + ". Unable to deal with "
5832 + "removal of " + v + " from ring " + frame
5833 + " in graph " + this.getGraphId()
5834 + ". See graph in " + debugFile);
5835 } else {
5836 if (edgeToPrevious.getSrcAP().getOwner() == vHere)
5837 {
5838 // This is an edge that has to be reversed.
5839 AttachmentPoint newSrcAP =
5840 edgeToPrevious.getTrgAP();
5841 AttachmentPoint newTrgAP =
5842 edgeToPrevious.getSrcAP();
5843 if (newSrcAP.getAPClass().isCPMapCompatibleWith(
5844 newTrgAP.getAPClass(), fragSpace))
5845 {
5846 BondType oldBt = edgeToPrevious.getBondType();
5847 removeEdge(edgeToPrevious);
5848 addEdge(new Edge(newSrcAP, newTrgAP,
5849 oldBt));
5850 } else {
5851 // There is a non-reversible connection along
5852 // the way, therefore we cannot do this
5853 // specific mutation.
5854 return false;
5855 }
5856 }
5857 }
5858 }
5859 }
5860 }
5861
5862 // Delete the chain to be removed
5863 for (Vertex vtr : toRemoveChain)
5864 {
5865 // This works across template boundaries!
5866 for (Vertex child : vtr.getChildrenThroughout())
5867 {
5868 if (remainingChain.contains(child)
5869 || toRemoveChain.contains(child))
5870 continue;
5871 DGraph ownerOfChild = child.getGraphOwner();
5872 ownerOfChild.removeVertex(child);
5873 }
5874 if (templateJacket!= null)
5875 {
5876 List<AttachmentPoint> apProjectionsToRemove =
5877 new ArrayList<AttachmentPoint>();
5878 for (AttachmentPoint outerAP :
5880 {
5881 AttachmentPoint innerAP =
5883 if (innerAP.getOwner() == vtr)
5884 {
5885 apProjectionsToRemove.add(innerAP);
5886 }
5887 }
5888 for (AttachmentPoint apToRemove : apProjectionsToRemove)
5890 }
5891 removeVertex(vtr);
5892 }
5893
5894 // Regenerate the rings that have been affected
5895 for (Vertex h : chordsToRecreate.keySet())
5896 {
5897 addRing(h, chordsToRecreate.get(h), chordsToRecreateBB.get(h));
5898 }
5899
5900 // Symmetry relation need to be compared with the change of topology.
5901 // The worst that can happen is that two vertices that are
5902 // listed as symmetric are, instead, one the (grand)parent of
5903 // the other. This is inconsistent with the expectations when
5904 // dealing with any operation with symmetric vertices.
5905 // A different level does NOT imply a parent-child relation,
5906 // but is a sign that the topology has changed substantially,
5907 // and that the symmetric relation is, most likely, not sensible
5908 // anymore.
5909 List<SymmetricVertexes> ssToRemove = new ArrayList<SymmetricVertexes>();
5910 Iterator<SymmetricVertexes> ssIter = getSymSetsIterator();
5911 while (ssIter.hasNext())
5912 {
5913 SymmetricVertexes ss = ssIter.next();
5914 int level = -2;
5915 for (Vertex vrt : ss)
5916 {
5917 if (level==-2)
5918 {
5919 level = getLevel(vrt);
5920 } else {
5921 if (level != getLevel(vrt))
5922 {
5923 ssToRemove.add(ss);
5924 break;
5925 }
5926 }
5927 }
5928 }
5929 for (SymmetricVertexes ss : ssToRemove)
5931
5932 // The free-ed up APs need to be projected to template's surface
5933 if (templateJacket!= null)
5934 {
5935 for (AttachmentPoint innerAP : getAvailableAPs())
5936 {
5938 }
5939 }
5940
5941 return true;
5942 }
5943
5944//------------------------------------------------------------------------------
5945
5951 @Deprecated
5953 {
5954 HashMap<Long, Long> nmap = new HashMap<>();
5955 for (int i=0; i<getVertexCount(); i++)
5956 {
5957 long vid = getVertexList().get(i).getVertexId();
5958 long nvid = -vid;
5959 nmap.put(vid, nvid);
5960
5961 getVertexList().get(i).setVertexId(nvid);
5962
5963 for (int j=0; j<getEdgeCount(); j++)
5964 {
5965 Edge e = getEdgeList().get(j);
5966 if (e.getSrcVertex() == vid) {
5967 e.getSrcAP().getOwner().setVertexId(nvid);
5968 }
5969 if (e.getTrgVertex() == vid) {
5970 e.getTrgAP().getOwner().setVertexId(nvid);
5971 }
5972 }
5973 }
5974 }
5975
5976//------------------------------------------------------------------------------
5977
5984 {
5986 }
5987
5988//------------------------------------------------------------------------------
5989
5996 public Map<Long,Long> renumberVerticesGetMap()
5997 {
5998 Map<Long, Long> nmap = new HashMap<>();
5999
6000 // for the vertices in the graph, get new vertex ids
6001 for (int i=0; i<getVertexCount(); i++)
6002 {
6003 Vertex v = getVertexList().get(i);
6004 long vid = v.getVertexId();
6005 long nvid = GraphUtils.getUniqueVertexIndex();
6006
6007 nmap.put(vid, nvid);
6008
6009 v.setVertexId(nvid);
6011 }
6012
6013 return nmap;
6014 }
6015
6016//------------------------------------------------------------------------------
6017
6026 public int getLevel(Vertex v)
6027 {
6028 ArrayList<Vertex> parentTree = new ArrayList<>();
6029 getParentTree(v,parentTree);
6030 return parentTree.size() - 1;
6031 }
6032
6033//------------------------------------------------------------------------------
6034
6053 public Object[] checkConsistency(RunTimeParameters settings)
6054 throws DENOPTIMException
6055 {
6056 return checkConsistency(settings, false);
6057 }
6058
6059//------------------------------------------------------------------------------
6060
6084 public Object[] checkConsistency(RunTimeParameters settings, boolean permissive)
6085 throws DENOPTIMException
6086 {
6088 if (settings.containsParameters(ParametersType.RC_PARAMS))
6089 {
6090 rcSettings = (RingClosureParameters)settings.getParameters(
6092 }
6094 if (settings.containsParameters(ParametersType.FS_PARAMS))
6095 {
6096 fsSettings = (FragmentSpaceParameters)settings.getParameters(
6098 }
6099
6100 // calculate the molecule representation
6101 ThreeDimTreeBuilder t3d = new ThreeDimTreeBuilder(settings.getLogger(),
6102 settings.getRandomizer());
6103 t3d.setAlignBBsIn3D(false);
6104 IAtomContainer mol = t3d.convertGraphTo3DAtomContainer(this,true);
6105 if (mol == null)
6106 {
6107 String msg ="Evaluation of graph: graph-to-mol returned null!"
6108 + toString();
6109 settings.getLogger().log(Level.FINE, msg);
6110 return null;
6111 }
6112
6113 // check if the molecule is connected
6114 boolean isConnected = ConnectivityChecker.isConnected(mol);
6115 if (!isConnected)
6116 {
6117 String msg = "Evaluation of graph: Not all connected"
6118 + toString();
6119 settings.getLogger().log(Level.FINE, msg);
6120 return null;
6121 }
6122
6123 // SMILES
6124 String smiles = null;
6125 smiles = MoleculeUtils.getSMILESForMolecule(mol,settings.getLogger());
6126 if (smiles == null)
6127 {
6128 String msg = "Evaluation of graph: SMILES is null! "
6129 + toString();
6130 settings.getLogger().log(Level.FINE, msg);
6131 smiles = "FAIL: NO SMILES GENERATED";
6132 }
6133 // if by chance the smiles indicates a disconnected molecule
6134 if (smiles.contains(".") && !permissive)
6135 {
6136 String msg = "Evaluation of graph: SMILES contains \".\"" + smiles;
6137 settings.getLogger().log(Level.FINE, msg);
6138 return null;
6139 }
6140
6141 // criteria from definition of Fragment space
6142 // 1A) number of heavy atoms
6143 if (fsSettings.getMaxHeavyAtom()>0 && !permissive)
6144 {
6146 fsSettings.getMaxHeavyAtom())
6147 {
6148 String msg = "Evaluation of graph: Max atoms constraint "
6149 + " violated: " + smiles;
6150 settings.getLogger().log(Level.FINE, msg);
6151 return null;
6152 }
6153 }
6154
6155 // 1B) molecular weight
6156 double mw = MoleculeUtils.getMolecularWeight(mol);
6157 if (fsSettings.getMaxMW()>0 && !permissive)
6158 {
6159 if (mw > fsSettings.getMaxMW())
6160 {
6161 String msg = "Evaluation of graph: Molecular weight "
6162 + "constraint violated: " + smiles + " | MW: " + mw;
6163 settings.getLogger().log(Level.FINE, msg);
6164 return null;
6165 }
6166 }
6167 mol.setProperty("MOL_WT", mw);
6168
6169 // 1C) number of rotatable bonds
6171 if (fsSettings.getMaxRotatableBond()>0 && !permissive)
6172 {
6173 if (nrot > fsSettings.getMaxRotatableBond())
6174 {
6175 String msg = "Evaluation of graph: Max rotatable bonds "
6176 + "constraint violated: "+ smiles;
6177 settings.getLogger().log(Level.FINE, msg);
6178 return null;
6179 }
6180 }
6181 mol.setProperty("ROT_BND", nrot);
6182
6183 // 1D) unacceptable free APs
6184 if (fsSettings.getFragmentSpace().useAPclassBasedApproach())
6185 {
6186 if (hasForbiddenEnd(fsSettings))
6187 {
6188 String msg = "Evaluation of graph: forbidden end in graph!";
6189 settings.getLogger().log(Level.FINE, msg);
6190 return null;
6191 }
6192 }
6193
6194 // criteria from settings of ring closures
6195 if (rcSettings.allowRingClosures() && !permissive)
6196 {
6197 // Count rings and RCAs
6198 int nPossRings = 0;
6199 Set<String> doneType = new HashSet<>();
6200 Map<String,String> rcaTypes = RingClosingAttractor.RCATYPEMAP;
6201 for (String rcaTyp : rcaTypes.keySet())
6202 {
6203 if (doneType.contains(rcaTyp))
6204 {
6205 continue;
6206 }
6207
6208 int nThisType = 0;
6209 int nCompType = 0;
6210 for (Vertex v : getRCVertices())
6211 {
6212 if (v.containsAtoms())
6213 {
6214 IAtom atm = v.getIAtomContainer().getAtom(0);
6215 if (MoleculeUtils.getSymbolOrLabel(atm).equals(rcaTyp))
6216 {
6217 nThisType++;
6218 } else if (MoleculeUtils.getSymbolOrLabel(atm).equals(
6219 rcaTypes.get(rcaTyp)))
6220 {
6221 nCompType++;
6222 }
6223 if (rcaTyp.equals(rcaTypes.get(rcaTyp)))
6224 {
6225 nCompType++;
6226 }
6227 }
6228 }
6229
6230 // check number of rca per type
6231 if (nThisType > rcSettings.getMaxRcaPerType(rcaTyp) ||
6232 nCompType > rcSettings.getMaxRcaPerType(rcaTyp))
6233 {
6234 String msg = "Evaluation of graph: too many RCAs! "
6235 + rcaTyp + ":" + nThisType + " "
6236 + rcaTypes.get(rcaTyp) + ":" + nCompType;
6237 settings.getLogger().log(Level.FINE, msg);
6238 return null;
6239 }
6240 if (nThisType < rcSettings.getMinRcaPerType(rcaTyp) ||
6241 nCompType < rcSettings.getMinRcaPerType(rcaTyp))
6242 {
6243 String msg = "Evaluation of graph: too few RCAs! "
6244 + rcaTyp + ":" + nThisType + " "
6245 + rcaTypes.get(rcaTyp) + ":" + nCompType;
6246 settings.getLogger().log(Level.FINE, msg);
6247 return null;
6248 }
6249
6250 nPossRings = nPossRings + Math.min(nThisType, nCompType);
6251 doneType.add(rcaTyp);
6252 doneType.add(rcaTypes.get(rcaTyp));
6253 }
6254 if (nPossRings < rcSettings.getMinRingClosures())
6255 {
6256 String msg = "Evaluation of graph: too few ring candidates";
6257 settings.getLogger().log(Level.FINE, msg);
6258 return null;
6259 }
6260 }
6261
6262 // get the smiles/Inchi representation
6263 String inchiKey = MoleculeUtils.getInChIKeyForMolecule(mol,
6264 settings.getLogger());
6265 if (inchiKey == null)
6266 {
6267 String msg = "Evaluation of graph: InChI Key is null!";
6268 settings.getLogger().log(Level.WARNING, msg);
6269 inchiKey = "UNDEFINED_INCHI";
6270 }
6271
6272 Object[] res = new Object[3];
6273 res[0] = inchiKey;
6274 res[1] = smiles;
6275 res[2] = mol;
6276
6277 return res;
6278 }
6279
6280//------------------------------------------------------------------------------
6281
6289 public ArrayList<DGraph> makeAllGraphsWithDifferentRingSets(
6290 RunTimeParameters settings)
6291 throws DENOPTIMException
6292 {
6294 if (settings.containsParameters(ParametersType.RC_PARAMS))
6295 {
6296 rcSettings = (RingClosureParameters)settings.getParameters(
6298 }
6300 if (settings.containsParameters(ParametersType.FS_PARAMS))
6301 {
6302 fsSettings = (FragmentSpaceParameters)settings.getParameters(
6304 }
6305 ArrayList<DGraph> lstGraphs = new ArrayList<>();
6306
6307 boolean rcnEnabled = fsSettings.getFragmentSpace()
6309 if (!rcnEnabled)
6310 return lstGraphs;
6311
6312 boolean evaluateRings = rcSettings.allowRingClosures();
6313 if (!evaluateRings)
6314 return lstGraphs;
6315
6316 // get a atoms/bonds molecular representation (no 3D needed)
6317 ThreeDimTreeBuilder t3d = new ThreeDimTreeBuilder(settings.getLogger(),
6318 settings.getRandomizer());
6319 t3d.setAlignBBsIn3D(false);
6320 IAtomContainer mol = t3d.convertGraphTo3DAtomContainer(this,false);
6321
6322 // Set rotatable property as property of IBond
6324 fsSettings.getRotSpaceDefFile(), true, true,
6325 settings.getLogger());
6326
6327 // get the set of possible RCA combinations = ring closures
6328 CyclicGraphHandler cgh = new CyclicGraphHandler(rcSettings,
6329 fsSettings.getFragmentSpace());
6330 ArrayList<List<Ring>> allCombsOfRings =
6331 cgh.getPossibleCombinationOfRings(mol, this);
6332
6333 // Keep closable chains that are relevant for chelate formation
6334 if (rcSettings.buildChelatesMode())
6335 {
6336 ArrayList<List<Ring>> toRemove = new ArrayList<>();
6337 for (List<Ring> setRings : allCombsOfRings)
6338 {
6339 if (!cgh.checkChelatesGraph(this,setRings))
6340 {
6341 toRemove.add(setRings);
6342 }
6343 }
6344 allCombsOfRings.removeAll(toRemove);
6345 }
6346
6347 // prepare output graphs
6348 for (List<Ring> ringSet : allCombsOfRings)
6349 {
6350 // clone root graph
6351 DGraph newGraph = this.clone();
6352
6353 Map<Long,Long> vRenum = newGraph.renumberVerticesGetMap();
6355
6356 // add rings
6357 for (Ring oldRing : ringSet)
6358 {
6359 Ring newRing = new Ring();
6360 for (int i=0; i<oldRing.getSize(); i++)
6361 {
6362 long oldVId = oldRing.getVertexAtPosition(i).getVertexId();
6363 long newVId = vRenum.get(oldVId);
6364 newRing.addVertex(newGraph.getVertexWithId(newVId));
6365 }
6366 newRing.setBondType(oldRing.getBondType());
6367 newGraph.addRing(newRing);
6368 }
6369
6370 // store
6371 lstGraphs.add(newGraph);
6372 }
6373
6374 return lstGraphs;
6375 }
6376
6377//------------------------------------------------------------------------------
6378
6386 public boolean hasForbiddenEnd(FragmentSpaceParameters fsSettings)
6387 {
6388 List<Vertex> vertices = getVertexList();
6389 Set<APClass> classOfForbEnds =
6391 boolean found = false;
6392 for (Vertex vtx : vertices)
6393 {
6394 List<AttachmentPoint> daps = vtx.getAttachmentPoints();
6395 for (AttachmentPoint dp : daps)
6396 {
6397 if (dp.isAvailable())
6398 {
6399 APClass apClass = dp.getAPClass();
6400 if (classOfForbEnds.contains(apClass))
6401 {
6402 found = true;
6403 String msg = "Forbidden free AP for Vertex: "
6404 + vtx.getVertexId() + " "
6405 + vtx.toString()
6406 + "\n"+ this +" \n "
6407 + " AP class: " + apClass;
6408 fsSettings.getLogger().log(Level.WARNING, msg);
6409 break;
6410 }
6411 }
6412 }
6413 if (found)
6414 {
6415 break;
6416 }
6417 }
6418
6419 return found;
6420 }
6421
6422//------------------------------------------------------------------------------
6423
6443 public void appendGraphOnGraph(List<Vertex> parentVertices,
6444 List<Integer> parentAPIdx,
6445 DGraph subGraph,
6446 Vertex childVertex, int childAPIdx,
6447 BondType bndType, boolean onAllSymmAPs)
6448 throws DENOPTIMException
6449 {
6450 // Collector for symmetries created by appending copies of subGraph
6451 Map<Vertex, SymmetricVertexes> newSymSets = new HashMap<>();
6452
6453 // Repeat append for each parent vertex while collecting symmetries
6454 for (int i=0; i<parentVertices.size(); i++)
6455 {
6456 appendGraphOnGraph(parentVertices.get(i), parentAPIdx.get(i),
6457 subGraph, childVertex, childAPIdx, bndType,
6458 newSymSets, onAllSymmAPs);
6459 }
6460 }
6461
6462//------------------------------------------------------------------------------
6463
6477 AttachmentPoint trgAP) throws DENOPTIMException
6478 {
6479 if (!srcAP.isAvailable())
6480 {
6481 throw new DENOPTIMException("Attempt to use unavailable "
6482 + "attachment point " + srcAP + " on vertex "
6483 + srcAP.getOwner().getVertexId() + " as srcAP.");
6484 }
6485 if ( !trgAP.isAvailable())
6486 {
6487 throw new DENOPTIMException("Attempt to use unavailable "
6488 + "attachment point " + trgAP + " on vertex "
6489 + trgAP.getOwner().getVertexId() + " as trgAP.");
6490 }
6491
6492 BondType btSrc = srcAP.getBondType();
6493 BondType btTrg = trgAP.getBondType();
6494 BondType bndTyp = btSrc;
6495 if (btSrc != btTrg)
6496 {
6497 if (btSrc == BondType.ANY && btTrg != BondType.ANY)
6498 {
6499 bndTyp = btTrg;
6500 } else {
6501 if (btSrc != BondType.ANY && btTrg == BondType.ANY)
6502 {
6503 bndTyp = btSrc;
6504 } else {
6505 bndTyp = BondType.UNDEFINED;
6506 }
6507 }
6508 }
6509
6510 this.addVertex(trgAP.getOwner());
6511 Edge edge = new Edge(srcAP,trgAP, bndTyp);
6512 addEdge(edge);
6513 }
6514
6515//------------------------------------------------------------------------------
6516
6526 public void appendGraphOnAP(AttachmentPoint apOnThisGraph,
6527 AttachmentPoint apOnIncomingGraph, BondType bndType)
6528 throws DENOPTIMException
6529 {
6530 DGraph incomingGraph = apOnIncomingGraph.getOwner().getGraphOwner();
6531 incomingGraph.renumberGraphVertices();
6532
6533 Edge edge = new Edge(apOnThisGraph, apOnIncomingGraph,
6534 bndType);
6535 addEdge(edge);
6536
6537 //Import vertices
6538 for (Vertex incomingVrtx : incomingGraph.getVertexList())
6539 {
6540 addVertex(incomingVrtx);
6541 }
6542
6543 //Import edges
6544 for (Edge incomingEdge : incomingGraph.getEdgeList())
6545 {
6546 addEdge(incomingEdge);
6547 }
6548
6549 //Import rings
6550 for (Ring incomingRing : incomingGraph.getRings())
6551 {
6552 addRing(incomingRing);
6553 }
6554
6555 incomingGraph.cleanup();
6556 }
6557
6558//------------------------------------------------------------------------------
6559
6580 public void appendGraphOnAP(Vertex parentVertex, int parentAPIdx,
6581 DGraph subGraph,
6582 Vertex childVertex, int childAPIdx,
6583 BondType bndType,
6584 Map<Vertex, SymmetricVertexes> newSymSets)
6585 throws DENOPTIMException
6586 {
6587 // Clone and renumber the subgraph to ensure uniqueness
6588 DGraph sgClone = subGraph.clone();
6589 // The clones have the same vertex IDs before renumbering vertices
6590 Vertex cvClone = sgClone.getVertexWithId(
6591 childVertex.getVertexId());
6592 sgClone.renumberGraphVertices();
6593
6594 Edge edge = new Edge(parentVertex.getAP(parentAPIdx),
6595 cvClone.getAP(childAPIdx), bndType);
6596 addEdge(edge);
6597
6598 // Import all vertices from cloned subgraph, i.e., sgClone
6599 for (int i=0; i<sgClone.getVertexList().size(); i++)
6600 {
6601 Vertex clonV = sgClone.getVertexList().get(i);
6602 Vertex origV = subGraph.getVertexList().get(i);
6603
6604 addVertex(sgClone.getVertexList().get(i));
6605
6606 // also need to tmp store pointers to symmetric vertices
6607 // Why is this working on subGraph and not on sgClone?
6608 // Since we are only checking is there is symmetry, there should be
6609 // no difference between doing it on sgClone or subGraph.
6610 if (subGraph.hasSymmetryInvolvingVertex(origV))
6611 {
6612 if (newSymSets.containsKey(origV))
6613 {
6614 newSymSets.get(origV).add(clonV);
6615 }
6616 else
6617 {
6618 newSymSets.put(origV, sgClone.getSymSetForVertex(clonV));
6619 }
6620 }
6621 else
6622 {
6623 if (newSymSets.containsKey(origV))
6624 {
6625 newSymSets.get(origV).add(clonV);
6626 }
6627 else
6628 {
6630 ss.add(clonV);
6631 newSymSets.put(origV, ss);
6632 }
6633 }
6634 }
6635 // Import all edges from cloned subgraph
6636 for (int i=0; i<sgClone.getEdgeList().size(); i++)
6637 {
6638 addEdge(sgClone.getEdgeList().get(i));
6639 }
6640 // Import all rings from cloned subgraph
6641 for (int i=0; i<sgClone.getRings().size(); i++)
6642 {
6643 addRing(sgClone.getRings().get(i));
6644 }
6645
6646 // project tmp symmetric set into final symmetric sets
6647 Set<SymmetricVertexes> doneTmpSymSets = new HashSet<SymmetricVertexes>();
6648 for (Map.Entry<Vertex, SymmetricVertexes> e : newSymSets.entrySet())
6649 {
6650 SymmetricVertexes tmpSS = e.getValue();
6651 if (doneTmpSymSets.contains(tmpSS))
6652 {
6653 continue;
6654 }
6655 doneTmpSymSets.add(tmpSS);
6656 boolean done = false;
6657 // NB: no need to check all entries of tmpSS: the first is enough
6658 SymmetricVertexes oldSS;
6659 Iterator<SymmetricVertexes> iter = getSymSetsIterator();
6660 while (iter.hasNext())
6661 {
6662 oldSS = iter.next();
6663 if (oldSS.contains(tmpSS.get(0)))
6664 {
6665 oldSS.addAll(tmpSS);
6666 done = true;
6667 break;
6668 }
6669 }
6670 if (!done)
6671 {
6672 if (tmpSS.size() <= 1)
6673 {
6674 // tmpSS has always at least one entry: the initial vrtx
6675 continue;
6676 }
6677 //Move tmpSS into a new SS on molGraph
6679 newSS.addAll(tmpSS);
6681 }
6682 }
6683 }
6684
6685//------------------------------------------------------------------------------
6686
6705 public void appendGraphOnGraph(Vertex parentVertex,
6706 int parentAPIdx, DGraph subGraph,
6707 Vertex childVertex, int childAPIdx,
6708 BondType bndType,
6709 Map<Vertex, SymmetricVertexes> newSymSets,
6710 boolean onAllSymmAPs)
6711 throws DENOPTIMException
6712 {
6713 SymmetricAPs symAPs = parentVertex.getSymmetricAPs(
6714 parentVertex.getAP(parentAPIdx));
6715 if (symAPs.size()!=0 && onAllSymmAPs)
6716 {
6717 for (AttachmentPoint symAP : symAPs)
6718 {
6719 if (!symAP.isAvailable())
6720 {
6721 continue;
6722 }
6723 appendGraphOnAP(parentVertex, symAP.getIndexInOwner(),
6724 subGraph, childVertex,
6725 childAPIdx, bndType, newSymSets);
6726 }
6727 } else {
6728 appendGraphOnAP(parentVertex, parentAPIdx, subGraph, childVertex,
6729 childAPIdx, bndType, newSymSets);
6730 }
6731 }
6732
6733//-----------------------------------------------------------------------------
6734
6742 public List<List<AttachmentPoint>> findAPs(
6743 List<AttachmentPointQuery> apQueries, Logger logger)
6744 {
6745 List<List<AttachmentPoint>> result = new ArrayList<>();
6746 for (AttachmentPointQuery apQuery : apQueries)
6747 {
6748 result.add(findAPs(apQuery, logger));
6749 }
6750 return result;
6751 }
6752
6753//-----------------------------------------------------------------------------
6754
6762 public List<AttachmentPoint> findAPs(AttachmentPointQuery apQuery, Logger logger)
6763 {
6764 logger.log(Level.FINE, "AP candidates: " + getAttachmentPoints());
6765
6766 List<AttachmentPoint> matches = new ArrayList<>();
6768 {
6769 if (apQuery.matches(ap))
6770 {
6771 matches.add(ap);
6772 }
6773 }
6774
6775 logger.log(Level.FINE, "AP matches: " + matches);
6776 return matches;
6777 }
6778
6779//-----------------------------------------------------------------------------
6780
6788 public List<Long> findVerticesIds(VertexQuery query, Logger logger)
6789 {
6790 List<Long> matches = new ArrayList<>();
6791 for (Vertex v : findVertices(query, logger))
6792 {
6793 matches.add(v.getVertexId());
6794 }
6795 return matches;
6796 }
6797
6798//-----------------------------------------------------------------------------
6799
6808 public List<Vertex> findVertices(VertexQuery vrtxQuery, Logger logger)
6809 {
6810 return findVertices(vrtxQuery, true,logger);
6811 }
6812
6813//-----------------------------------------------------------------------------
6814
6825 public List<Vertex> findVertices(VertexQuery vrtxQuery,
6826 boolean purgeSym, Logger logger)
6827 {
6828 logger.log(Level.FINE, "Candidates: " + getVertexList());
6829
6830 List<Vertex> matches = new ArrayList<>();
6831 for (Vertex v : getVertexList())
6832 {
6833 if (vrtxQuery.matches(v))
6834 {
6835 matches.add(v);
6836 }
6837 }
6838
6839 logger.log(Level.FINE, "Matches: " + matches);
6840
6841 if (purgeSym)
6842 {
6843 removeSymmetryRedundance(matches);
6844 }
6845
6846 logger.log(Level.FINE, "Final Matches (after symmetry): " + matches);
6847
6848 return matches;
6849 }
6850
6851//-----------------------------------------------------------------------------
6852
6859 public List<Edge> findEdges(EdgeQuery edgeQuery, Logger logger)
6860 {
6861 ArrayList<Edge> matches = new ArrayList<>(getEdgeList());
6862 logger.log(Level.FINE, "Edge candidates: " + matches);
6863
6864 if (edgeQuery == null)
6865 {
6866 return matches;
6867 }
6868
6869 ArrayList<Edge> newLst = new ArrayList<>();
6870 for (Edge e : matches)
6871 {
6872 if (edgeQuery.matches(e))
6873 {
6874 newLst.add(e);
6875 }
6876 }
6877 logger.log(Level.FINE, "Edge matches: " + newLst);
6878 return newLst;
6879 }
6880
6881//-----------------------------------------------------------------------------
6882
6889 private class EdgeFinder implements Function<Vertex,List<Edge>>
6890 {
6891 private int mode = 0;
6892
6897 public EdgeFinder(int i)
6898 {
6899 mode = i;
6900 }
6901
6902 @Override
6903 public List<Edge> apply(Vertex v)
6904 {
6905 List<Edge> edges = new ArrayList<Edge>();
6906 if (mode < 0)
6907 {
6908 Edge eToParent = v.getEdgeToParent();
6909 if (eToParent != null)
6910 edges.add(eToParent);
6911 } else {
6913 {
6914 if (!ap.isAvailable() && ap.isSrcInUser())
6915 {
6916 edges.add(ap.getEdgeUser());
6917 }
6918 }
6919 }
6920 return edges;
6921 }
6922 }
6923
6924//-----------------------------------------------------------------------------
6925
6932 public void removeSymmetryRedundance(List<Vertex> list)
6933 {
6934 List<Vertex> symRedundant = new ArrayList<>();
6935 Iterator<SymmetricVertexes> itSymm = getSymSetsIterator();
6936 while (itSymm.hasNext())
6937 {
6938 SymmetricVertexes ss = itSymm.next();
6939 for (Vertex v : list)
6940 {
6941 if (symRedundant.contains(v))
6942 {
6943 continue;
6944 }
6945 if (ss.contains(v))
6946 {
6947 symRedundant.addAll(ss);
6948 symRedundant.remove(v);
6949 }
6950 }
6951 }
6952 for (Vertex v : symRedundant)
6953 {
6954 list.remove(v);
6955 }
6956 }
6957
6958//-----------------------------------------------------------------------------
6959
6966 public void removeSymmetryRedundantIds(ArrayList<Long> list) {
6967 ArrayList<Vertex> vList = new ArrayList<>();
6968 for (long vid : list) {
6969 vList.add(getVertexWithId(vid));
6970 }
6972 list.clear();
6973 for (Vertex v : vList) {
6974 list.add(v.getVertexId());
6975 }
6976 }
6977
6978//------------------------------------------------------------------------------
6979
6993 public DGraph editGraph(ArrayList<GraphEdit> edits,
6994 boolean symmetry, FragmentSpace fragSpace, Logger logger)
6995 throws DENOPTIMException
6996 {
6997 DGraph modGraph = this.clone();
6998
6999 for (GraphEdit edit : edits)
7000 {
7001 logger.log(Level.FINE, "Graph edit task: " + edit.getType());
7002
7003 switch (edit.getType())
7004 {
7005 case REPLACECHILD:
7006 {
7007 DGraph inGraph = edit.getIncomingGraph();
7008 VertexQuery query = edit.getVertexQuery();
7009 int idAPOnInGraph = -1; // Initialization to invalid value
7010 Vertex rootOfInGraph = null;
7011 if (edit.getIncomingAPId() != null)
7012 {
7013 AttachmentPoint ap = inGraph.getAPWithId(
7014 edit.getIncomingAPId().intValue());
7015 if (ap == null)
7016 {
7017 String msg = "Skipping " + edit.getType() + " on "
7018 + "graph " + getGraphId() + ". The incoming"
7019 + " graph has no AP with ID = "
7020 + edit.getIncomingAPId() + ". The IDs of "
7021 + "free APs are:";
7022 for (AttachmentPoint freeAP : inGraph.getAvailableAPs())
7023 {
7024 msg = msg + " " + freeAP.getID();
7025 }
7026 msg = msg + ". "
7027 + "Please, use one of those values in "
7028 + "'idAPOnIncomingGraph'.";
7029 logger.log(Level.WARNING, msg);
7030 }
7031 idAPOnInGraph = ap.getIndexInOwner();
7032 rootOfInGraph = ap.getOwner();
7033 } else {
7034 ArrayList<AttachmentPoint> freeAPs =
7035 inGraph.getAvailableAPs();
7036 if (freeAPs.size()==1)
7037 {
7038 AttachmentPoint ap = freeAPs.get(0);
7039 idAPOnInGraph = ap.getIndexInOwner();
7040 rootOfInGraph = ap.getOwner();
7041 } else {
7042 String geClsName = GraphEdit.class.getSimpleName();
7043 String msg = "Skipping " + edit.getType() + " on "
7044 + "graph " + getGraphId() + ". The incoming"
7045 + " graph has more than one free AP ("
7046 + freeAPs.size() + ") and "
7047 + "the " + geClsName + " "
7048 + "does not provide sufficient information "
7049 + "to unambiguously choose one AP. "
7050 + "Please, add 'idAPOnIncomingGraph' in "
7051 + "the definition of " + geClsName + ".";
7052 logger.log(Level.WARNING, msg);
7053 }
7054 }
7055
7056 List<Vertex> matches = modGraph.findVertices(query,
7057 false, logger);
7058 for (Vertex vertexToReplace : matches)
7059 {
7060 Edge edgeToParent = vertexToReplace.getEdgeToParent();
7061 if (edgeToParent == null)
7062 {
7063 //The matched vertex has no parent, therefore
7064 // the change would correspond to changing the graph
7065 // completely. This is unlikely the desired effect,
7066 // so we do not do anything.
7067 continue;
7068 }
7069 Vertex parent = vertexToReplace.getParent();
7070 int srcApId = edgeToParent.getSrcAPID();
7071
7072 BondType bondType = edgeToParent.getBondType();
7073
7074 modGraph.removeBranchStartingAt(vertexToReplace,symmetry);
7075
7076 modGraph.appendGraphOnGraph(parent, srcApId, inGraph,
7077 rootOfInGraph, idAPOnInGraph, bondType,
7078 new HashMap<Vertex, SymmetricVertexes>(), symmetry);
7079 }
7080 break;
7081 }
7082 case CHANGEVERTEX:
7083 {
7084 // One of the ways to provide the incoming vertex/subgraph
7085 if (edit.getIncomingBBId() > -1
7086 && edit.getIncomingBBType() != null
7087 && edit.getIncomingGraph() == null)
7088 {
7089 List<Vertex> matches = modGraph.findVertices(
7090 edit.getVertexQuery(), false, logger);
7091 for (Vertex vertexToChange : matches)
7092 {
7093 if (modGraph.containsVertex(vertexToChange))
7094 {
7095 DGraph graph = vertexToChange.getGraphOwner();
7096 graph.replaceVertex(vertexToChange,
7097 edit.getIncomingBBId(),
7098 edit.getIncomingBBType(),
7099 edit.getAPMappig(),
7100 symmetry,
7101 fragSpace);
7102 }
7103 }
7104 }
7105 // Another of the ways to provide the incoming vertex/subgraph
7106 if (edit.getIncomingGraph() != null
7107 && edit.getIncomingBBType() == null)
7108 {
7109 // Since the replaceSingleSubGraph method below does not
7110 // deal with symmetry, we keep symmetrically-redundant
7111 // matches
7112 List<Vertex> matches = modGraph.findVertices(
7113 edit.getVertexQuery(), false, logger);
7114
7115 for (Vertex vertexToChange : matches)
7116 {
7117 DGraph newSubG = edit.getIncomingGraph().clone();
7118 newSubG.renumberGraphVertices();
7119
7120 APMapping apMap = new APMapping();
7121 for (Map.Entry<Integer,Integer> e :
7122 edit.getAPMappig().entrySet())
7123 {
7124 apMap.put(vertexToChange.getAP(e.getKey()),
7125 newSubG.getAvailableAPs().get(
7126 e.getValue()));
7127 }
7128
7129 List<Vertex> oldSubG = new ArrayList<Vertex>();
7130 oldSubG.add(vertexToChange);
7131 DGraph.replaceSingleSubGraph(apMap, fragSpace);
7132 }
7133 }
7134
7135 break;
7136 }
7137 case CHANGESUBGRAPH:
7138 {
7139 // Identify the APs that are involved within this graph (well, it's clone)
7140 List<List<AttachmentPoint>> apMatchesOnGraph = modGraph.findAPs(
7141 edit.getTargetGraphAPQueries(), logger);
7142 for (List<AttachmentPoint> aps : apMatchesOnGraph)
7143 {
7144 if (aps.size() ==0)
7145 {
7146 throw new IllegalStateException(
7147 "No APs found for the target graph. "
7148 + "Cannot perform " + edit.getType() + ".");
7149 } else if (aps.size() > 1)
7150 {
7151 throw new IllegalStateException(
7152 "Expected 1 AP matching the query on the target "
7153 + "graph, but found " + aps.size()
7154 + ". Cannot perform " + edit.getType() + ".");
7155 }
7156 }
7157
7158 // Identify the APs that are involved within the incoming graph
7159 DGraph incomingGraph = edit.getIncomingGraph();
7160 if (incomingGraph == null)
7161 {
7162 String pathName = edit.getIncomingGraphPathname();
7163 if (pathName == null)
7164 {
7165 throw new IllegalStateException(
7166 "The incoming graph pathname is null. "
7167 + "Cannot perform " + edit.getType() + ".");
7168 }
7169 try {
7170 incomingGraph = DenoptimIO.readDENOPTIMGraphsFromFile(
7171 new File(pathName)).get(0);
7172 } catch (Exception e) {
7173 throw new IllegalStateException(
7174 "Error reading the incoming graph from file " + pathName + ". "
7175 + "Cannot perform " + edit.getType() + ".", e);
7176 }
7177 }
7178 List<List<AttachmentPoint>> apMatchesOnIncomingGraph = incomingGraph.findAPs(
7179 edit.getIncomingGraphAPQueries(), logger);
7180 for (List<AttachmentPoint> aps : apMatchesOnIncomingGraph)
7181 {
7182 if (aps.size() == 0)
7183 {
7184 throw new IllegalStateException(
7185 "No APs found for the incoming graph. "
7186 + "Cannot perform " + edit.getType() + ".");
7187 } else if (aps.size() > 1)
7188 {
7189 throw new IllegalStateException(
7190 "Expected 1 AP matching the query on the incoming "
7191 + "graph, but found " + aps.size()
7192 + ". Cannot perform " + edit.getType() + ".");
7193 }
7194 }
7195
7196 if (apMatchesOnGraph.get(0).size()
7197 != apMatchesOnIncomingGraph.get(0).size())
7198 {
7199 throw new IllegalStateException(
7200 "The number of APs on the target graph and the incoming "
7201 + "graph do not match. Cannot perform " + edit.getType() + ".");
7202 }
7203
7204 APMapping apMapping = new APMapping();
7205 for (int i = 0; i < apMatchesOnGraph.size(); i++)
7206 {
7207 // We have ensured the lists contain only one entry
7208 apMapping.put(apMatchesOnGraph.get(i).get(0),
7209 apMatchesOnIncomingGraph.get(i).get(0));
7210 }
7211
7212 // Perform the actual subgraph replacement
7213 DGraph.replaceSingleSubGraph(apMapping, fragSpace);
7214 break;
7215 }
7216 case DELETEBRANCH:
7217 {
7218 List<Vertex> matches = modGraph.findVertices(
7219 edit.getVertexQuery(), false, logger);
7220 for (Vertex vertexToRemove : matches)
7221 {
7222 if (modGraph.containsVertex(vertexToRemove))
7223 modGraph.removeBranchStartingAt(vertexToRemove,
7224 symmetry);
7225 }
7226 break;
7227 }
7228 case DELETEVERTEX:
7229 {
7230 List<Vertex> matches = modGraph.findVertices(
7231 edit.getVertexQuery(), false, logger);
7232 for (Vertex vertexToRemove : matches)
7233 {
7234 if (modGraph.containsVertex(vertexToRemove))
7235 modGraph.removeVertexAndSymmetricOnes(vertexToRemove,
7236 symmetry);
7237 }
7238 break;
7239 }
7240 }
7241 }
7242
7243 if (modGraph.getVertexList().size() == 0)
7244 {
7245 logger.log(Level.WARNING, "The graph after editing is empty. "
7246 + "This will likely trigger an error in subsequent steps.");
7247 }
7248
7249 return modGraph;
7250 }
7251
7252//------------------------------------------------------------------------------
7253
7262 public List<Vertex> getMutableSites()
7263 {
7264 List<Vertex> mutableSites = new ArrayList<Vertex>();
7265 for (Vertex v : gVertices)
7266 {
7267 mutableSites.addAll(v.getMutationSites(
7268 new ArrayList<MutationType>()));
7269 }
7270 return mutableSites;
7271 }
7272
7273//------------------------------------------------------------------------------
7274
7286 public List<Vertex> getMutableSites(List<MutationType> ignoredTypes)
7287 {
7288 List<Vertex> mutableSites = new ArrayList<Vertex>();
7289 for (Vertex v : gVertices)
7290 {
7291 mutableSites.addAll(v.getMutationSites(ignoredTypes));
7292 }
7293 return mutableSites;
7294 }
7295
7296//------------------------------------------------------------------------------
7297
7309 public List<Vertex> getSelectedMutableSites(MutationType requestedType)
7310 {
7311 List<Vertex> mutableSites = new ArrayList<Vertex>();
7312 for (Vertex v : gVertices)
7313 {
7314 v.getMutationSites()
7315 .stream()
7316 .filter(vrt -> vrt.getMutationTypes().contains(requestedType))
7317 .forEach(vrt -> mutableSites.add(vrt));
7318 }
7319 return mutableSites;
7320 }
7321
7322//------------------------------------------------------------------------------
7323
7330 public String toJson()
7331 {
7332 Gson gson = DENOPTIMgson.getWriter();
7333 String jsonOutput = gson.toJson(this);
7334 return jsonOutput;
7335 }
7336
7337//------------------------------------------------------------------------------
7338
7339 protected void ensureUniqueApIDs()
7340 {
7342 {
7343 ap.setID(apCounter.getAndIncrement());
7344 }
7345 }
7346
7347//------------------------------------------------------------------------------
7348
7355 public static DGraph fromJson(String json)
7356 {
7357 Gson gson = DENOPTIMgson.getReader();
7358 DGraph graph = gson.fromJson(json, DGraph.class);
7359 return graph;
7360 }
7361
7362//------------------------------------------------------------------------------
7363
7370 public static DGraph fromJson(Reader reader)
7371 {
7372 Gson gson = DENOPTIMgson.getReader();
7373 DGraph graph = gson.fromJson(reader, DGraph.class);
7374 return graph;
7375 }
7376
7377//------------------------------------------------------------------------------
7378
7382 public static class DENOPTIMGraphSerializer
7383 implements JsonSerializer<DGraph>
7384 {
7385 @Override
7386 public JsonElement serialize(DGraph g, Type typeOfSrc,
7387 JsonSerializationContext context)
7388 {
7389 boolean regenerateVrtxID = false;
7390 boolean regenerateAP = false;
7391 Set<Long> unqVrtxIDs = new HashSet<Long>();
7392 Set<Integer> unqApIDs = new HashSet<Integer>();
7393 for (Vertex v : g.getVertexList())
7394 {
7395 if (!unqVrtxIDs.add(v.getVertexId()))
7396 {
7397 regenerateVrtxID = true;
7398 }
7399 for (AttachmentPoint ap : v.getAttachmentPoints())
7400 {
7401 if (!unqApIDs.add(ap.getID()))
7402 {
7403 regenerateAP = true;
7404 break;
7405 }
7406 }
7407 }
7408 if (regenerateVrtxID)
7409 {
7411 }
7412 if (regenerateAP)
7413 {
7415 }
7416
7417 JsonObject jsonObject = new JsonObject();
7418 jsonObject.addProperty("graphId", g.graphId);
7419 jsonObject.add("gVertices", context.serialize(g.gVertices));
7420 jsonObject.add("gEdges", context.serialize(g.gEdges));
7421 jsonObject.add("gRings", context.serialize(g.gRings));
7422 jsonObject.add("symVertices", context.serialize(g.symVertices));
7423 return jsonObject;
7424 }
7425 }
7426
7427 //--------------------------------------------------------------------------
7428
7429 public static class DENOPTIMGraphDeserializer
7430 implements JsonDeserializer<DGraph>
7431 {
7432 @Override
7433 public DGraph deserialize(JsonElement json, Type typeOfT,
7434 JsonDeserializationContext context) throws JsonParseException
7435 {
7436 JsonObject jsonObject = json.getAsJsonObject();
7437
7438 // First, build a graph with a graph ID and a list of vertices
7439 JsonObject partialJsonObj = new JsonObject();
7440 partialJsonObj.add("graphId", jsonObject.get("graphId"));
7441 partialJsonObj.add("gVertices", jsonObject.get("gVertices"));
7442
7443 Gson gson = new GsonBuilder()
7444 .setExclusionStrategies(new DENOPTIMExclusionStrategyNoAPMap())
7445 .registerTypeAdapter(Vertex.class,
7447 .registerTypeAdapter(APClass.class, new APClassDeserializer())
7448 .setPrettyPrinting()
7449 .create();
7450
7451 DGraph graph = gson.fromJson(partialJsonObj, DGraph.class);
7452
7453 // Refresh APs
7454 for (Vertex v : graph.getVertexList())
7455 {
7456 // Regenerate reference to fragment owner
7457 v.setGraphOwner(graph);
7458
7459 for (AttachmentPoint ap : v.getAttachmentPoints())
7460 {
7461 // Regenerate reference to AP owner
7462 ap.setOwner(v);
7463 }
7464 }
7465
7466 // Then, recover those members that are heavily based on references:
7467 // edges, rings.
7468 JsonArray edgeArr = jsonObject.get("gEdges").getAsJsonArray();
7469 for (JsonElement e : edgeArr)
7470 {
7471 JsonObject o = e.getAsJsonObject();
7472 AttachmentPoint srcAP = graph.getAPWithId(
7473 o.get("srcAPID").getAsInt());
7474 AttachmentPoint trgAP = graph.getAPWithId(
7475 o.get("trgAPID").getAsInt());
7476
7477 Edge edge = new Edge(srcAP, trgAP,
7478 context.deserialize(o.get("bondType"),BondType.class));
7479 graph.addEdge(edge);
7480 }
7481
7482 // Now, recover the rings
7483 JsonArray ringArr = jsonObject.get("gRings").getAsJsonArray();
7484 for (JsonElement e : ringArr)
7485 {
7486 JsonObject o = e.getAsJsonObject();
7487 Ring ring = new Ring();
7488 for (JsonElement re : o.get("vertices").getAsJsonArray())
7489 {
7490 ring.addVertex(graph.getVertexWithId(re.getAsInt()));
7491 }
7492 ring.setBondType(context.deserialize(o.get("bndTyp"),
7493 BondType.class));
7494 graph.addRing(ring);
7495 }
7496
7497 //and symmetry relations between vertexes
7498 if (jsonObject.has("symVertices"))
7499 {
7500 for (JsonElement elSet : jsonObject.get("symVertices").getAsJsonArray())
7501 {
7503 for (JsonElement elId : elSet.getAsJsonArray())
7504 {
7505 int id = context.deserialize(elId, Integer.class);
7506 ss.add(graph.getVertexWithId(id));
7507 }
7508 try
7509 {
7510 graph.addSymmetricSetOfVertices(ss);
7511 } catch (DENOPTIMException e1)
7512 {
7513 e1.printStackTrace();
7514 throw new Error("Vertex listed in multiple symmetric "
7515 + "sets. Check this: " + elSet);
7516 }
7517 }
7518 }
7519
7520 return graph;
7521 }
7522 }
7523
7524//------------------------------------------------------------------------------
7525
7533 public static void setScaffold(Vertex v) {
7534 ArrayList<Vertex> newVertexList = new ArrayList<>();
7535
7536 Set<Long> visited = new HashSet<>();
7537 Queue<Vertex> currLevel = new ArrayDeque<>();
7538 Queue<Vertex> nextLevel = new ArrayDeque<>();
7539 currLevel.add(v);
7540
7541 while (!currLevel.isEmpty()) {
7542 Vertex currVertex = currLevel.poll();
7543
7544 long currId = currVertex.getVertexId();
7545 if (!visited.contains(currId)) {
7546 visited.add(currId);
7547
7548 newVertexList.add(currVertex);
7549
7550 Iterable<Vertex> neighbors = currVertex
7552 .stream()
7554 .filter(e -> e != null)
7555 .map(e -> e.getSrcVertex() == currId ?
7556 e.getTrgAP() : e.getSrcAP())
7558 .collect(Collectors.toList());
7559 for (Vertex adj : neighbors) {
7560 nextLevel.add(adj);
7561 }
7562 }
7563
7564 if (currLevel.isEmpty()) {
7565 currLevel = nextLevel;
7566 nextLevel = new ArrayDeque<>();
7567 }
7568 }
7569
7570 v.getGraphOwner().setVertexList(newVertexList);
7571 }
7572
7573//------------------------------------------------------------------------------
7574
7579 public boolean hasScaffoldTypeVertex() {
7580 return getVertexList()
7581 .stream()
7582 .anyMatch(v -> v.getBuildingBlockType() == BBType.SCAFFOLD);
7583 }
7584
7585//------------------------------------------------------------------------------
7586
7592 public void setTemplateJacket(Template template)
7593 {
7594 this.templateJacket = template;
7595 }
7596
7597//------------------------------------------------------------------------------
7598
7603 {
7604 return templateJacket;
7605 }
7606
7607//------------------------------------------------------------------------------
7608
7614 {
7615 if (templateJacket == null)
7616 return this;
7617 else
7619 }
7620
7621//------------------------------------------------------------------------------
7622
7635 public List<Template> getEmbeddingPath()
7636 {
7637 List<Template> path = new ArrayList<Template>();
7638 if (templateJacket==null)
7639 return path;
7640 if (templateJacket.getGraphOwner()!=null)
7642 path.add(templateJacket);
7643 return path;
7644 }
7645
7646//------------------------------------------------------------------------------
7647
7653 {
7654 for (Vertex v : gVertices)
7655 {
7656 v.setProperty(DENOPTIMConstants.STOREDVID, v.getVertexId());
7657 }
7658 }
7659
7660//------------------------------------------------------------------------------
7661
7675 public AttachmentPoint getAPOnLeftVertexID(long nbrVid, long vid)
7676 {
7677 Vertex v1 = getVertexWithId(nbrVid);
7678 Vertex v2 = getVertexWithId(vid);
7679 if ( v1== null || v2 == null)
7680 return null;
7681
7682 if (getChildVertices(v1).contains(v2))
7683 {
7684 return v2.getEdgeToParent().getSrcAP();
7685 } else if (getChildVertices(v2).contains(v1))
7686 {
7687 return v1.getEdgeToParent().getTrgAP();
7688 }
7689
7690 // At this point the two vertices are not directly connected, but there
7691 // could still be a chord between them. Here, we check for chords:
7692 /*
7693 for (DENOPTIMRing r : getRingsInvolvingVertex(v1))
7694 {
7695 if (r.contains(v2))
7696 {
7697 int lstId = r.getSize()-1;
7698 // Position 0 and lstId are where the RCVs sit
7699 if (r.getPositionOf(v1)==1 && r.getPositionOf(v2)==lstId)
7700 {
7701 return r.getHeadVertex().getEdgeToParent().getSrcAP();
7702 }
7703 if (r.getPositionOf(v1)==lstId && r.getPositionOf(v2)==1)
7704 {
7705 return r.getTailVertex().getEdgeToParent().getSrcAP();
7706 }
7707 }
7708 }
7709 */
7710 return null;
7711 }
7712
7713//------------------------------------------------------------------------------
7714
7724 public boolean isReversible(FragmentSpace fragSpace)
7725 {
7726 for (Edge e : gEdges)
7727 {
7728 if (!e.getTrgAPClass().isCPMapCompatibleWith(e.getSrcAPClass(),
7729 fragSpace))
7730 {
7731 return false;
7732 }
7733 }
7734 return true;
7735 }
7736
7737//------------------------------------------------------------------------------
7738
7756 DGraph graphB, List<Template> path)
7757 {
7758 if (path.isEmpty())
7759 return graphY;
7760 Template currentLevelVertex = null;
7761 DGraph currentLevelGraphEmdInB = graphB;
7762 DGraph currentLevelGraphEmbInY = graphY;
7763 for (Template t : path)
7764 {
7765 currentLevelVertex = (Template) currentLevelGraphEmbInY
7766 .getVertexAtPosition(currentLevelGraphEmdInB.indexOf(t));
7767 currentLevelGraphEmdInB = t.getInnerGraph();
7768 currentLevelGraphEmbInY = currentLevelVertex.getInnerGraph();
7769 }
7770 return currentLevelVertex.getInnerGraph();
7771 }
7772
7773//------------------------------------------------------------------------------
7774
7783 public List<AttachmentPoint> getInterfaceAPs(List<Vertex> subGraphB)
7784 {
7785 List<AttachmentPoint> interfaceAPs = new ArrayList<AttachmentPoint>();
7786 for (Vertex v : subGraphB)
7787 {
7788 for (AttachmentPoint ap : v.getAttachmentPoints())
7789 {
7790 if (ap.isAvailableThroughout())
7791 continue;
7792 if (ap.isAvailable())
7793 {
7794 // This AP is used across the template boundary
7795 interfaceAPs.add(ap);
7796 } else {
7797 Vertex user = ap.getLinkedAP().getOwner();
7798 if (!subGraphB.contains(user))
7799 {
7800 // AP used to make a connection to outside subgraph
7801 interfaceAPs.add(ap);
7802 }
7803 }
7804 }
7805 }
7806 return interfaceAPs;
7807 }
7808
7809//------------------------------------------------------------------------------
7810
7818 public List<AttachmentPoint> getSubgraphAPs(
7819 List<Vertex> subGraphB)
7820 {
7821 List<AttachmentPoint> aps = new ArrayList<AttachmentPoint>();
7822 for (Vertex v : subGraphB)
7823 {
7824 for (AttachmentPoint ap : v.getAttachmentPoints())
7825 {
7826 if (ap.isAvailable())
7827 {
7828 aps.add(ap);
7829 continue;
7830 }
7831 Vertex user = ap.getLinkedAP().getOwner();
7832 if (!subGraphB.contains(user))
7833 {
7834 // AP used to make a connection to outside subgraph
7835 aps.add(ap);
7836 }
7837 }
7838 }
7839 return aps;
7840 }
7841
7842//------------------------------------------------------------------------------
7843}
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)
static Vertex getPolarizedRCV(boolean polarity)
Returns a newly-built vertex that can play the role of a ring-closing vertex even when working with 3...
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 isSrcInUser()
Checks the role of this AP in the user.
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.
Query for searching AttachmentPoints.
boolean matches(AttachmentPoint ap)
Tests whether the given attachment point satisfies all non-null criteria in this query.
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:7433
We expect unique IDs for vertices.
Definition: DGraph.java:7384
JsonElement serialize(DGraph g, Type typeOfSrc, JsonSerializationContext context)
Definition: DGraph.java:7386
Utility to make selection of edges to a vertex tunable by a parameter.
Definition: DGraph.java:6890
List< Edge > apply(Vertex v)
Definition: DGraph.java:6903
Container for the list of vertices and the edges that connect them.
Definition: DGraph.java:104
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:1489
List< ClosableChain > getClosableChains()
Definition: DGraph.java:942
void getChildrenTree(Vertex vertex, List< Vertex > children, int numLayers, boolean stopBeforeRCVs)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:3556
void setTemplateJacket(Template template)
Sets the reference to a template that embeds this graph, i.e., this graph's "jacket" template.
Definition: DGraph.java:7592
void setVertexList(ArrayList< Vertex > vertices)
Definition: DGraph.java:908
String toJson()
Produces a string that represents this graph and that adheres to the JSON format.
Definition: DGraph.java:7330
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:3710
ArrayList< Integer > getIndexOfEdgesWithChild(int vid)
Definition: DGraph.java:3941
Candidate candidate
Reference to the candidate entity owning this graph, or null.
Definition: DGraph.java:147
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:2908
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:7675
Vertex getVertexWithId(long vid)
Searches for a vertex with the given identifier.
Definition: DGraph.java:3231
int getSymmetricSetCount()
Returns the number of symmetric sets of vertices.
Definition: DGraph.java:323
Vertex getSourceVertex()
Identifies and return the vertex from which the spanning tree originates.
Definition: DGraph.java:996
List< Integer > getBranchIdOfVertex(Vertex v)
Returns the branch identifier.
Definition: DGraph.java:3608
Edge getEdgeAtPosition(int pos)
Definition: DGraph.java:3298
void getChildrenTree(Vertex vertex, List< Vertex > children, boolean markBranches)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:3454
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:5337
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:4908
void removeRing(Ring ring)
Definition: DGraph.java:3286
ArrayList< AttachmentPoint > getAttachmentPoints()
Returns the list of all attachment points contained in this graph.
Definition: DGraph.java:4620
boolean containsVertexID(long l)
Checks if a number is already used as VertexIDs within the graph.
Definition: DGraph.java:3999
boolean containsVertex(Vertex v)
Check if this graph contains the specified vertex.
Definition: DGraph.java:3206
List< Vertex > findVertices(VertexQuery vrtxQuery, Logger logger)
Filters a list of vertices according to a query.
Definition: DGraph.java:6808
boolean isIsomorphicTo(DGraph other)
Checks if this graph is "DENOPTIM-isomorphic" to the other one given.
Definition: DGraph.java:4103
ArrayList< AttachmentPoint > getAvailableAPs()
Returns the list of available attachment points contained in this graph.
Definition: DGraph.java:4638
void setCandidateClosableChains(ArrayList< ClosableChain > closableChains)
Definition: DGraph.java:935
ArrayList< Ring > getRingsInvolvingVertex(Vertex v)
Returns the list of rings that include the given vertex in their fundamental cycle.
Definition: DGraph.java:1082
void addVertex(Vertex vertex)
Appends a vertex to this graph without creating any edge.
Definition: DGraph.java:1391
ArrayList< Ring > getRingsInvolvingVertexID(int vid)
Definition: DGraph.java:1127
int indexOfVertexWithID(long vid)
Returns the position of the first vertex that has the given ID.
Definition: DGraph.java:3247
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:1541
List< ClosableChain > closableChains
The potentially closable chains of vertices.
Definition: DGraph.java:123
DefaultUndirectedGraph< Vertex, UndirectedEdge > jGraph
JGraph representation used to detect DENOPTIM-isomorphism.
Definition: DGraph.java:158
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:5316
DGraph(List< Vertex > gVertices, List< Edge > gEdges)
Definition: DGraph.java:184
void getChildrenTree(Vertex vertex, List< Vertex > children)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:3421
boolean graphNeedsCappingGroups(FragmentSpace fragSpace)
Checks the graph for unused APs that need to be capped.
Definition: DGraph.java:4714
String getLocalMsg()
Definition: DGraph.java:289
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:4685
void removeVertex(Vertex vertex)
Remove a vertex from this graph.
Definition: DGraph.java:1413
Iterator< SymmetricVertexes > getSymSetsIterator()
Get an iterator for the sets of symmetrically related vertices.
Definition: DGraph.java:334
void setGraphId(int id)
Definition: DGraph.java:266
void removeSymmetryRedundance(List< Vertex > list)
Remove all but one of the symmetry-related partners in a list of vertices.
Definition: DGraph.java:6932
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:5417
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:4927
ArrayList< Vertex > getRCVertices()
Search for ring closing vertices: vertices that contain only a RingClosingAttractor
Definition: DGraph.java:1236
ArrayList< Vertex > getFreeRCVertices()
Search for unused ring closing vertices: vertices that contain only a RingClosingAttractor and are no...
Definition: DGraph.java:1258
void setCandidateOwner(Candidate candidate)
Sets the reference to the candidate item that is defined by this graph.
Definition: DGraph.java:247
List< List< Vertex > > getSymmetricSubGraphs(List< Vertex > subGrpVrtxs)
We assume that the subgraph is a continuously connected, directed graph.
Definition: DGraph.java:2137
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:4953
int indexOf(Vertex v)
Returns the index of a vertex in the list of vertices of this graph.
Definition: DGraph.java:3218
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:6993
List< Vertex > gVertices
The vertices belonging to this graph.
Definition: DGraph.java:108
boolean hasScaffoldTypeVertex()
Checks if this graph contains a scaffold vertex.
Definition: DGraph.java:7579
void setRings(ArrayList< Ring > rings)
Definition: DGraph.java:926
Object[] checkConsistency(RunTimeParameters settings)
Peeks into this graph to derive a preliminary chemical representation with SMILES and InChIKey.
Definition: DGraph.java:6053
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:3163
boolean containsAtoms()
Returns true if this graph has any vertex that contains atoms.
Definition: DGraph.java:4585
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:1061
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:7755
List< Ring > gRings
The rings defined in this graph.
Definition: DGraph.java:118
int getBondingAPIndex(Vertex srcVert, int dapidx, Vertex dstVert)
Definition: DGraph.java:3374
void setSymmetricVertexSets(List< SymmetricVertexes > symVertices)
Definition: DGraph.java:877
AtomicInteger apCounter
Generator of unique AP identifiers within this graph.
Definition: DGraph.java:174
Vertex getDeepestAmongThese(List< Vertex > list)
Identify the oldest ancestor (i.e., most great grandparent) in the given collection.
Definition: DGraph.java:3773
void appendGraphOnAP(AttachmentPoint apOnThisGraph, AttachmentPoint apOnIncomingGraph, BondType bndType)
Appends a graph onto this graph.
Definition: DGraph.java:6526
static boolean replaceSingleSubGraph(APMapping apMapping, FragmentSpace fragSpace)
Replaced the subgraph defined by a set of Attachment Points that belong to a graph (ie....
Definition: DGraph.java:2299
static void setScaffold(Vertex v)
Update the graph so that the vertex argument is at the scaffold level i.e.
Definition: DGraph.java:7533
Map< DGraph, ObjectPair > extractPattern(GraphPattern pattern, boolean recordConnectivity)
Extracts subgraphs that match the provided pattern.
Definition: DGraph.java:5188
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:7724
String getBranchIdOfVertexAsStr(Vertex v)
Returns the branch identifier as a literal string.
Definition: DGraph.java:3628
List< AttachmentPoint > getAvailableAPsThroughout()
Returns the list of attachment points contained in this graph that are available throughout the templ...
Definition: DGraph.java:4661
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:3650
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:6476
List< Vertex > getVertexList()
Returns the list of vertexes without entering Templates.
Definition: DGraph.java:973
boolean removeBranchStartingAt(Vertex v)
Deletes the branch, i.e., the specified vertex and its children.
Definition: DGraph.java:5521
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:4475
boolean hasSymmetricAP()
Definition: DGraph.java:296
void convertSymmetricLabelsToSymmetricSets()
Looks for any symmetric labels, creates symmetric sets that collect the same information,...
Definition: DGraph.java:1920
DGraph(List< Vertex > gVertices, List< Edge > gEdges, List< Ring > gRings, List< ClosableChain > closableChains, List< SymmetricVertexes > symVertices)
Definition: DGraph.java:220
List< AttachmentPoint > getInterfaceAPs(List< Vertex > subGraphB)
Searches for all AttachmentPoints that represent the interface between a subgraph,...
Definition: DGraph.java:7783
DGraph clone()
Returns almost "deep-copy" of this graph.
Definition: DGraph.java:3836
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:6386
List< DGraph > extractPattern(GraphPattern pattern)
Extracts subgraphs that match the provided pattern.
Definition: DGraph.java:5157
void removeCappingGroups(List< Vertex > lstVerts)
Remove capping groups that belong to this graph and are in the given list.
Definition: DGraph.java:4764
ArrayList< Vertex > getChildVertices(Vertex vertex)
Definition: DGraph.java:3406
boolean sameAsRings(StringBuilder reason, Map< Vertex, Vertex > vertexMap, Ring rT, Vertex vhT, Vertex vtT, Ring rO)
Definition: DGraph.java:4425
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:5114
void renumberGraphVertices()
Reassign vertex IDs to all vertices of this graph.
Definition: DGraph.java:5983
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:3179
ArrayList< DGraph > makeAllGraphsWithDifferentRingSets(RunTimeParameters settings)
Evaluates the possibility of closing rings in this graph and generates all alternative graphs resulti...
Definition: DGraph.java:6289
static DGraph fromJson(Reader reader)
Reads a JSON string and returns an instance of this class.
Definition: DGraph.java:7370
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:1364
List< Vertex > getSymVerticesForVertex(Vertex v)
Definition: DGraph.java:345
static final String SYM_ID
Key used to uniquely identify vertices and attachment points for symmetry detection.
Definition: DGraph.java:180
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:2002
static Set< Vertex > exploreGraph(Vertex seed, Set< Vertex > limits)
Navigates vertexes starting from a given seed vertex, and stopping the exploration at any of the give...
Definition: DGraph.java:5090
void changeSignOfVertexID()
Change all vertex IDs to the corresponding negative value.
Definition: DGraph.java:5952
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:4499
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:3089
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:3742
void reassignSymmetricLabels()
Marks the vertices of this graph with a string that is consistent for all vertices that belong to sym...
Definition: DGraph.java:1888
List< Edge > findEdges(EdgeQuery edgeQuery, Logger logger)
Search this graph for edges that match the criteria defined in a query.
Definition: DGraph.java:6859
void removeVertexAndSymmetricOnes(Vertex v, boolean symmetry)
Deletes a vertex and, optionally, its symmetric couinterparts.
Definition: DGraph.java:1820
List< Edge > gEdges
The edges belonging to this graph.
Definition: DGraph.java:113
void replaceUnusedRCVsWithCapps(FragmentSpace fragSpace)
Removes unused ring-closing vertices.
Definition: DGraph.java:1846
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:6443
void setEdgeList(ArrayList< Edge > edges)
Definition: DGraph.java:917
boolean sameAs(DGraph other, StringBuilder reason)
Compare this and another graph ignoring the vertex IDs.
Definition: DGraph.java:4315
int getLevel(Vertex v)
Calculates the level of a vertex in this graph.
Definition: DGraph.java:6026
Vertex getParent(Vertex v)
Definition: DGraph.java:3818
void removeSymmetryRedundantIds(ArrayList< Long > list)
Remove all but one of the symmetry-related partners in a given list of vertex IDs.
Definition: DGraph.java:6966
static void exploreGraph(Vertex seed, Set< Vertex > limits, Set< Vertex > visited)
Depth-first exploration of graphs.
Definition: DGraph.java:5057
void removeSymmetrySet(SymmetricVertexes ss)
Tries to determine the set of symmetric vertices in this graph based on finding compatible Vertexes t...
Definition: DGraph.java:850
void storeCurrentVertexIDs()
Copies the current vertexID of each vertex into a property of the vertex itself.
Definition: DGraph.java:7652
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:6580
static void fixEdgeDirections(DGraph graph)
Flips edges in the graph so that the scaffold is the only source vertex.
Definition: DGraph.java:5433
DGraph getOutermostGraphOwner()
Definition: DGraph.java:7613
List< List< AttachmentPoint > > findAPs(List< AttachmentPointQuery > apQueries, Logger logger)
Search the graph for AttachmentPoints that match the criteria defined in a list of queries.
Definition: DGraph.java:6742
void removeCappingGroupsOn(Vertex vertex)
Remove capping groups on the given vertex of this graph.
Definition: DGraph.java:4734
List< Long > findVerticesIds(VertexQuery query, Logger logger)
Search a graph for vertices that match the criteria defined in a query vertex.
Definition: DGraph.java:6788
static DGraph fromJson(String json)
Reads a JSON string and returns an instance of this class.
Definition: DGraph.java:7355
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:1040
void addRing(Vertex vI, Vertex vJ)
Adds a chord between the given vertices, thus adding a ring in this graph.
Definition: DGraph.java:1321
List< Ring > getRings()
Definition: DGraph.java:1027
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:5258
List< Vertex > findVertices(VertexQuery vrtxQuery, boolean purgeSym, Logger logger)
Filters a list of vertices according to a query.
Definition: DGraph.java:6825
boolean isVertexIDInRing(int vid)
Definition: DGraph.java:1198
void addSymmetricSetOfVertices(SymmetricVertexes symSet)
Adds a symmetric set of vertices to this graph.
Definition: DGraph.java:891
SymmetricVertexes getSymSetForVertex(Vertex v)
Returns the set of vertexes symmetric to the given one.
Definition: DGraph.java:863
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:3799
void addCappingGroups(FragmentSpace fragSpace)
Add a capping groups on free unused attachment points.
Definition: DGraph.java:4819
DGraph(List< Vertex > gVertices, List< Edge > gEdges, List< Ring > gRings)
Definition: DGraph.java:198
List< Edge > getEdgeList()
Definition: DGraph.java:1020
DGraph(List< Vertex > gVertices, List< Edge > gEdges, List< Ring > gRings, List< SymmetricVertexes > symSets)
Definition: DGraph.java:209
void removeCappingGroups()
Remove all capping groups on this graph.
Definition: DGraph.java:4806
void cleanup()
Wipes the data in this graph.
Definition: DGraph.java:4018
boolean hasRings()
Check for rings in this graph.
Definition: DGraph.java:1148
List< AttachmentPoint > findAPs(AttachmentPointQuery apQuery, Logger logger)
Search the graph for AttachmentPoints that match the criteria defined in a query.
Definition: DGraph.java:6762
List< Vertex > getVertexAnyLevel()
Returns the list of vertexes at any level in the graph.
Definition: DGraph.java:953
void removeCappingGroupsFromChilds(List< Vertex > lstVerts)
Definition: DGraph.java:4792
Object[] checkConsistency(RunTimeParameters settings, boolean permissive)
Peeks into this graph to derive a preliminary chemical representation with SMILES and InChIKey.
Definition: DGraph.java:6084
List< Vertex > getMutableSites(List< MutationType > ignoredTypes)
A list of mutation sites from within this graph.
Definition: DGraph.java:7286
DefaultUndirectedGraph< Node, NodeConnection > jGraphKernel
JGraph representation used to detect DENOPTIM-isostructural graphs.
Definition: DGraph.java:164
ArrayList< Edge > getEdgesWithChild(int vid)
Definition: DGraph.java:3964
boolean isVertexInRing(Vertex v)
Definition: DGraph.java:1214
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:7818
boolean isConnected()
Check if this graph is connected, i.e., there is at least one path between any two vertices.
Definition: DGraph.java:1160
Candidate getCandidateOwner()
Returns the reference of the candidate item that is defined by this graph.
Definition: DGraph.java:259
List< SymmetricVertexes > symVertices
Definition: DGraph.java:134
void addRing(Ring ring)
Definition: DGraph.java:1304
ArrayList< Ring > getRingsInvolvingVertex(Vertex[] vs)
Returns the list of rings that include the given list of vertices in their fundamental cycle.
Definition: DGraph.java:1103
Map< Long, Long > renumberVerticesGetMap()
Reassign vertex IDs to a graph.
Definition: DGraph.java:5996
static void replaceChordWithEdge(Ring chord)
We assume that the two vertexes belong to the same graph.
Definition: DGraph.java:2868
boolean hasSymmetryInvolvingVertex(Vertex v)
Definition: DGraph.java:303
static void fixEdgeDirections(Vertex v, Set< Long > visited)
Recursive utility method for fixEdgeDirections(graph).
Definition: DGraph.java:5445
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:2932
ArrayList< Vertex > getUsedRCVertices()
Search for used ring closing vertices: vertices that contain only a RingClosingAttractor and are part...
Definition: DGraph.java:1281
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:3009
Edge getEdgeWithParent(long l)
Looks for an edge that points to a vertex with the given vertex id.
Definition: DGraph.java:3923
void getChildrenTree(Vertex vertex, List< Vertex > children, AtomicInteger branchIdGenerator, List< Integer > prevBranchId)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:3511
void removeEdge(Edge edge)
Removes an edge and update the free valences of the attachment points that were originally involved i...
Definition: DGraph.java:3269
void getChildTreeLimited(Vertex vertex, List< Vertex > children, boolean stopBeforeRCVs)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:3678
Template templateJacket
Reference to the Template embedding this graph.
Definition: DGraph.java:152
boolean removeBranchStartingAt(Vertex v, boolean symmetry)
Deletes the branch, i.e., the specified vertex and its children.
Definition: DGraph.java:5488
int getHeavyAtomsCount()
Calculate the number of atoms from the graph representation.
Definition: DGraph.java:4603
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:5239
boolean removeOrphanBranchStartingAt(Vertex v)
Deletes the branch, i.e., the specified vertex and its children.
Definition: DGraph.java:5547
List< Vertex > getMutableSites()
A list of mutation sites from within this graph.
Definition: DGraph.java:7262
String localMsg
A free-format string used to record simple properties in the graph.
Definition: DGraph.java:142
void addEdge(Edge edge)
Adds the edge to the list of edges belonging to this graph.
Definition: DGraph.java:1295
List< Template > getEmbeddingPath()
Find the path that one has to traverse to reach this graph from any template-embedding structure.
Definition: DGraph.java:7635
void addCappingGroups(List< Vertex > vertexAddedToThis, FragmentSpace fragSpace)
Add a capping group on the given vertices, if needed.
Definition: DGraph.java:4842
Template getTemplateJacket()
Definition: DGraph.java:7602
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:5578
List< Integer > getBranchIdOfVertexAtPosition(int i)
Returns the branch identifier.
Definition: DGraph.java:3591
void setLocalMsg(String msg)
Definition: DGraph.java:281
List< Vertex > getSelectedMutableSites(MutationType requestedType)
A list of mutation sites from within this graph.
Definition: DGraph.java:7309
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:6705
boolean isIsostructuralTo(DGraph other)
Checks if this graph is "DENOPTIM-isostructural" to the other one given.
Definition: DGraph.java:4230
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:5004
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:1180
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:489
boolean detectSymVertexSets()
Detects and groups symmetric sets of Vertexes in the graph based on unique identification and path en...
Definition: DGraph.java:370
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:294
long getSrcVertex()
Definition: Edge.java:122
AttachmentPoint getSrcAP()
Definition: Edge.java:94
long getTrgVertex()
Definition: Edge.java:145
BondType getBondType()
Definition: Edge.java:166
A query for edges: a list of properties that target edges should possess in order to match this query...
Definition: EdgeQuery.java:28
boolean matches(Edge e)
Tests whether the given edge satisfies this query.
Definition: EdgeQuery.java:97
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 Vertex 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
BondType getBondType()
Definition: Ring.java:146
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:61
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:1144
abstract Vertex clone()
Returns a deep-copy of this vertex.
void setMutationTypes(List< MutationType > lst)
Definition: Vertex.java:881
int getBuildingBlockId()
Returns the index of the building block that should correspond to the position of the building block ...
Definition: Vertex.java:304
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:1059
void setVertexId(long vertexId2)
Definition: Vertex.java:281
int getFreeAPCountThroughout()
Counts the number of attachment points that are availability throughout the graph level,...
Definition: Vertex.java:430
int getIndexOfAP(AttachmentPoint ap)
Returns the position of the given AP in the list of APs of this vertex.
Definition: Vertex.java:1036
String toString()
Produces a human readable, short string to represent the vertex by its vertex ID, building block ID (...
Definition: Vertex.java:631
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:1083
Vertex.BBType getBuildingBlockType()
Definition: Vertex.java:318
DGraph getGraphOwner()
Returns the graph this vertex belongs to or null.
Definition: Vertex.java:851
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:1172
abstract List< AttachmentPoint > getAttachmentPoints()
Object getProperty(Object property)
Definition: Vertex.java:1223
boolean sameAs(Vertex other)
Compares this and another vertex ignoring vertex IDs.
Definition: Vertex.java:669
int getCappedAPCountThroughout()
Counts the number of attachment points that are used by BBType#CAP vertex.
Definition: Vertex.java:513
void setProperty(Object key, Object property)
Definition: Vertex.java:1235
ArrayList< AttachmentPoint > getFreeAPThroughout()
Gets attachment points that are availability throughout the graph level, i.e., checks also across the...
Definition: Vertex.java:402
AttachmentPoint getAP(int i)
Get attachment point i on this vertex.
Definition: Vertex.java:1007
static Vertex newVertexFromLibrary(int bbId, Vertex.BBType bbt, FragmentSpace fragSpace)
Builds a new molecular fragment kind of vertex.
Definition: Vertex.java:214
Edge getEdgeWith(Vertex other)
Finds the edge between this and the other vertex, if it exists.
Definition: Vertex.java:1514
Query for searching vertices.
boolean matches(Vertex v)
Tests whether the given vertex satisfies all non-null criteria in this query.
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 ArrayList< DGraph > readDENOPTIMGraphsFromFile(File inFile)
Reads a list of DGraphs from file.
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:40
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 to generate random numbers and random decisions.
Definition: Randomizer.java:35
public< T > T randomlyChooseOne(Collection< T > c)
Chooses one member among the given collection.
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 (a.k.a.
Identifier for the format of string representations of a graph.
Definition: DGraph.java:169
Possible chemical bond types an edge can represent.
Definition: Edge.java:305
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:86
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...