$darkmode
DENOPTIM
GraphOperations.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.ga;
21
22import java.io.File;
23import java.util.ArrayList;
24import java.util.LinkedHashMap;
25import java.util.List;
26import java.util.Map;
27import java.util.Map.Entry;
28import java.util.TreeMap;
29import java.util.logging.Level;
30import java.util.stream.Collectors;
31
32import org.openscience.cdk.interfaces.IAtomContainer;
33import org.paukov.combinatorics3.Generator;
34
35import denoptim.constants.DENOPTIMConstants;
36import denoptim.exception.DENOPTIMException;
37import denoptim.fragmenter.BridgeHeadFindingRule;
38import denoptim.fragspace.APMapFinder;
39import denoptim.fragspace.FragmentSpace;
40import denoptim.fragspace.FragmentSpaceParameters;
41import denoptim.fragspace.GraphLinkFinder;
42import denoptim.fragspace.IdFragmentAndAP;
43import denoptim.graph.APClass;
44import denoptim.graph.APMapping;
45import denoptim.graph.AttachmentPoint;
46import denoptim.graph.DGraph;
47import denoptim.graph.Edge;
48import denoptim.graph.RelatedAPPair;
49import denoptim.graph.Ring;
50import denoptim.graph.SymmetricAPs;
51import denoptim.graph.SymmetricVertexes;
52import denoptim.graph.Template;
53import denoptim.graph.Template.ContractLevel;
54import denoptim.graph.Vertex;
55import denoptim.graph.Vertex.BBType;
56import denoptim.graph.rings.ChainLink;
57import denoptim.graph.rings.ClosableChain;
58import denoptim.graph.rings.PathSubGraph;
59import denoptim.graph.rings.RandomCombOfRingsIterator;
60import denoptim.graph.rings.RingClosingAttractor;
61import denoptim.graph.rings.RingClosureParameters;
62import denoptim.io.DenoptimIO;
63import denoptim.logging.CounterID;
64import denoptim.logging.Monitor;
65import denoptim.molecularmodeling.ThreeDimTreeBuilder;
66import denoptim.programs.RunTimeParameters.ParametersType;
67import denoptim.programs.denovo.GAParameters;
68import denoptim.utils.CrossoverType;
69import denoptim.utils.GraphUtils;
70import denoptim.utils.MutationType;
71import denoptim.utils.Randomizer;
72
77public class GraphOperations
78{
79
80//------------------------------------------------------------------------------
81
95 public static List<XoverSite> locateCompatibleXOverPoints(
96 DGraph graphA, DGraph graphB, FragmentSpace fragSpace,
97 int maxSizeXoverSubGraph)
99 {
100 // First, we identify all the edges that allow crossover, and collect
101 // their target vertexes (i.e., all the potential seed vertexes of
102 // subgraphs that crossover could swap.
103 List<Vertex[]> compatibleVrtxPairs = new ArrayList<Vertex[]>();
104 for (Edge eA : graphA.getEdgeList())
105 {
106 Vertex vA = eA.getTrgAP().getOwner();
107 // We don't do genetic operations on capping vertexes
108 if (vA.getBuildingBlockType() == BBType.CAP)
109 continue;
110
111 for (Edge eB : graphB.getEdgeList())
112 {
113 Vertex vB = eB.getTrgAP().getOwner();
114 // We don't do genetic operations on capping vertexes
115 if (vB.getBuildingBlockType() == BBType.CAP)
116 continue;
117
118 //Check condition for considering this combination
119 if (isCrossoverPossible(eA, eB, fragSpace))
120 {
121 Vertex[] pair = new Vertex[]{vA,vB};
122 compatibleVrtxPairs.add(pair);
123 }
124 }
125 }
126
127 // The crossover sites are the combination of the above compatible
128 // vertexes that define subgraphs respecting the requirements for
129 // being swapped between the two graphs.
130 ArrayList<XoverSite> sites = new ArrayList<XoverSite>();
131 for (Vertex[] pair : compatibleVrtxPairs)
132 {
133 Vertex vA = pair[0];
134 Vertex vB = pair[1];
135 DGraph gA = vA.getGraphOwner();
136 DGraph gB = vB.getGraphOwner();
137
138 // Here we also identify the branch identity of each descendant
139 List<Vertex> descendantsA = new ArrayList<Vertex>();
140 gA.getChildrenTree(vA, descendantsA, true);
141 List<Vertex> descendantsB = new ArrayList<Vertex>();
142 gB.getChildrenTree(vB, descendantsB, true);
143
144 // Branches that are isomorphic are not considered for crossover
145 DGraph test1 = gA.clone();
146 DGraph test2 = gB.clone();
147 try
148 {
149 DGraph subGraph1 = test1.extractSubgraph(gA.indexOf(vA));
150 DGraph subGraph2 = test2.extractSubgraph(gB.indexOf(vB));
151 if (maxSizeXoverSubGraph >= Math.max(subGraph1.getVertexCount(),
152 subGraph2.getVertexCount()))
153 {
154 if (!subGraph1.isIsomorphicTo(subGraph2))
155 {
156 List<Vertex> branchOnVA = new ArrayList<Vertex>();
157 branchOnVA.add(vA);
158 branchOnVA.addAll(descendantsA);
159 List<Vertex> branchOnVB = new ArrayList<Vertex>();
160 branchOnVB.add(vB);
161 branchOnVB.addAll(descendantsB);
162
163 checkAndAddXoverSites(fragSpace, branchOnVA, branchOnVB,
164 CrossoverType.BRANCH, sites);
165 }
166 }
167 } catch (DENOPTIMException e)
168 {
169 //We should never end up here.
170 e.printStackTrace();
171 }
172
173 // To limit the number of combination, we first get rid of end-point
174 // candidates that cannot be used
175 List<Vertex[]> usablePairs = new ArrayList<Vertex[]>();
176
177 // To identify subgraphs smaller than the full branch we need to find
178 // where such subgraphs end, i.e., the vertexes at the end of
179 // such subgraphs (included in them), a.k.a. the subgraph ends.
180 // Since these subgraph ends will need to allow connection with the
181 // rest of the original graph, they are related to the
182 // already-identified crossover-compatible
183 // sites, i.e., they are the parents of the vertexes collected in
184 // compatibleVrtxPairs. Yet, we can combine them
185 // * in any number from 1 to all of them,
186 // * in any combination of the chosen number of them.
187 // Also, note that the ends need not to cover all the branches. So,
188 // some combinations will have to cut some branches short while
189 // taking some other branches completely till their last leaf.
190 for (Vertex[] otherPair : compatibleVrtxPairs)
191 {
192 // NB: the xover compatible sites are the child vertexes of the
193 // subgraph ends. So we need to get the parent
194 Vertex nextToEndOnA = otherPair[0];
195 Vertex nextToEndOnB = otherPair[1];
196 Vertex endOnA = nextToEndOnA.getParent();
197 Vertex endOnB = nextToEndOnB.getParent();
198 if (endOnA==null || endOnB==null)
199 continue;
200
201 // Exclude vertexes that are not downstream to the seed of the subgraph
202 if (!descendantsA.contains(endOnA) && endOnA!=vA
203 || !descendantsB.contains(endOnB) && endOnB!=vB)
204 continue;
205
206 // If any partner is a fixed-structure templates...
207 if ((gA.getTemplateJacket()!=null
210 || (gB.getTemplateJacket()!=null
213 {
214 //...the two paths must have same length. This would be
215 // checked anyway later when checking for isostructural
216 // subgraphs, but here it helps reducing the size of the
217 // combinatorial problem.
218 PathSubGraph pathA = new PathSubGraph(vA, endOnA, gA);
219 PathSubGraph pathB = new PathSubGraph(vB, endOnB, gB);
220 if (pathA.getPathLength()!=pathB.getPathLength())
221 continue;
222 }
223 Vertex[] pairOfEnds = new Vertex[]{endOnA,endOnB};
224 if (!usablePairs.contains(pairOfEnds))
225 usablePairs.add(pairOfEnds);
226 }
227
228 // We classify the pairs by branch ownership
229 TreeMap<String,List<Vertex[]>> sitesByBranchIdA =
230 new TreeMap<String,List<Vertex[]>>();
231 TreeMap<String,List<Vertex[]>> sitesByBranchIdB =
232 new TreeMap<String,List<Vertex[]>>();
233 for (Vertex[] pp : usablePairs)
234 {
235 String branchIdA = gA.getBranchIdOfVertexAsStr(pp[0]);
236 String branchIdB = gB.getBranchIdOfVertexAsStr(pp[1]);
237 if (sitesByBranchIdA.containsKey(branchIdA))
238 {
239 sitesByBranchIdA.get(branchIdA).add(pp);
240 } else {
241 ArrayList<Vertex[]> lst = new ArrayList<Vertex[]>();
242 lst.add(pp);
243 sitesByBranchIdA.put(branchIdA, lst);
244 }
245 if (sitesByBranchIdB.containsKey(branchIdB))
246 {
247 sitesByBranchIdB.get(branchIdB).add(pp);
248 } else {
249 ArrayList<Vertex[]> lst = new ArrayList<Vertex[]>();
250 lst.add(pp);
251 sitesByBranchIdB.put(branchIdB, lst);
252 }
253 }
254
255 // The side with the smallest set of branches determines the max
256 // number of pairs that can define a subgraph.
257 TreeMap<String,List<Vertex[]>> fewestBranchesSide = null;
258 if (sitesByBranchIdA.size() <= sitesByBranchIdB.size())
259 fewestBranchesSide = sitesByBranchIdA;
260 else
261 fewestBranchesSide = sitesByBranchIdB;
262
263 // Add the empty, i.e., the branch with empty is not cut short.
264 for (List<Vertex[]> val : fewestBranchesSide.values())
265 val.add(new Vertex[]{null,null});
266
267 // Generate the combinations: Cartesian product of multiple lists.
268 // NB: this combinatorial generator retains the
269 // sequence of generated subsets (important for reproducibility)
270 List<List<Vertex[]>> preCombsOfEnds = Generator.cartesianProduct(
271 fewestBranchesSide.values())
272 .stream()
273 .limit(100000) //Prevent explosion!!!
274 .collect(Collectors.<List<Vertex[]>>toList());
275
276 // Remove the 'null,null' place holders that indicate the use of no
277 // end-point on a specific branch.
278 List<List<Vertex[]>> combsOfEnds = new ArrayList<List<Vertex[]>>();
279 for (List<Vertex[]> comb : preCombsOfEnds)
280 {
281 List<Vertex[]> nullPurgedComb = new ArrayList<Vertex[]>();
282 for (Vertex[] inPair : comb)
283 {
284 if (inPair[0]!=null && inPair[1]!=null)
285 nullPurgedComb.add(inPair);
286 }
287 // the case where all entries are null corresponds to use no
288 // end point on any branch, which is already considered above.
289 if (nullPurgedComb.size()>0)
290 combsOfEnds.add(nullPurgedComb);
291 }
292
293 // This would be a strategy to parallelize. However, this type of
294 // parallelization is not compatible with ensuring reproducibility.
295 // Perhaps, we could guarantee reproducibility by acting on the
296 // collector of sites as to ensure the list is sorted
297 // at the end of the generation of all possibilities.
298 /*
299 combsOfEnds
300 .parallelStream()
301 .limit(50) // Prevent explosion!
302 .forEach(c -> processCombinationOfEndPoints(pair, c, sites,
303 fragSpace));
304 */
305
306 combsOfEnds.stream()
307 .limit(50) // Prevent explosion!
308 .forEach(c -> processCombinationOfEndPoints(pair, c, sites,
309 fragSpace));
310 }
311
312 // NB: we consider only templates that are at the same level of embedding
313 for (Vertex vA : graphA.getVertexList())
314 {
315 if (!(vA instanceof Template))
316 continue;
317 Template tA = (Template) vA;
318
320 continue;
321
322 for (Vertex vB : graphB.getVertexList())
323 {
324 if (!(vB instanceof Template))
325 continue;
326 Template tB = (Template) vB;
327
329 continue;
330
332 tA.getInnerGraph(), tB.getInnerGraph(), fragSpace,
333 maxSizeXoverSubGraph))
334 {
335 if (!sites.contains(xos))
336 sites.add(xos);
337 }
338 }
339 }
340 return sites;
341 }
342
343//------------------------------------------------------------------------------
344
357 private static void processCombinationOfEndPoints(Vertex[] pair,
358 List<Vertex[]> cominationOfEnds,
359 List<XoverSite> collector, FragmentSpace fragSpace)
360 {
361 // Empty set corresponds to using the entire branch and subgraph and
362 // has been already dealt with at this point
363 if (cominationOfEnds.size()==0)
364 return;
365
366 // This would be a strategy to parallelize. However, this type of
367 // parallelization is not compatible with ensuring reproducibility.
368 // Perhaps, we could guarantee reproducibility by acting on the
369 // collector as to ensure the list of collected results is sorted
370 // at the end of the generation of all possibilities
371 /*
372 List<List<Vertex[]>> permutsOfEnds = new ArrayList<List<Vertex[]>>();
373 Generator.subset(cominationOfEnds)
374 .simple()
375 .stream()
376 .limit(100) // Prevent explosion!
377 .forEach(c -> permutsOfEnds.add(c));
378 permutsOfEnds
379 .parallelStream()
380 .forEach(c -> processPermutationOfEndPoints(pair, c, collector,
381 fragSpace));
382 */
383
384 Generator.permutation(cominationOfEnds)
385 .simple()
386 .stream()
387 .limit(100) // Prevent explosion!
388 .forEach(c -> processPermutationOfEndPoints(pair, c, collector,
389 fragSpace));
390 }
391
392//------------------------------------------------------------------------------
393
406 private static void processPermutationOfEndPoints(Vertex[] pair,
407 List<Vertex[]> chosenSequenceOfEndpoints,
408 List<XoverSite> collector, FragmentSpace fragSpace)
409 {
410 Vertex vA = pair[0];
411 Vertex vB = pair[1];
412 DGraph gA = vA.getGraphOwner();
413 DGraph gB = vB.getGraphOwner();
414
415 // Exclude overlapping combinations
416 boolean exclude = false;
417 for (Vertex[] pairA : chosenSequenceOfEndpoints)
418 {
419 for (Vertex[] pairB : chosenSequenceOfEndpoints)
420 {
421 if (pairA==pairB)
422 continue;
423
424 if (pairA[0]==pairB[0] || pairA[1]==pairB[1])
425 {
426 exclude = true;
427 break;
428 }
429 }
430 if (exclude)
431 break;
432 }
433 if (exclude)
434 return;
435
436 List<Vertex> subGraphEndInA = new ArrayList<Vertex>();
437 List<Vertex> subGraphEndInB = new ArrayList<Vertex>();
438 List<Vertex> alreadyIncludedFromA = new ArrayList<Vertex>();
439 List<Vertex> alreadyIncludedFromB = new ArrayList<Vertex>();
440 for (Vertex[] otherPair : chosenSequenceOfEndpoints)
441 {
442 Vertex endOnA = otherPair[0];
443 Vertex endOnB = otherPair[1];
444
445 // Ignore vertexes that are already part of the subgraph
446 if (alreadyIncludedFromA.contains(endOnA)
447 || alreadyIncludedFromB.contains(endOnB))
448 continue;
449
450 PathSubGraph pathA = new PathSubGraph(vA, endOnA, gA);
451 PathSubGraph pathB = new PathSubGraph(vB, endOnB, gB);
452 subGraphEndInA.add(endOnA);
453 subGraphEndInB.add(endOnB);
454 alreadyIncludedFromA.addAll(pathA.getVertecesPath());
455 alreadyIncludedFromB.addAll(pathB.getVertecesPath());
456 }
457 ArrayList<Vertex> subGraphA = new ArrayList<Vertex>();
458 subGraphA.add(vA);
459 if (!subGraphEndInA.contains(vA))
460 gA.getChildTreeLimited(vA, subGraphA, subGraphEndInA, true);
461
462 ArrayList<Vertex> subGraphB = new ArrayList<Vertex>();
463 subGraphB.add(vB);
464 if (!subGraphEndInB.contains(vB))
465 gB.getChildTreeLimited(vB, subGraphB, subGraphEndInB, true);
466
467 // The two subgraphs must not be isomorfic to prevent unproductive crossover
468 if (subGraphA.size()>1 && subGraphB.size()>1)
469 {
470 DGraph subGraphCloneA = gA.extractSubgraph(subGraphA);
471 DGraph subGraphCloneB = gB.extractSubgraph(subGraphB);
472 if (subGraphCloneA.isIsomorphicTo(subGraphCloneB))
473 return;
474 } else {
475 if (subGraphA.get(0).sameAs(subGraphB.get(0), new StringBuilder()))
476 return;
477 }
478
479 checkAndAddXoverSites(fragSpace, subGraphA, subGraphB,
480 CrossoverType.SUBGRAPH, collector);
481 }
482
483//------------------------------------------------------------------------------
484
494 private static void checkAndAddXoverSites(FragmentSpace fragSpace,
495 List<Vertex> subGraphA,
496 List<Vertex> subGraphB, CrossoverType xoverType,
497 List<XoverSite> collector)
498 {
499 DGraph gOwnerA = subGraphA.get(0).getGraphOwner();
500 DGraph gOwnerB = subGraphB.get(0).getGraphOwner();
501
502 // What APs need to find a corresponding AP in the other
503 // subgraph in order to allow swapping?
504 List<AttachmentPoint> needyAPsA = gOwnerA.getInterfaceAPs(
505 subGraphA);
506 List<AttachmentPoint> allAPsA = gOwnerA.getSubgraphAPs(
507 subGraphA);
508 List<AttachmentPoint> needyAPsB = gOwnerB.getInterfaceAPs(
509 subGraphB);
510 List<AttachmentPoint> allAPsB = gOwnerB.getSubgraphAPs(
511 subGraphB);
512 if (allAPsA.size() < needyAPsB.size()
513 || allAPsB.size() < needyAPsA.size())
514 {
515 // Impossible to satisfy needy APs. Crossover site is not usable.
516 return;
517 }
518
519 // Shortcut: since the compatibility of one AP that is needed to do
520 // branch swapping is guaranteed by the identification of the seeds of
521 // swappable subgraphs, we can avoid searching for a valid A mapping
522 // when the graphs are not embedded. This because any AP that is not
523 // the one connecting the subgraph to the parent can be left free or
524 // removed without side effects on templates that embed the graph
525 // because there is no such template.
526 Template jacketTmplA = gOwnerA.getTemplateJacket();
527 Template jacketTmplB = gOwnerB.getTemplateJacket();
528 if (xoverType == CrossoverType.BRANCH
529 && jacketTmplA==null
530 && jacketTmplB==null)
531 {
532 XoverSite xos = new XoverSite(subGraphA, needyAPsA, subGraphB,
533 needyAPsB, xoverType);
534 if (!collector.contains(xos))
535 collector.add(xos);
536 return;
537 }
538
539 if ((jacketTmplA!=null && jacketTmplA.getContractLevel()
541 || (jacketTmplB!=null && jacketTmplB.getContractLevel()
543 {
544 // Avoid to alter cyclicity of inner graphs
545 for (Vertex v : subGraphA)
546 if (v.isRCV() && !gOwnerA.getRingsInvolvingVertex(v).isEmpty())
547 return;
548 for (Vertex v : subGraphB)
549 if (v.isRCV() && !gOwnerB.getRingsInvolvingVertex(v).isEmpty())
550 return;
551
552 // Avoid to change the structure of inner graphs
553 DGraph subGraphCloneA = gOwnerA.extractSubgraph(subGraphA);
554 DGraph subGraphCloneB = gOwnerB.extractSubgraph(subGraphB);
555 if (!subGraphCloneA.isIsostructuralTo(subGraphCloneB))
556 return;
557 }
558
559 // Retain connection to parent to keep directionality of spanning tree!
560 // To this end, identify the seed of the subgraphs...
561 Vertex seedOnA = gOwnerA.getDeepestAmongThese(subGraphA);
562 Vertex seedOnB = gOwnerB.getDeepestAmongThese(subGraphB);
563 //...and ensure we use the same APs to link to the parent graph.
564 APMapping fixedRootAPs = new APMapping();
565 fixedRootAPs.put(seedOnA.getEdgeToParent().getTrgAP(),
566 seedOnB.getEdgeToParent().getTrgAP());
567
568 APMapFinder apmf = new APMapFinder(fragSpace,
569 allAPsA, needyAPsA, allAPsB, needyAPsB,
570 fixedRootAPs,
571 false, // false: we stop at the first good mapping
572 true, // true: only complete mapping
573 false); // false: free APs are not compatible by default
574 if (apmf.foundMapping())
575 {
576 XoverSite xos = new XoverSite(subGraphA, needyAPsA,
577 subGraphB, needyAPsB, xoverType);
578 if (!collector.contains(xos))
579 collector.add(xos);
580 }
581 }
582
583//------------------------------------------------------------------------------
584
596 private static boolean isCrossoverPossible(Edge eA, Edge eB,
597 FragmentSpace fragSpace)
598 {
599 APClass apClassSrcA = eA.getSrcAPClass();
600 APClass apClassTrgA = eA.getTrgAPClass();
601 APClass apClassSrcB = eB.getSrcAPClass();
602 APClass apClassTrgB = eB.getTrgAPClass();
603
604 if (apClassSrcA.isCPMapCompatibleWith(apClassTrgB, fragSpace))
605 {
606 if (apClassSrcB.isCPMapCompatibleWith(apClassTrgA, fragSpace))
607 {
608 return true;
609 }
610 }
611 return false;
612 }
613
614//------------------------------------------------------------------------------
615
627 protected static boolean deleteLink(Vertex vertex,
628 int chosenVrtxIdx, Monitor mnt, FragmentSpace fragSpace)
629 throws DENOPTIMException
630 {
631 DGraph graph = vertex.getGraphOwner();
632 boolean done = graph.removeVertexAndWeld(vertex, fragSpace);
633 if (!done)
634 {
636 }
637 return done;
638 }
639
640//------------------------------------------------------------------------------
641
658 protected static boolean substituteLink(Vertex vertex,
659 int chosenVrtxIdx, Monitor mnt, FragmentSpace fragSpace)
660 throws DENOPTIMException
661 {
662 //TODO: for reproducibility, the AP mapping should become an optional
663 // parameter: if given we try to use it, if not given, GraphLinkFinder
664 // will try to find a suitable mapping.
665
666 GraphLinkFinder glf = null;
667 if (chosenVrtxIdx<0)
668 {
669 glf = new GraphLinkFinder(fragSpace, vertex);
670 } else {
671 glf = new GraphLinkFinder(fragSpace, vertex, chosenVrtxIdx);
672 }
673 if (!glf.foundAlternativeLink())
674 {
676 return false;
677 }
678
679 DGraph graph = vertex.getGraphOwner();
680 boolean done = graph.replaceVertex(vertex,
684 fragSpace);
685 if (!done)
686 {
687 mnt.increase(
689 }
690 return done;
691 }
692
693//------------------------------------------------------------------------------
694
710 public static boolean extendLink(Vertex vertex,
711 int chosenAPId, Monitor mnt, FragmentSpace fragSpace)
712 throws DENOPTIMException
713 {
714 return extendLink(vertex, chosenAPId, -1 , mnt, fragSpace);
715 }
716
717//------------------------------------------------------------------------------
718
736 public static boolean extendLink(Vertex vertex, int chosenAPId,
737 int chosenNewVrtxId, Monitor mnt, FragmentSpace fragSpace)
738 throws DENOPTIMException
739 {
740 AttachmentPoint ap = vertex.getAP(chosenAPId);
741 if (ap == null)
742 {
743 throw new DENOPTIMException("No AP "+chosenAPId+" in vertex "
744 +vertex+".");
745 }
747
748 if (e == null)
749 {
750 throw new DENOPTIMException("AP "+chosenAPId+" in vertex "
751 +vertex+" has no edge user.");
752 }
753 if (e.getSrcAP().getOwner() != vertex)
754 {
755 throw new DENOPTIMException("Request to extend a link from a child "
756 + "vertex (AP "+chosenAPId+" of vertex "+vertex+").");
757 }
758 return extendLink(e, chosenNewVrtxId, mnt, fragSpace);
759 }
760
761//------------------------------------------------------------------------------
762
775 public static boolean extendLink(Edge edge, int chosenBBIdx,
776 Monitor mnt, FragmentSpace fragSpace) throws DENOPTIMException
777 {
778 //TODO: for reproducibility, the AP mapping should become an optional
779 // parameter: if given we try to use it, if not given we GraphLinkFinder
780 // will try to find a suitable mapping.
781
782 GraphLinkFinder glf = null;
783 if (chosenBBIdx < 0)
784 {
785 glf = new GraphLinkFinder(fragSpace, edge);
786 } else {
787 glf = new GraphLinkFinder(fragSpace, edge,chosenBBIdx);
788 }
789 if (!glf.foundAlternativeLink())
790 {
792 return false;
793 }
794
795 // Need to convert the mapping to make it independent from the instance
796 // or the new link.
797 LinkedHashMap<AttachmentPoint,Integer> apMap =
798 new LinkedHashMap<AttachmentPoint,Integer>();
799 for (Entry<AttachmentPoint, AttachmentPoint> e :
800 glf.getChosenAPMapping().entrySet())
801 {
802 apMap.put(e.getKey(), e.getValue().getIndexInOwner());
803 }
804
805 DGraph graph = edge.getSrcAP().getOwner().getGraphOwner();
806 boolean done = graph.insertVertex(edge,
809 apMap, fragSpace);
810 if (!done)
811 {
812 mnt.increase(
814 }
815 return done;
816 }
817
818//------------------------------------------------------------------------------
819
841 protected static boolean rebuildBranch(Vertex vertex,
842 boolean force, int chosenVrtxIdx, int chosenApId,
843 GAParameters settings) throws DENOPTIMException
844 {
845 DGraph g = vertex.getGraphOwner();
846
847 // first get the edge with the parent
848 Edge e = vertex.getEdgeToParent();
849 if (e == null)
850 {
851 String msg = "Program Bug in substituteFragment: Unable to locate "
852 + "parent edge for vertex "+vertex+" in graph "+g;
853 settings.getLogger().log(Level.SEVERE, msg);
854 throw new DENOPTIMException(msg);
855 }
856
857 // vertex id of the parent
858 long pvid = e.getSrcVertex();
859 Vertex parentVrt = g.getVertexWithId(pvid);
860
861 // Need to remember symmetry because we are deleting the symm. vertices
862 boolean symmetry = g.hasSymmetryInvolvingVertex(vertex);
863
864 // delete the vertex and its children and all its symmetric partners
865 deleteFragment(vertex);
866
867 // extend the graph at this vertex but without recursion
868 return extendGraph(parentVrt,false,symmetry,force,chosenVrtxIdx,
869 chosenApId, settings);
870 }
871
872//------------------------------------------------------------------------------
873
882 protected static boolean deleteFragment(Vertex vertex)
883 throws DENOPTIMException
884 {
885 long vid = vertex.getVertexId();
886 DGraph molGraph = vertex.getGraphOwner();
887
888 if (molGraph.hasSymmetryInvolvingVertex(vertex))
889 {
890 List<Vertex> toRemove = new ArrayList<Vertex>();
891 toRemove.addAll(molGraph.getSymSetForVertex(vertex));
892 for (Vertex v : toRemove)
893 {
894 molGraph.removeBranchStartingAt(v);
895 }
896 }
897 else
898 {
899 molGraph.removeBranchStartingAt(vertex);
900 }
901
902 if (molGraph.getVertexWithId(vid) == null && molGraph.getVertexCount() > 1)
903 return true;
904
905 return false;
906 }
907
908//------------------------------------------------------------------------------
909
922 protected static boolean deleteChain(Vertex vertex, Monitor mnt,
923 FragmentSpace fragSpace) throws DENOPTIMException
924 {
925 long vid = vertex.getVertexId();
926 DGraph molGraph = vertex.getGraphOwner();
927
928 if (molGraph.hasSymmetryInvolvingVertex(vertex))
929 {
930 List<Vertex> toRemove = new ArrayList<Vertex>();
931 toRemove.addAll(molGraph.getSymSetForVertex(vertex));
932 for (Vertex v : toRemove)
933 {
934 if (!v.getMutationTypes(new ArrayList<MutationType>())
935 .contains(MutationType.DELETECHAIN))
936 continue;
937 molGraph.removeChainUpToBranching(v, fragSpace);
938 }
939 }
940 else
941 {
942 molGraph.removeChainUpToBranching(vertex, fragSpace);
943 }
944
945 if (molGraph.getVertexWithId(vid) == null && molGraph.getVertexCount() > 1)
946 return true;
947 return false;
948 }
949
950//------------------------------------------------------------------------------
951
967 protected static boolean addRing(Vertex vertex, Monitor mnt, boolean force,
968 FragmentSpace fragSpace, GAParameters settings)
969 throws DENOPTIMException
970 {
971 // get settings //TODO: this should happen inside RunTimeParameters
973 if (settings.containsParameters(ParametersType.RC_PARAMS))
974 {
975 rcParams = (RingClosureParameters)settings.getParameters(
977 }
978 Randomizer rng = settings.getRandomizer();
979
980 // First of all we remove capping groups in the graph
981 vertex.getGraphOwner().removeCappingGroups();
982
983 List<AttachmentPoint> freeeAPs = vertex.getFreeAPThroughout();
984 if (freeeAPs.size()==0)
985 {
987 return false;
988 }
989 DGraph originalGraph = vertex.getGraphOwner();
990 DGraph tmpGraph = originalGraph.clone();
991
992 Vertex headVrtx = tmpGraph.getVertexAtPosition(originalGraph.indexOf(
993 vertex));
994
995 // Define the set of rings on the cloned (tmp) graph
996 List<Ring> setOfRingsOnTmpGraph = null;
997 for (AttachmentPoint srcAP : headVrtx.getFreeAPThroughout())
998 {
999 APClass apc = srcAP.getAPClass();
1000
1001 // Skip if the APClass is not allowed to form ring closures
1002 if (!fragSpace.getRCCompatibilityMatrix().containsKey(apc))
1003 {
1004 continue;
1005 }
1006 List<APClass> rcTrgAPCs = fragSpace.getRCCompatibilityMatrix().get(
1007 apc);
1008
1009 // NB: the fragment space may or may not have a RCV for this AP
1010 Vertex rcvOnSrcAP = null;
1011 List<Vertex> candidateRCVs = fragSpace.getRCVsForAPClass(apc);
1012 boolean rcvIsChosenArbitrarily = false;
1013 if (candidateRCVs.size()>0)
1014 {
1015 rcvOnSrcAP = rng.randomlyChooseOne(candidateRCVs);
1016 } else {
1017 rcvIsChosenArbitrarily = true;
1018 rcvOnSrcAP = fragSpace.getPolarizedRCV(true);
1019 }
1020
1021 // Add the RCV on this AP
1022 List<Vertex> rcvAddedToGraph = new ArrayList<Vertex>();
1023 tmpGraph.appendVertexOnAP(srcAP, rcvOnSrcAP.getAP(0));
1024 rcvAddedToGraph.add(rcvOnSrcAP);
1025
1026 // Add a few RCVs in the rest of the system
1027 // WARNING: hard-coded max number of attempts. It should not be too
1028 // high to prevent combinatorial explosion.
1029 for (int i=0; i<20; i++)
1030 {
1031 // Do it only on APs that APClass-compatible with chord formation
1032 List<AttachmentPoint> apsToTry =
1033 tmpGraph.getAvailableAPsThroughout();
1034 int numberOfAttempts = apsToTry.size();
1035 AttachmentPoint trgAP = null;
1036 for (int iap=0; iap<numberOfAttempts; iap++)
1037 {
1038 AttachmentPoint candidate = rng.randomlyChooseOne(apsToTry);
1039 if (rcTrgAPCs.contains(candidate.getAPClass()))
1040 {
1041 trgAP = candidate;
1042 break;
1043 }
1044 apsToTry.remove(trgAP);
1045 }
1046 if (trgAP==null)
1047 {
1048 // No more AP can be used to form rings with srcAP
1049 break;
1050 }
1051
1052 // Choose type of RCV
1053 Vertex rcvOnTrgAP = null;
1054 if (rcvIsChosenArbitrarily)
1055 {
1056 rcvOnTrgAP = fragSpace.getPolarizedRCV(false);
1057 } else {
1058 List<Vertex> candRCVs = fragSpace.getRCVsForAPClass(
1059 trgAP.getAPClass());
1060 if (candRCVs.size()>0)
1061 {
1062 APClass requiredAPC = RingClosingAttractor.RCAAPCMAP.get(
1063 rcvOnSrcAP.getAP(0).getAPClass());
1064 List<Vertex> keptRCVs = new ArrayList<Vertex>();
1065 for (Vertex rcv : candRCVs)
1066 {
1067 if (requiredAPC.equals(rcv.getAP(0).getAPClass()))
1068 keptRCVs.add(rcv);
1069 }
1070 rcvOnTrgAP = rng.randomlyChooseOne(keptRCVs);
1071 if (rcvOnTrgAP==null)
1072 {
1073 // no RCV is both usable and compatible with the
1074 // one already selected for srcAP
1075 continue;
1076 }
1077 } else {
1078 // The APClass settings and RCV compatibility rules
1079 // do not allow to identify a suitable RCV
1080 continue;
1081 }
1082 }
1083
1084 // append RCV
1085 tmpGraph.appendVertexOnAP(trgAP, rcvOnTrgAP.getAP(0));
1086 rcvAddedToGraph.add(rcvOnTrgAP);
1087 }
1088 if (rcvAddedToGraph.size() < 2)
1089 {
1090 // TODO: we could consider counting these to see what is the
1091 // most frequent cause of this mutation to fail
1092 continue;
1093 }
1094
1095 // Define rings to close in tmp graph
1097 settings.getLogger(), rng);
1098 t3d.setAlignBBsIn3D(false); //3D not needed
1099 IAtomContainer mol = t3d.convertGraphTo3DAtomContainer(tmpGraph,true);
1101 mol,
1102 tmpGraph,
1103 settings.getMaxRingsAddedByMutation(),
1104 fragSpace, rcParams);
1105
1106 //TODO: possibility to generate multiple combinations, rank them,
1107 // and pick the best one. Though definition of comparator is not
1108 // unambiguous.
1109
1110 setOfRingsOnTmpGraph = rCombIter.next();
1111
1112 // Termination of search over trgAPs
1113 if (setOfRingsOnTmpGraph.size()>0)
1114 break;
1115
1116 // Cleanup before starting new iteration
1117 for (Vertex toRemove : rcvAddedToGraph)
1118 tmpGraph.removeVertex(toRemove);
1119 }
1120 if (setOfRingsOnTmpGraph==null || setOfRingsOnTmpGraph.size()==0)
1121 {
1123 return false;
1124 }
1125
1126 // Project rings into the actual graph
1127 boolean done = false;
1128 for (Ring rOnTmp : setOfRingsOnTmpGraph)
1129 {
1130 // Project head RCV and all info to attach it to original graph
1131 Vertex vToHeadRCV = originalGraph.getVertexAtPosition(
1132 tmpGraph.indexOf(rOnTmp.getHeadVertex().getParent()));
1133 AttachmentPoint apToHeadRCV = vToHeadRCV.getAP(
1134 rOnTmp.getHeadVertex().getEdgeToParent().getSrcAP()
1135 .getIndexInOwner());
1136 Vertex headRCV = null;
1137 if (!apToHeadRCV.isAvailable())
1138 {
1139 headRCV = apToHeadRCV.getLinkedAP().getOwner();
1140 } else {
1141 headRCV = rOnTmp.getHeadVertex().clone();
1143 // And append head RCV on original graph
1144 originalGraph.appendVertexOnAP(apToHeadRCV, headRCV.getAP(0));
1145 }
1146
1147 // Project tail RCV and all info to attach it to original graph
1148 Vertex vToTailRCV = originalGraph.getVertexAtPosition(
1149 tmpGraph.indexOf(rOnTmp.getTailVertex().getParent()));
1150 AttachmentPoint apToTailRCV = vToTailRCV.getAP(
1151 rOnTmp.getTailVertex().getEdgeToParent().getSrcAP()
1152 .getIndexInOwner());
1153 Vertex tailRCV = null;
1154 if (!apToTailRCV.isAvailable())
1155 {
1156 tailRCV = apToTailRCV.getLinkedAP().getOwner();
1157 } else {
1158 tailRCV = rOnTmp.getTailVertex().clone();
1160 // And append tail RCV on original graph
1161 originalGraph.appendVertexOnAP(apToTailRCV, tailRCV.getAP(0));
1162 }
1163
1164 // Add ring
1165 originalGraph.addRing(headRCV, tailRCV);
1166 done = true;
1167 }
1168
1169 // Restore capping groups
1170 vertex.getGraphOwner().addCappingGroups(fragSpace);
1171
1172 return done;
1173 }
1174
1175//------------------------------------------------------------------------------
1176
1192 protected static boolean addFusedRing(Vertex vertex, Monitor mnt,
1193 boolean force, FragmentSpace fragSpace, GAParameters settings)
1194 throws DENOPTIMException
1195 {
1196 // get settings //TODO: this should happen inside RunTimeParameters
1198 if (settings.containsParameters(ParametersType.RC_PARAMS))
1199 {
1200 rcParams = (RingClosureParameters)settings.getParameters(
1202 }
1203
1204 Randomizer rng = settings.getRandomizer();
1205
1206 // First of all we remove capping groups in the graph
1207 vertex.getGraphOwner().removeCappingGroups();
1208
1209 List<AttachmentPoint> freeAPs = vertex.getFreeAPThroughout();
1210 if (freeAPs.size()==0)
1211 {
1213 return false;
1214 }
1215
1216 DGraph graph = vertex.getGraphOwner();
1217
1218 // Define where to add a bridge. Multiple sites are the result of
1219 // symmetry, so they all correspond to the same kind of operation
1220 // performed on symmetry-related sites
1221 List<List<RelatedAPPair>> candidatePairsSets =
1223 graph,
1224 fragSpace,
1225 rcParams,
1226 rng.nextBoolean(settings.getSymmetryProbability()),
1227 settings.getLogger(), rng);
1228 if (candidatePairsSets.size()==0)
1229 {
1231 return false;
1232 }
1233
1234 // Bias by potential ring size considering the existing part of the
1235 // to-be-created ring.
1236 // NB: we have to do this twice because some sites may be used to
1237 // form rings with different sizes. So, see below for the second time...
1238 List<List<RelatedAPPair>> szBiasedCandidatePairsSets =
1239 new ArrayList<List<RelatedAPPair>>();
1240 for (List<RelatedAPPair> pairSet : candidatePairsSets)
1241 {
1243 pairSet.get(0).property;
1244 int existingBridgeLength = bhfrOfPair.getExistingBridgeLength();
1245 int[] allowedBridgeLengths = bhfrOfPair.getAllowedBridgeLength(
1246 rcParams.getMaxRingSize());
1247 for (int i=0; i<allowedBridgeLengths.length; i++)
1248 {
1249 int allowedBridgeLength = allowedBridgeLengths[i];
1250 int possibleRingSize = allowedBridgeLength
1251 + existingBridgeLength;
1252 int weight = 1; // weight of a ring size
1253 if (possibleRingSize < rcParams.getMaxRingSize())
1254 {
1255 weight = rcParams.getRingSizeBias().get(possibleRingSize);
1256 }
1257
1258 // We add copies of the same set to the list of candidate
1259 // sets, so when we randomly choose we are more likely to
1260 // choose a set that leads to preferred ring sizes.
1261 for (int z=0; z<weight; z++)
1262 {
1263 szBiasedCandidatePairsSets.add(pairSet);
1264 }
1265 }
1266 }
1267 if (szBiasedCandidatePairsSets.size()==0)
1268 {
1270 return false;
1271 }
1272
1273 // Select one combination
1274 List<RelatedAPPair> chosenPairsSet = rng.randomlyChooseOne(
1275 szBiasedCandidatePairsSets);
1276
1277 // Based on the chosen pair, decide on the number of electrons to use
1278 // in the incoming fragment that will be used to close the ring
1279 // the pairs are all the same kind of ring fusion, so just take the 1st
1280 String elsInHalfFrag = chosenPairsSet.get(0).propID.substring(0,1);
1281 if (elsInHalfFrag.matches("[a-zA-Z]"))
1282 elsInHalfFrag = "0";
1283 boolean newRingIsAromatic = true;
1284 String elInIncomingFrag = "0el";
1285 switch (elsInHalfFrag)
1286 {
1287 case "0":
1288 case "1":
1289 // no aromaticity to be retained: use non-aromatic chords
1290 elInIncomingFrag = "0el";
1291 newRingIsAromatic = false;
1292 break;
1293
1294 case "2":
1295 // Formally we can use any fragment delivering 4n electrons.
1296 // Effectively, we have only 4-el fragments
1297 elInIncomingFrag = "4el";
1298 break;
1299
1300 case "3":
1301 // We could use a 5-el fragment, but the 8-el aromatic system is
1302 // so rare that we avoid it. So, we can only use 3-el fragment
1303 elInIncomingFrag = "3el";
1304 break;
1305
1306 case "4":
1307 // Effectively can only use 2-el fragments
1308 elInIncomingFrag = "2el";
1309 break;
1310
1311 case "5":
1312 // We could use a 3-el fragment, but the 8-el aromatic system is
1313 // so rare that we avoid it. This could become a tunable config
1314 elInIncomingFrag = "1el";
1315 break;
1316 default:
1317 throw new Error("Unknown number of pi-electrons in fragment to "
1318 + "be used for ring fusion operation.");
1319 }
1320
1321 // Collect fragment that can be used as ring-closing bridge based on the
1322 // number of aromatic electrons and number of atoms
1324 chosenPairsSet.get(0).property;
1325
1326 List<Vertex> usableBridges = null;
1327 if (newRingIsAromatic)
1328 {
1329 usableBridges = EAUtils.getUsableAromaticBridges(
1330 elInIncomingFrag,
1331 bhfr.getAllowedBridgeLength(rcParams.getMaxRingSize()),
1332 fragSpace);
1333 } else {
1334 // NB: we keep track of which APs are supposed to be used to form
1335 // the bridge by recording their index in a property of the vertex
1336 usableBridges = EAUtils.getUsableAliphaticBridges(
1337 chosenPairsSet.get(0).apA.getAPClass(),
1338 chosenPairsSet.get(0).apB.getAPClass(),
1339 bhfr.getAllowedBridgeLength(rcParams.getMaxRingSize()),
1340 fragSpace);
1341 }
1342
1343 if (usableBridges.size()==0)
1344 {
1346 return false;
1347 }
1348
1349 // Select size of the incoming bridge based on ring-size biases
1350 // NB: we have to do this twice because some sites may be used to
1351 // form rings with different sizes. So, see above for the first time...
1352 List<Vertex> szBiasedUsableBridges = new ArrayList<Vertex>();
1353 for (Vertex candidateBridge : usableBridges)
1354 {
1355 int thisBridgeLength = (int) candidateBridge.getProperty(
1357 int existingBridgeLength = bhfr.getExistingBridgeLength();
1358 int resultingRingSize = existingBridgeLength + thisBridgeLength;
1359 int weigth = 1; // weight of a ring size
1360 if (resultingRingSize < rcParams.getMaxRingSize())
1361 {
1362 weigth = rcParams.getRingSizeBias().get(resultingRingSize);
1363 }
1364
1365 // We add copies of the same vertex to the list of candidate
1366 // vertexes, so when we randomly choose we are more likely to
1367 // choose those leading to preferred ring sizes.
1368 for (int z=0; z<weigth; z++)
1369 {
1370 szBiasedUsableBridges.add(candidateBridge);
1371 }
1372 }
1373
1374 if (szBiasedUsableBridges.size()==0)
1375 {
1377 return false;
1378 }
1379
1380 Vertex incomingVertex = rng.randomlyChooseOne(szBiasedUsableBridges);
1381
1382 // Decide which aps on the bridge are used as head/tail
1383 List<AttachmentPoint> apsInFusion = new ArrayList<AttachmentPoint>();
1384 int[] idApOnBridge = new int[2];
1385 if (newRingIsAromatic)
1386 {
1387 apsInFusion.addAll(incomingVertex.getAPsWithAPClassStartingWith(
1388 elInIncomingFrag));
1389 if (rng.nextBoolean())
1390 {
1391 idApOnBridge[0] = apsInFusion.get(0).getIndexInOwner();
1392 idApOnBridge[1] = apsInFusion.get(1).getIndexInOwner();
1393 } else {
1394 idApOnBridge[0] = apsInFusion.get(1).getIndexInOwner();
1395 idApOnBridge[1] = apsInFusion.get(0).getIndexInOwner();
1396 }
1397 } else {
1398 idApOnBridge[0] = Integer.parseInt(incomingVertex.getProperty(
1400 idApOnBridge[1] = Integer.parseInt(incomingVertex.getProperty(
1402 }
1403
1404 boolean done = false;
1405 for (RelatedAPPair pairOfAPs : chosenPairsSet)
1406 {
1407 AttachmentPoint apHead = pairOfAPs.apA;
1408 AttachmentPoint apTail = pairOfAPs.apB;
1409
1410 Vertex bridgeClone = incomingVertex.clone();
1411 bridgeClone.setVertexId(graph.getMaxVertexId()+1);
1412
1413 graph.appendVertexOnAP(apHead, bridgeClone.getAP(idApOnBridge[0]));
1414
1415 Vertex rcvBridge = fragSpace.getPolarizedRCV(true);
1416 graph.appendVertexOnAP(bridgeClone.getAP(idApOnBridge[1]),
1417 rcvBridge.getAP(0));
1418
1419 Vertex rcvTail = fragSpace.getPolarizedRCV(false);
1420 graph.appendVertexOnAP(apTail, rcvTail.getAP(0));
1421 graph.addRing(rcvBridge, rcvTail);
1422 done = true;
1423 }
1424
1425 // Restore capping groups
1426 vertex.getGraphOwner().addCappingGroups(fragSpace);
1427
1428 return done;
1429 }
1430
1431//------------------------------------------------------------------------------
1432
1447 protected static boolean extendGraph(Vertex curVertex,
1448 boolean extend,
1449 boolean symmetryOnAps,
1450 GAParameters settings)
1451 throws DENOPTIMException
1452 {
1453 return extendGraph(curVertex, extend, symmetryOnAps, false, -1, -1,
1454 settings);
1455 }
1456
1457//------------------------------------------------------------------------------
1458
1482 protected static boolean extendGraph(Vertex curVrtx,
1483 boolean extend,
1484 boolean symmetryOnAps,
1485 boolean force,
1486 int chosenVrtxIdx,
1487 int chosenApId,
1488 GAParameters settings)
1489 throws DENOPTIMException
1490 {
1491 // get settings //TODO: this should happen inside RunTimeParameters
1493 if (settings.containsParameters(ParametersType.RC_PARAMS))
1494 {
1495 rcParams = (RingClosureParameters)settings.getParameters(
1497 }
1499 if (settings.containsParameters(ParametersType.FS_PARAMS))
1500 {
1501 fsParams = (FragmentSpaceParameters)settings.getParameters(
1503 }
1504 int maxHeavyAtoms = fsParams.getMaxHeavyAtom();
1505
1506 // return true if the append has been successful
1507 boolean status = false;
1508
1509 // check if the fragment has available APs
1510 if (!curVrtx.hasFreeAP())
1511 {
1512 return status;
1513 }
1514
1515 DGraph molGraph = curVrtx.getGraphOwner();
1516 int lvl = molGraph.getLevel(curVrtx);
1517
1518 ArrayList<Long> addedVertices = new ArrayList<>();
1519
1520 List<AttachmentPoint> lstDaps = curVrtx.getAttachmentPoints();
1521 List<AttachmentPoint> toDoAPs = new ArrayList<AttachmentPoint>();
1522 toDoAPs.addAll(lstDaps);
1523 for (int i=0; i<lstDaps.size(); i++)
1524 {
1525 // WARNING: randomization decouples 'i' from the index of the AP
1526 // in the vertex's list of APs! So 'i' is just the i-th attempt on
1527 // the curVertex.
1528
1529 AttachmentPoint ap = settings.getRandomizer().randomlyChooseOne(
1530 toDoAPs);
1531 toDoAPs.remove(ap);
1532 int apId = ap.getIndexInOwner();
1533
1534 // is it possible to extend on this AP?
1535 if (!ap.isAvailable())
1536 {
1537 continue;
1538 }
1539
1540 // NB: this is done also in addRing()
1541 // Ring closure does not change the size of the molecule, so we
1542 // give it an extra chance to occur irrespectively on molecular size
1543 // limit, while still subject of crowdedness probability.
1544 boolean allowOnlyRingClosure = false;
1545 if (!force)
1546 {
1547 // Decide whether we want to extend the graph at this AP?
1548 // Note that depending on the criterion (level/molSize) one
1549 // of these two first factors is 1.0.
1550 double molSizeProb = EAUtils.getMolSizeProbability(molGraph,
1551 settings);
1552 double byLevelProb = EAUtils.getGrowthByLevelProbability(lvl,
1553 settings);
1554 double crowdingProb = EAUtils.getCrowdingProbability(ap,
1555 settings);
1556 double extendGraphProb = molSizeProb * byLevelProb * crowdingProb;
1557 boolean fgrow = settings.getRandomizer().nextBoolean(
1558 extendGraphProb);
1559 if (!fgrow)
1560 {
1561 if (rcParams.allowRingClosures()
1562 && settings.getRandomizer().nextBoolean(byLevelProb
1563 * crowdingProb))
1564 {
1565 allowOnlyRingClosure = true;
1566 } else {
1567 continue;
1568 }
1569 }
1570 }
1571
1572 // Apply closability bias in selection of next fragment
1573 if (!allowOnlyRingClosure
1574 && rcParams.allowRingClosures()
1576 {
1577 boolean successful = attachFragmentInClosableChain(curVrtx,
1578 apId, molGraph, addedVertices, settings);
1579 if (successful)
1580 {
1581 continue;
1582 }
1583 }
1584
1585 // find a compatible combination of fragment and AP
1586 IdFragmentAndAP chosenFrgAndAp = null;
1587 if (allowOnlyRingClosure)
1588 {
1589 // NB: this works only for RCVs that are in the BBSpace, does
1590 // not generate a default RCV on-the-fly. So if no RCV is found
1591 // we'll get a pointer to nothing, which is what we check in the
1592 // next IF-block.
1593 chosenFrgAndAp = getRCVForSrcAp(curVrtx, apId,
1594 fsParams.getFragmentSpace());
1595 } else {
1596 chosenFrgAndAp = getFrgApForSrcAp(curVrtx,
1597 apId, chosenVrtxIdx, chosenApId, fsParams.getFragmentSpace());
1598 }
1599 int fid = chosenFrgAndAp.getVertexMolId();
1600 if (fid == -1)
1601 {
1602 continue;
1603 }
1604
1605 // Get the vertex that we'll add to the graph
1606 Vertex incomingVertex = Vertex.newVertexFromLibrary(-1,
1607 chosenFrgAndAp.getVertexMolId(),
1609 fsParams.getFragmentSpace());
1610
1611 // Stop if graph is already too big
1612 if ((curVrtx.getGraphOwner().getHeavyAtomsCount() +
1613 incomingVertex.getHeavyAtomsCount()) > maxHeavyAtoms)
1614 {
1615 continue;
1616 }
1617
1618 // Decide on symmetric substitution within this vertex...
1619 boolean cpOnSymAPs = applySymmetry(
1621 ap.getAPClass()),
1622 settings.getSymmetryProbability(),
1623 fsParams.getRandomizer());
1624 SymmetricAPs symAPs = new SymmetricAPs();
1625 if (curVrtx.getSymmetricAPs(ap).size()!=0
1626 && (cpOnSymAPs || symmetryOnAps)
1627 && !allowOnlyRingClosure)
1628 {
1629 symAPs.addAll(curVrtx.getSymmetricAPs(ap));
1630
1631 // Are symmetric APs rooted on same atom?
1632 boolean allOnSameSrc = true;
1633 for (AttachmentPoint symAP : symAPs)
1634 {
1635 if (!symAP.hasSameSrcAtom(ap))
1636 {
1637 allOnSameSrc = false;
1638 break;
1639 }
1640 }
1641
1642 if (allOnSameSrc)
1643 {
1644 // If the APs are rooted on the same src atom, we want to
1645 // apply the crowdedness probability to avoid over crowded
1646 // atoms
1647
1648 int crowdedness = EAUtils.getCrowdedness(ap);
1649
1650 SymmetricAPs toKeep = new SymmetricAPs();
1651
1652 // Start by keeping "ap"
1653 toKeep.add(ap);
1654 crowdedness = crowdedness + 1;
1655
1656 // Pick the accepted value once (used to decide how much
1657 // crowdedness we accept)
1658 double shot = settings.getRandomizer().nextDouble();
1659
1660 // Keep as many as allowed by the crowdedness decision
1661 for (AttachmentPoint symAP : symAPs)
1662 {
1663 if (symAP == ap)
1664 continue;
1665
1666 double crowdProb = EAUtils.getCrowdingProbability(
1667 crowdedness, settings);
1668
1669 if (shot > crowdProb)
1670 break;
1671
1672 toKeep.add(symAP);
1673 crowdedness = crowdedness + 1;
1674 }
1675
1676 // Adjust the list of symmetric APs to work with
1677 symAPs = toKeep;
1678 }
1679 } else {
1680 symAPs = new SymmetricAPs();
1681 symAPs.add(ap);
1682 }
1683
1684 // ...and inherit symmetry from previous levels
1685 boolean cpOnSymVrts = molGraph.hasSymmetryInvolvingVertex(curVrtx);
1686 SymmetricVertexes symVerts = new SymmetricVertexes();
1687 if (cpOnSymVrts)
1688 {
1689 symVerts = molGraph.getSymSetForVertex(curVrtx);
1690 }
1691 else
1692 {
1693 symVerts.add(curVrtx);
1694 }
1695
1696 // Consider size after application of symmetry
1697 if ((curVrtx.getGraphOwner().getHeavyAtomsCount() +
1698 incomingVertex.getHeavyAtomsCount() * symVerts.size()
1699 * symAPs.size()) > maxHeavyAtoms)
1700 {
1701 continue;
1702 }
1703
1704 // Collects all sym APs: within the vertex and outside it
1705 List<AttachmentPoint> allAPsFromSymVerts = new ArrayList<>();
1706 for (Vertex symVrt : symVerts)
1707 {
1708 for (AttachmentPoint apOnVrt : symAPs)
1709 {
1710 AttachmentPoint apOnSymVrt = symVrt.getAP(
1711 apOnVrt.getIndexInOwner());
1712 // This check is most often not needed, but it prevents that
1713 // misleading symmetry relations are used to break APClass
1714 // compatibility constraints
1715 if (apOnVrt.sameAs(apOnSymVrt)
1716 // Also ignore previously found APs
1717 && !symAPs.contains(apOnSymVrt))
1718 {
1719 allAPsFromSymVerts.add(apOnSymVrt);
1720 }
1721 }
1722 }
1723 symAPs.addAll(allAPsFromSymVerts);
1724
1726
1727 // loop on all symmetric vertices, but can be only one.
1728 SymmetricVertexes newSymSetOfVertices = new SymmetricVertexes();
1729 for (AttachmentPoint symAP : symAPs)
1730 {
1731 if (!symAP.isAvailable())
1732 {
1733 continue;
1734 }
1735
1736 // Finally add the fragment on a symmetric AP
1737 long newVrtId = GraphUtils.getUniqueVertexIndex();
1738 Vertex fragVertex = Vertex.newVertexFromLibrary(newVrtId,
1739 chosenFrgAndAp.getVertexMolId(),
1741 fsParams.getFragmentSpace());
1742 AttachmentPoint trgAP = fragVertex.getAP(
1743 chosenFrgAndAp.getApId());
1744
1745 molGraph.appendVertexOnAP(symAP, trgAP);
1746
1747 addedVertices.add(newVrtId);
1748 newSymSetOfVertices.add(fragVertex);
1749 }
1750
1751 // If any, store symmetry of new vertices in the graph
1752 if (newSymSetOfVertices.size() > 1)
1753 {
1754 molGraph.addSymmetricSetOfVertices(newSymSetOfVertices);
1755 }
1756 } // end loop over APs
1757
1758 if (extend)
1759 {
1760 // attempt to further extend each of the newly added vertices
1761 for (int i=0; i<addedVertices.size(); i++)
1762 {
1763 long vid = addedVertices.get(i);
1764 Vertex v = molGraph.getVertexWithId(vid);
1765 extendGraph(v, extend, symmetryOnAps, settings);
1766 }
1767 }
1768
1769 if (addedVertices.size() > 0)
1770 status = true;
1771
1772 return status;
1773 }
1774
1775//------------------------------------------------------------------------------
1776
1788 protected static IdFragmentAndAP getFrgApForSrcAp(Vertex curVertex,
1789 int dapidx, FragmentSpace fragSpace) throws DENOPTIMException
1790 {
1791 return getFrgApForSrcAp(curVertex, dapidx, -1, -1, fragSpace);
1792 }
1793
1794//------------------------------------------------------------------------------
1795
1813 protected static IdFragmentAndAP getFrgApForSrcAp(Vertex curVertex,
1814 int dapidx, int chosenVrtxIdx, int chosenApId,
1815 FragmentSpace fragSpace) throws DENOPTIMException
1816 {
1817 List<AttachmentPoint> lstDaps = curVertex.getAttachmentPoints();
1818 AttachmentPoint curDap = lstDaps.get(dapidx);
1819
1820 // Initialize with an empty pointer
1821 IdFragmentAndAP res = new IdFragmentAndAP(-1, -1, BBType.FRAGMENT, -1,
1822 -1, -1);
1823 if (!fragSpace.useAPclassBasedApproach())
1824 {
1825 int fid = fragSpace.getRandomizer().nextInt(
1826 fragSpace.getFragmentLibrary().size());
1827 res = new IdFragmentAndAP(-1,fid,BBType.FRAGMENT,-1,-1,-1);
1828 }
1829 else
1830 {
1831 List<IdFragmentAndAP> candidates =
1832 fragSpace.getFragAPsCompatibleWithClass(
1833 curDap.getAPClass());
1834 if (candidates.size() > 0)
1835 {
1836 if (chosenVrtxIdx>-1 && chosenApId>-1)
1837 {
1838 // We have asked to force the selection
1839 res = new IdFragmentAndAP(-1,chosenVrtxIdx,BBType.FRAGMENT,
1840 chosenApId,-1,-1);
1841 } else {
1842 res = fragSpace.getRandomizer().randomlyChooseOne(candidates);
1843 }
1844 }
1845 }
1846 return res;
1847 }
1848
1849//------------------------------------------------------------------------------
1850
1862 protected static IdFragmentAndAP getRCVForSrcAp(Vertex curVertex,
1863 int dapidx, FragmentSpace fragSpace) throws DENOPTIMException
1864 {
1865 AttachmentPoint ap = curVertex.getAP(dapidx);
1866
1867 Randomizer rng = fragSpace.getRandomizer();
1868 List<Vertex> rcvs = fragSpace.getRCVs();
1869 Vertex chosen = null;
1870 if (!fragSpace.useAPclassBasedApproach())
1871 {
1872 chosen = rng.randomlyChooseOne(rcvs);
1873 } else {
1874 List<Vertex> candidates = fragSpace.getRCVsForAPClass(
1875 ap.getAPClass());
1876 if (candidates.size() > 0)
1877 {
1878 chosen = rng.randomlyChooseOne(candidates);
1879 }
1880 }
1881
1882 IdFragmentAndAP pointer = new IdFragmentAndAP();
1883 if (chosen!=null)
1884 pointer = new IdFragmentAndAP(-1, chosen.getBuildingBlockId(),
1885 chosen.getBuildingBlockType(), 0, -1, -1);
1886 return pointer;
1887 }
1888
1889//------------------------------------------------------------------------------
1890
1891 protected static boolean attachFragmentInClosableChain(
1892 Vertex curVertex, int dapidx, DGraph molGraph,
1893 ArrayList<Long> addedVertices, GAParameters settings)
1894 throws DENOPTIMException
1895 {
1896 boolean res = false;
1898 if (settings.containsParameters(ParametersType.FS_PARAMS))
1899 {
1900 fsParams = (FragmentSpaceParameters)settings.getParameters(
1902 }
1903
1904 // Get candidate fragments
1905 ArrayList<FragForClosabChains> lscFfCc = getFragmentForClosableChain(
1906 curVertex, dapidx, molGraph);
1907
1908 // Here we can get:
1909 // 1) a selection of fragments that allow to close rings
1910 // 2) an empty list because no fragments allow to close rings
1911 // 3) "-1" as molID that means there are closable chains that
1912 // terminate at the current level, so we let the standard
1913 // routine proceeds selecting an extension of the chain
1914 // or cap this end.
1915
1916 // Choose a candidate and attach it to the graph
1917 int numCands = lscFfCc.size();
1918 if (numCands > 0)
1919 {
1920 int chosenId = settings.getRandomizer().nextInt(numCands);
1921 FragForClosabChains chosenFfCc = lscFfCc.get(chosenId);
1922 ArrayList<Integer> newFragIds = chosenFfCc.getFragIDs();
1923 int molIdNewFrag = newFragIds.get(0);
1924 BBType typeNewFrag = BBType.parseInt(newFragIds.get(1));
1925 int dapNewFrag = newFragIds.get(2);
1926 if (molIdNewFrag != -1)
1927 {
1928 long newvid = GraphUtils.getUniqueVertexIndex();
1930 newvid, molIdNewFrag, typeNewFrag,
1931 fsParams.getFragmentSpace());
1932
1933 molGraph.appendVertexOnAP(curVertex.getAP(dapidx),
1934 newVrtx.getAP(dapNewFrag));
1935
1936 if (newvid != -1)
1937 {
1938 addedVertices.add(newvid);
1939 // update list of candidate closable chains
1940 molGraph.getClosableChains().removeAll(
1941 chosenFfCc.getIncompatibleCC());
1942 APClass apc = curVertex.getAttachmentPoints().get(
1943 dapidx).getAPClass();
1944 if (applySymmetry(
1946 settings.getSymmetryProbability(),
1947 fsParams.getRandomizer()))
1948 {
1949//TODO: implement symmetric substitution with closability bias
1950 }
1951 res = true;
1952 }
1953 else
1954 {
1955 String msg = "BUG: Incorrect vertex num. Contact author.";
1956 settings.getLogger().log(Level.SEVERE, msg);
1957 throw new DENOPTIMException(msg);
1958 }
1959 }
1960 }
1961 return res;
1962 }
1963
1964//------------------------------------------------------------------------------
1965
1970 private static class FragForClosabChains
1971 {
1972 private ArrayList<ClosableChain> compatChains;
1973 private ArrayList<ClosableChain> incompatChains;
1974 private ArrayList<Integer> fragIds;
1975
1976 //----------------------------------------------------------------------
1977
1978 public FragForClosabChains(ArrayList<ClosableChain> compatChains,
1979 ArrayList<ClosableChain> incompatChains,
1980 ArrayList<Integer> fragIds)
1981 {
1982 this.compatChains = compatChains;
1983 this.incompatChains = incompatChains;
1984 this.fragIds = fragIds;
1985 }
1986
1987 //----------------------------------------------------------------------
1988
1990 {
1991 compatChains.add(icc);
1992 }
1993
1994 //----------------------------------------------------------------------
1995
1996 public ArrayList<ClosableChain> getCompatibleCC()
1997 {
1998 return compatChains;
1999 }
2000
2001 //----------------------------------------------------------------------
2002
2003 public ArrayList<ClosableChain> getIncompatibleCC()
2004 {
2005 return incompatChains;
2006 }
2007
2008 //----------------------------------------------------------------------
2009
2010 public ArrayList<Integer> getFragIDs()
2011 {
2012 return fragIds;
2013 }
2014
2015 //----------------------------------------------------------------------
2016 }
2017
2018//------------------------------------------------------------------------------
2019
2025 protected static ArrayList<FragForClosabChains> getFragmentForClosableChain(
2026 Vertex curVertex,
2027 int dapidx,
2028 DGraph molGraph)
2029 throws DENOPTIMException
2030 {
2031 // Select candidate fragments respecting the closability conditions
2032 ArrayList<FragForClosabChains> lstChosenFfCc =
2033 new ArrayList<FragForClosabChains>();
2034
2035 if (molGraph.getClosableChains().size() == 0)
2036 {
2037 return lstChosenFfCc;
2038 }
2039
2040 if (curVertex.getBuildingBlockType() == BBType.SCAFFOLD)
2041 {
2042 for (ClosableChain cc : molGraph.getClosableChains())
2043 {
2044 int posInCc = cc.involvesVertex(curVertex);
2045 ChainLink cLink = cc.getLink(posInCc);
2046 int nfid = -1;
2047 BBType nfty = BBType.UNDEFINED;
2048 int nfap = -1;
2049
2050 if (cLink.getApIdToLeft() != dapidx &&
2051 cLink.getApIdToRight() != dapidx)
2052 {
2053 // Chain does not involve AP dapidx
2054 continue;
2055 }
2056
2057 if (cLink.getApIdToRight() == dapidx)
2058 {
2059 if (cc.getSize() > (posInCc+1))
2060 {
2061 // cLink is NOT the rightmost chain link
2062 ChainLink nextChainLink = cc.getLink(posInCc+1);
2063 nfid = nextChainLink.getIdx();
2064 nfty = nextChainLink.getFragType();
2065 nfap = nextChainLink.getApIdToLeft();
2066 }
2067 else
2068 {
2069 // cLink is the rightmost chain link
2070 // closability bias suggest NO fragment
2071 }
2072 }
2073 else if (cLink.getApIdToLeft() == dapidx)
2074 {
2075 if ((posInCc-1) >= 0)
2076 {
2077 // cLink is NOT the leftmost chain link
2078 ChainLink nextChainLink = cc.getLink(posInCc-1);
2079 nfid = nextChainLink.getIdx();
2080 nfty = nextChainLink.getFragType();
2081 nfap = nextChainLink.getApIdToRight();
2082 }
2083 else
2084 {
2085 // cLink is the leftmost chain link
2086 // closability bias suggest NO fragment
2087 }
2088 }
2089
2090 ArrayList<Integer> eligibleFrgId = new ArrayList<Integer>();
2091 eligibleFrgId.add(nfid);
2092 eligibleFrgId.add(nfty.toOldInt());
2093 eligibleFrgId.add(nfap);
2094 boolean found = false;
2095 for (FragForClosabChains ffcc : lstChosenFfCc)
2096 {
2097 int fidA = ffcc.getFragIDs().get(0);
2098 BBType ftyA = BBType.parseInt(ffcc.getFragIDs().get(1));
2099 int fapA = ffcc.getFragIDs().get(2);
2100 if (nfid==fidA && nfty==ftyA && nfap==fapA)
2101 {
2102 found = true;
2103 ffcc.getCompatibleCC().add(cc);
2104 }
2105 else
2106 {
2107 ffcc.getIncompatibleCC().add(cc);
2108 }
2109 }
2110 if (!found)
2111 {
2112 ArrayList<ClosableChain> compatChains =
2113 new ArrayList<ClosableChain>();
2114 ArrayList<ClosableChain> incompatChains =
2115 new ArrayList<ClosableChain>();
2116 for (FragForClosabChains otherFfCc : lstChosenFfCc)
2117 {
2118 incompatChains.addAll(otherFfCc.getCompatibleCC());
2119 }
2120 FragForClosabChains newChosenCc = new FragForClosabChains(
2121 compatChains,
2122 incompatChains,
2123 eligibleFrgId);
2124
2125 newChosenCc.addCompatibleCC(cc);
2126 lstChosenFfCc.add(newChosenCc);
2127 }
2128 }
2129 }
2130 else
2131 {
2132 Vertex parent = molGraph.getParent(curVertex);
2133 Edge edge = molGraph.getEdgeWithParent(
2134 curVertex.getVertexId());
2135 int prntId = parent.getBuildingBlockId();
2136 BBType prntTyp = parent.getBuildingBlockType();
2137 int prntAp = edge.getSrcAPID();
2138 int chidAp = edge.getTrgAPID();
2139 for (ClosableChain cc : molGraph.getClosableChains())
2140 {
2141 int posInCc = cc.involvesVertexAndAP(curVertex, dapidx, chidAp);
2142
2143 if (posInCc == -1)
2144 {
2145 // closable chain does not span this combination
2146 // of vertex and APs
2147 continue;
2148 }
2149
2150 ChainLink cLink = cc.getLink(posInCc);
2151 int nfid = -1;
2152 BBType nfty = BBType.UNDEFINED;
2153 int nfap = -1;
2154
2155 List<Integer> altertnativeDirections = new ArrayList<>();
2156 altertnativeDirections.add(-1);
2157 altertnativeDirections.add(+1);
2158 for (int altDir : altertnativeDirections)
2159 {
2160 ChainLink parentLink = cc.getLink(posInCc + altDir);
2161 int pLnkId = parentLink.getIdx();
2162 BBType pLnkTyp = parentLink.getFragType();
2163
2164 int pLnkAp = -1;
2165 int cApId = -1;
2166 if (altDir>0)
2167 {
2168 pLnkAp = parentLink.getApIdToRight();
2169 cApId = cLink.getApIdToLeft();
2170 } else {
2171 pLnkAp = parentLink.getApIdToLeft();
2172 cApId = cLink.getApIdToRight();
2173 }
2174 if (pLnkId==prntId && pLnkTyp==prntTyp && pLnkAp == prntAp &&
2175 cApId == chidAp)
2176 {
2177 if (cc.getSize() > (posInCc+altDir)
2178 && (posInCc+altDir) >= 0)
2179 {
2180 ChainLink nextChainLink = cc.getLink(posInCc + altDir);
2181 nfid = nextChainLink.getIdx();
2182 nfty = nextChainLink.getFragType();
2183 nfap = nextChainLink.getApIdToLeft();
2184 }
2185 else
2186 {
2187 // cLink is the rightmost chain link
2188 // closability bias suggests NO fragment
2189 }
2190 }
2191 else
2192 {
2193 // different parent link
2194 continue;
2195 }
2196 }
2197
2198 ArrayList<Integer> eligibleFrgId = new ArrayList<Integer>();
2199 eligibleFrgId.add(nfid);
2200 eligibleFrgId.add(nfty.toOldInt());
2201 eligibleFrgId.add(nfap);
2202 boolean found = false;
2203 for (FragForClosabChains ffcc : lstChosenFfCc)
2204 {
2205 int fidA = ffcc.getFragIDs().get(0);
2206 BBType ftyA = BBType.parseInt(ffcc.getFragIDs().get(1));
2207 int fapA = ffcc.getFragIDs().get(2);
2208 if (nfid==fidA && nfty==ftyA && nfap==fapA)
2209 {
2210 found = true;
2211 ffcc.getCompatibleCC().add(cc);
2212 }
2213 else
2214 {
2215 ffcc.getIncompatibleCC().add(cc);
2216 }
2217 }
2218 if (!found)
2219 {
2220 ArrayList<ClosableChain> compatChains =
2221 new ArrayList<ClosableChain>();
2222 ArrayList<ClosableChain> incompatChains =
2223 new ArrayList<ClosableChain>();
2224 for (FragForClosabChains otherFfCc : lstChosenFfCc)
2225 {
2226 incompatChains.addAll(otherFfCc.getCompatibleCC());
2227 }
2228 FragForClosabChains newChosenCc = new FragForClosabChains(
2229 compatChains,
2230 incompatChains,
2231 eligibleFrgId);
2232 newChosenCc.addCompatibleCC(cc);
2233 lstChosenFfCc.add(newChosenCc);
2234 }
2235 }
2236 }
2237 return lstChosenFfCc;
2238 }
2239
2240//------------------------------------------------------------------------------
2241
2252 public static boolean performCrossover(XoverSite site,
2253 FragmentSpace fragSpace) throws DENOPTIMException
2254 {
2255 DGraph gA = site.getA().get(0).getGraphOwner();
2256 DGraph gB = site.getB().get(0).getGraphOwner();
2257
2258 // All the APs that point away from the subgraph
2259 List<AttachmentPoint> allAPsOnA = gA.getSubgraphAPs(site.getA());
2260 List<AttachmentPoint> allAPsOnB = gB.getSubgraphAPs(site.getB());
2261
2262 // The APs that are required to have a mapping for proper crossover,
2263 // eg. because the change of subgraph needs to retain a super structure.
2264 List<AttachmentPoint> needyAPsOnA = site.getAPsNeedingMappingA();
2265 List<AttachmentPoint> needyAPsOnB = site.getAPsNeedingMappingB();
2266
2267 // APs that connects the subgraphs' root to the parent vertex
2268 AttachmentPoint apToParentA = null;
2269 AttachmentPoint apToParentB = null;
2270 for (AttachmentPoint ap : needyAPsOnA)
2271 {
2272 if (!ap.isSrcInUserThroughout())
2273 {
2274 apToParentA = ap;
2275 //WARNING: we assume there is one AND only one AP to parent!!!
2276 break;
2277 }
2278 }
2279 for (AttachmentPoint ap : needyAPsOnB)
2280 {
2281 if (!ap.isSrcInUserThroughout())
2282 {
2283 apToParentB = ap;
2284 //WARNING: we assume there is one AND only one AP to parent!!!
2285 break;
2286 }
2287 }
2288 if (apToParentA==null || apToParentB==null)
2289 {
2290 throw new DENOPTIMException("Could not identify any attachment "
2291 + "point connecting a subgraph to the rest of the graph. "
2292 + "This violates assumption that crossover does not "
2293 + "involve scaffold or vertexes without parent.");
2294 }
2295 // Check if the subgraphs can be used with reversed edge direction, or
2296 // bias the AP mapping to use the original source vertexes.
2297 APMapping fixedRootAPs = null;
2298 //TODO: REACTIVATE ONCE REVERSION of the subgrsph's spanning tree is in place.
2299 //if (!subG_M.isReversible() || !subG_F.isReversible())
2300 if (true)
2301 {
2302 // Constrain the AP mapping so that the AP originally used to
2303 // connect to the parent vertex, will also be used the same way.
2304 // Thus, forces retention of edge direction within the subgraph.
2305 fixedRootAPs = new APMapping();
2306 fixedRootAPs.put(apToParentA, apToParentB);
2307 }
2308
2309 // Find an AP mapping that satisfies both root-vertex constrain and
2310 // need to ensure the mapping of needy APs
2311 APMapFinder apmf = new APMapFinder(fragSpace,
2312 allAPsOnA, needyAPsOnA,
2313 allAPsOnB, needyAPsOnB, fixedRootAPs,
2314 false, // false means stop at the first compatible mapping.
2315 false, // false means we do not require complete mapping.
2316 false); // false means free AP are not considered compatible.
2317 if (!apmf.foundMapping())
2318 {
2319 // Since the xover site has been detected by searching for compatible
2320 // sites that do have a mapping there should always be at least one
2321 // mapping and this exception should never occur.
2322 throw new DENOPTIMException("Missing AP mapping for known XoverSite.");
2323 }
2324
2325 // To replace each subgraph in the original graphs, we need to
2326 // map the APs on the original A/B graph with those in the
2327 // corresponding incoming subgraph, which are clones of the original:
2328 DGraph subGraphA = gA.extractSubgraph(site.getA());
2329 DGraph subGraphB = gB.extractSubgraph(site.getB());
2330
2331 // Here we create the two AP mappings we need: one for A other for B.
2332 LinkedHashMap<AttachmentPoint,AttachmentPoint>
2333 apMapA = new LinkedHashMap<AttachmentPoint,AttachmentPoint>();
2334 LinkedHashMap<AttachmentPoint,AttachmentPoint>
2335 apMapB = new LinkedHashMap<AttachmentPoint,AttachmentPoint>();
2336 for (Map.Entry<AttachmentPoint, AttachmentPoint> e :
2337 apmf.getChosenAPMapping().entrySet())
2338 {
2339 AttachmentPoint apOnA = e.getKey();
2340 AttachmentPoint apOnB = e.getValue();
2341
2342 // NB: assumption that vertex IDs are healthy, AND that order of APs
2343 // is retained upon cloning of the subgraph!
2344 AttachmentPoint apOnSubGraphA = subGraphA.getVertexWithId(
2345 apOnA.getOwner().getVertexId()).getAP(
2346 apOnA.getIndexInOwner());
2347 AttachmentPoint apOnSubGraphB = subGraphB.getVertexWithId(
2348 apOnB.getOwner().getVertexId()).getAP(
2349 apOnB.getIndexInOwner());
2350 apMapA.put(apOnA, apOnSubGraphB);
2351 apMapB.put(apOnB, apOnSubGraphA);
2352 }
2353
2354 // Now we do the actual replacement of subgraphs
2355 if (!gA.replaceSubGraph(site.getA(), subGraphB, apMapA, fragSpace))
2356 return false;
2357 if (!gB.replaceSubGraph(site.getB(), subGraphA, apMapB, fragSpace))
2358 return false;
2359
2360 return true;
2361 }
2362
2363//------------------------------------------------------------------------------
2364
2377 protected static boolean applySymmetry(boolean apclassImposed,
2378 double symmetryProbability, Randomizer randomizer)
2379 {
2380 boolean r = false;
2381 if (apclassImposed)
2382 {
2383 r = true;
2384 }
2385 else
2386 {
2387 r = randomizer.nextBoolean(symmetryProbability);
2388 }
2389 return r;
2390 }
2391
2392//------------------------------------------------------------------------------
2393
2406 public static boolean performMutation(DGraph graph, Monitor mnt,
2407 GAParameters settings) throws DENOPTIMException
2408 {
2409 // Get vertices that can be mutated: they can be part of subgraphs
2410 // embedded in templates. Here, we consider only single-vertexes sites.
2411 // So sites for ADDRINGFUSION mutation are not added here.
2412 List<Vertex> mutable = graph.getMutableSites(
2413 settings.getExcludedMutationTypes());
2414 // Now, add also the sites that involve multiple vertexes, such sites for
2415 // ADDFUSEDRING mutation.
2416 for (List<RelatedAPPair> siteCombination : EAUtils.searchRingFusionSites(
2417 graph, settings))
2418 {
2419 for (RelatedAPPair site : siteCombination)
2420 {
2421 Vertex vA = site.apA.getOwner();
2422 Vertex vB = site.apB.getOwner();
2423 if (!mutable.contains(vA))
2424 mutable.add(vA);
2425 if (!mutable.contains(vB))
2426 mutable.add(vB);
2427 }
2428 }
2429
2430 if (mutable.size() == 0)
2431 {
2433 String msg = "Graph has no mutable site. Mutation aborted.";
2434 settings.getLogger().info(msg);
2435 return false;
2436 }
2437 boolean doneMutation = true;
2438 int numberOfMutations = EAUtils.chooseNumberOfSitesToMutate(
2439 settings.getMultiSiteMutationWeights(),
2440 settings.getRandomizer().nextDouble());
2441 for (int i=0; i<numberOfMutations; i++)
2442 {
2443 if (i>0)
2444 {
2445 mutable = graph.getMutableSites(
2446 settings.getExcludedMutationTypes());
2447 break;
2448 }
2449 Vertex v = settings.getRandomizer().randomlyChooseOne(mutable);
2450 doneMutation = performMutation(v, mnt, settings);
2451 if(!doneMutation)
2452 break;
2453 }
2454 return doneMutation;
2455 }
2456
2457//------------------------------------------------------------------------------
2458
2472 public static boolean performMutation(Vertex vertex, Monitor mnt,
2473 GAParameters settings) throws DENOPTIMException
2474 {
2475 List<MutationType> mTypes = vertex.getMutationTypes(
2476 settings.getExcludedMutationTypes());
2477 if (mTypes.size() == 0)
2478 {
2479 return false;
2480 }
2481 MutationType mType = settings.getRandomizer().randomlyChooseOne(mTypes);
2482 return performMutation(vertex, mType, mnt, settings);
2483 }
2484
2485//------------------------------------------------------------------------------
2486
2498 public static boolean performMutation(Vertex vertex,
2499 MutationType mType, Monitor mnt, GAParameters settings)
2500 throws DENOPTIMException
2501 {
2502 DGraph c = vertex.getGraphOwner().clone();
2503 int pos = vertex.getGraphOwner().indexOf(vertex);
2504 try
2505 {
2506 return performMutation(vertex, mType, false, -1 ,-1, mnt, settings);
2507 } catch (IllegalArgumentException|NullPointerException e)
2508 {
2509 String debugFile = "failedMutation_" + mType
2510 + "_" + vertex.getVertexId() + "(" + pos + ")_"
2511 + settings.timeStamp + ".sdf";
2512 DenoptimIO.writeGraphToSDF(new File(debugFile), c, false,
2513 settings.getLogger(), settings.getRandomizer());
2514 settings.getLogger().warning("Fatal exception while performing "
2515 + "mutation. See file '" + debugFile + "' to reproduce the "
2516 + "problem.");
2517 throw e;
2518 }
2519 }
2520
2521//------------------------------------------------------------------------------
2522
2548 public static boolean performMutation(Vertex vertex,
2549 MutationType mType, boolean force, int chosenVrtxIdx,
2550 int chosenApId, Monitor mnt, GAParameters settings)
2551 throws DENOPTIMException
2552 {
2554 if (settings.containsParameters(ParametersType.FS_PARAMS))
2555 {
2556 fsParams = (FragmentSpaceParameters)settings.getParameters(
2558 }
2559
2560 DGraph graph = vertex.getGraphOwner();
2561 if (graph == null)
2562 {
2564 settings.getLogger().info("Vertex has no owner - "
2565 + "Mutation aborted");
2566 return false;
2567 }
2568 if (!vertex.getMutationTypes(settings.getExcludedMutationTypes())
2569 .contains(mType))
2570 {
2572 settings.getLogger().info("Vertex does not allow mutation type "
2573 + "'" + mType + "' - Mutation aborted");
2574 return false;
2575 }
2576
2577 int graphId = graph.getGraphId();
2578 int positionOfVertex = graph.indexOf(vertex);
2579 //NB: since we have renumbered the vertexes, we use the old vertex ID
2580 // when reporting what vertex is being mutated. Also, note that the
2581 // identity of the candidate is already in the graph's local msg.
2582 String mutantOrigin = graph.getLocalMsg() + "|"
2583 + mType + "|"
2584 + vertex.getProperty(DENOPTIMConstants.STOREDVID)
2585 + " (" + positionOfVertex + ")";
2586 graph.setLocalMsg(mutantOrigin);
2587
2588 boolean done = false;
2589 switch (mType)
2590 {
2591 case CHANGEBRANCH:
2592 done = rebuildBranch(vertex, force, chosenVrtxIdx, chosenApId,
2593 settings);
2594 if (!done)
2595 mnt.increase(
2597 break;
2598
2599 case CHANGELINK:
2600 done = substituteLink(vertex, chosenVrtxIdx, mnt,
2601 fsParams.getFragmentSpace());
2602 if (!done)
2603 mnt.increase(
2605 break;
2606
2607 case DELETELINK:
2608 done = deleteLink(vertex, chosenApId, mnt,
2609 fsParams.getFragmentSpace());
2610 if (!done)
2611 mnt.increase(
2613 break;
2614
2615 case DELETECHAIN:
2616 done = deleteChain(vertex, mnt, fsParams.getFragmentSpace());
2617 if (!done)
2618 mnt.increase(
2620 break;
2621
2622 case ADDLINK:
2623 if (chosenApId < 0)
2624 {
2625 List<Integer> candidates = new ArrayList<Integer>();
2626 for (Vertex c : vertex.getChilddren())
2627 {
2628 candidates.add(c.getEdgeToParent().getSrcAP()
2629 .getIndexInOwner());
2630 }
2631 if (candidates.size() == 0)
2632 {
2633 mnt.increase(
2635 break;
2636 }
2637 chosenApId = settings.getRandomizer().randomlyChooseOne(
2638 candidates);
2639 }
2640 done = extendLink(vertex, chosenApId, chosenVrtxIdx, mnt,
2641 fsParams.getFragmentSpace());
2642 if (!done)
2643 mnt.increase(
2645 break;
2646
2647 case ADDRING:
2648 done = addRing(vertex, mnt, false, fsParams.getFragmentSpace(),
2649 settings);
2650 if (!done)
2652 break;
2653
2654 case ADDFUSEDRING:
2655 done = addFusedRing(vertex, mnt, false, fsParams.getFragmentSpace(),
2656 settings);
2657 if (!done)
2659 break;
2660
2661 case EXTEND:
2662 vertex.getGraphOwner().removeCappingGroupsOn(vertex);
2663 done = extendGraph(vertex, false, false, force, chosenVrtxIdx,
2664 chosenApId, settings);
2665 if (!done)
2667 break;
2668
2669 case DELETE:
2670 done = deleteFragment(vertex);
2671 if (!done)
2673 break;
2674 }
2675
2676 String msg = "Mutation '" + mType.toString() + "' on vertex "
2677 + vertex.toString() + " (position " + positionOfVertex
2678 + " in graph " + graphId+"): ";
2679 if (done)
2680 {
2681 msg = msg + "done";
2682
2683 // Triggers reconstruction of the molecular representation of
2684 // templates upon changes of the embedded graph
2685 if (graph.getTemplateJacket() != null)
2686 {
2688 }
2689 } else {
2690 msg = msg + "unsuccessful";
2691 }
2692 settings.getLogger().info(msg);
2693
2694 return done;
2695 }
2696
2697//------------------------------------------------------------------------------
2698
2699
2700
2701}
General set of constants used in DENOPTIM.
static final String VRTPROPBRIDGELENGTH
Name of Vertex property used to record how long a ring-closing bridge is.
static final String VRTPROPBRIDGEEND_B
Name of Vertex property used to record which AP is selected for bridge formation on side 'B'.
static final Object STOREDVID
Key of the property remembering vertex IDs.
static final String VRTPROPBRIDGEEND_A
Name of Vertex property used to record which AP is selected for bridge formation on side 'A'.
SMARTS-based rules to identify potential bridge head atoms for ring fusion operations.
An utility class to encapsulate the search for an AttachmentPoint-AttachmentPoint mapping.
APMapping getChosenAPMapping()
Returns the AttachmentPoint-AttachmentPoint mapping chosen among the possible mappings.
boolean foundMapping()
Returns true if any mapping has been found.
Class defining a space of building blocks.
boolean imposeSymmetryOnAPsOfClass(APClass apClass)
Checks if the symmetry settings impose use of symmetry on attachment points of the given AP class.
Parameters defining the fragment space.
Data structure containing information that identifies a single AP of a vertex/fragment.
Helper methods for the genetic algorithm.
Definition: EAUtils.java:102
static double getGrowthByLevelProbability(int level, GAParameters settings)
Calculates the probability of adding a fragment to the given level.
Definition: EAUtils.java:2277
static int chooseNumberOfSitesToMutate(double[] multiSiteMutationProb, double hit)
Takes a decision on how many sites to mutate on a candidate.
Definition: EAUtils.java:219
static List< Vertex > getUsableAliphaticBridges(APClass apcA, APClass apcB, int[] allowedLengths, FragmentSpace fragSpace)
Finds all vertexes that can be used as aliphatic bridge.
Definition: EAUtils.java:3084
static double getCrowdingProbability(AttachmentPoint ap, GAParameters settings)
Calculated the probability of using and attachment point rooted on an atom that is holding other atta...
Definition: EAUtils.java:2300
static List< List< RelatedAPPair > > searchRingFusionSites(DGraph graph, GAParameters gaParams)
Definition: EAUtils.java:2517
static int getCrowdedness(AttachmentPoint ap)
Calculate the current crowdedness of the given attachment point.
Definition: EAUtils.java:2345
static List< Vertex > getUsableAromaticBridges(String elInIncomingFrag, int[] allowedLengths, FragmentSpace fragSpace)
Finds all vertexes that can be used as aromatic bridge, i.e., can be used to create an aromatic ring ...
Definition: EAUtils.java:3040
static double getMolSizeProbability(DGraph graph, GAParameters settings)
Calculated the probability of extending a graph based on the current size of the molecular representa...
Definition: EAUtils.java:2200
Private class representing a selected closable chain of fragments.
FragForClosabChains(ArrayList< ClosableChain > compatChains, ArrayList< ClosableChain > incompatChains, ArrayList< Integer > fragIds)
Collection of operators meant to alter graphs and associated utilities.
static IdFragmentAndAP getFrgApForSrcAp(Vertex curVertex, int dapidx, FragmentSpace fragSpace)
Select a compatible fragment for the given attachment point.
static boolean performMutation(Vertex vertex, MutationType mType, boolean force, int chosenVrtxIdx, int chosenApId, Monitor mnt, GAParameters settings)
Mutates the given vertex according to the given mutation type, if possible.
static boolean extendGraph(Vertex curVrtx, boolean extend, boolean symmetryOnAps, boolean force, int chosenVrtxIdx, int chosenApId, GAParameters settings)
function that will keep extending the graph.
static boolean extendLink(Vertex vertex, int chosenAPId, Monitor mnt, FragmentSpace fragSpace)
Inserts a vertex in between two connected vertexes that are identified by the one vertex holding the ...
static List< XoverSite > locateCompatibleXOverPoints(DGraph graphA, DGraph graphB, FragmentSpace fragSpace, int maxSizeXoverSubGraph)
Identify crossover sites, i.e., subgraphs that can be swapped between two graphs (i....
static boolean applySymmetry(boolean apclassImposed, double symmetryProbability, Randomizer randomizer)
Decides whether to apply constitutional symmetry or not.
static void checkAndAddXoverSites(FragmentSpace fragSpace, List< Vertex > subGraphA, List< Vertex > subGraphB, CrossoverType xoverType, List< XoverSite > collector)
Here we check that the given subgraphs have a mapping that allows to swap them, and full fill any oth...
static boolean performMutation(Vertex vertex, MutationType mType, Monitor mnt, GAParameters settings)
Mutates the given vertex according to the given mutation type, if possible.
static boolean substituteLink(Vertex vertex, int chosenVrtxIdx, Monitor mnt, FragmentSpace fragSpace)
Substitutes a vertex while keeping its surrounding.
static boolean isCrossoverPossible(Edge eA, Edge eB, FragmentSpace fragSpace)
Evaluate AP class-compatibility of a pair of edges with respect to crossover.
static void processCombinationOfEndPoints(Vertex[] pair, List< Vertex[]> cominationOfEnds, List< XoverSite > collector, FragmentSpace fragSpace)
Given a pair of seed vertexes that define where a pair of subgraphs stars in the corresponding origin...
static boolean attachFragmentInClosableChain(Vertex curVertex, int dapidx, DGraph molGraph, ArrayList< Long > addedVertices, GAParameters settings)
static void processPermutationOfEndPoints(Vertex[] pair, List< Vertex[]> chosenSequenceOfEndpoints, List< XoverSite > collector, FragmentSpace fragSpace)
Given a pair of seed vertexes that define where a pair of subgraphs stars in the corresponding origin...
static boolean extendGraph(Vertex curVertex, boolean extend, boolean symmetryOnAps, GAParameters settings)
function that will keep extending the graph according to the growth/substitution probability.
static ArrayList< FragForClosabChains > getFragmentForClosableChain(Vertex curVertex, int dapidx, DGraph molGraph)
Method to select fragments that increase the likeliness of generating closable chains.
static boolean performMutation(Vertex vertex, Monitor mnt, GAParameters settings)
Tries to do mutate the given vertex.
static IdFragmentAndAP getFrgApForSrcAp(Vertex curVertex, int dapidx, int chosenVrtxIdx, int chosenApId, FragmentSpace fragSpace)
Select a compatible fragment for the given attachment point.
static IdFragmentAndAP getRCVForSrcAp(Vertex curVertex, int dapidx, FragmentSpace fragSpace)
Select a compatible ring-closing vertex for the given attachment point.
static boolean deleteFragment(Vertex vertex)
Deletion mutation removes the vertex and also the symmetric partners on its parent.
static boolean rebuildBranch(Vertex vertex, boolean force, int chosenVrtxIdx, int chosenApId, GAParameters settings)
Substitutes a vertex and any child branch.
static boolean addFusedRing(Vertex vertex, Monitor mnt, boolean force, FragmentSpace fragSpace, GAParameters settings)
Tries to add a fused ring using a pair of free APs, one of which on the given vertex.
static boolean deleteLink(Vertex vertex, int chosenVrtxIdx, Monitor mnt, FragmentSpace fragSpace)
Removes a vertex while merging as many of the child branches into the parent vertex.
static boolean extendLink(Vertex vertex, int chosenAPId, int chosenNewVrtxId, Monitor mnt, FragmentSpace fragSpace)
Inserts a vertex in between two connected vertexes that are identified by the one vertex holding the ...
static boolean performMutation(DGraph graph, Monitor mnt, GAParameters settings)
Tries to do mutate the given graph.
static boolean addRing(Vertex vertex, Monitor mnt, boolean force, FragmentSpace fragSpace, GAParameters settings)
Tries to use any free AP of the given vertex to close ring in the graph by adding a chord.
static boolean extendLink(Edge edge, int chosenBBIdx, Monitor mnt, FragmentSpace fragSpace)
Replace an edge with two edges with a new vertex in between, thus inserting a vertex in between two d...
static boolean deleteChain(Vertex vertex, Monitor mnt, FragmentSpace fragSpace)
Deletes the given vertex and all other vertexes that are not connected to more than 2 non-capping gro...
static boolean performCrossover(XoverSite site, FragmentSpace fragSpace)
Performs the crossover that swaps the two subgraphs defining the given XoverSite.
This class collects the data identifying the subgraphs that would be swapped by a crossover event.
Definition: XoverSite.java:36
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
boolean equals(Object o)
Definition: APClass.java:516
Class representing a mapping between attachment points (APs).
Definition: APMapping.java:42
LinkedHashMap< Integer, Integer > toIntMappig()
Produces an index-based version of this mapping where each index represents the attachment point as i...
Definition: APMapping.java:71
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.
APClass getAPClass()
Returns the Attachment Point class.
boolean isAvailable()
Check availability of this attachment point.
Edge getEdgeUserThroughout()
Gets the edge that is using this AP, or null if no edge is using this AP.
Container for the list of vertices and the edges that connect them.
Definition: DGraph.java:102
boolean removeVertexAndWeld(Vertex vertex, FragmentSpace fragSpace)
Remove a given vertex belonging to this graph and re-connects the resulting graph branches as much as...
Definition: DGraph.java:1423
boolean replaceVertex(Vertex vertex, int bbId, BBType bbt, LinkedHashMap< Integer, Integer > apIdMap, FragmentSpace fragSpace)
Replaced a given vertex belonging to this graph with a new vertex generated specifically for this pur...
Definition: DGraph.java:2487
Vertex getVertexWithId(long vid)
Searches for a vertex with the given identifier.
Definition: DGraph.java:2811
DGraph extractSubgraph(int index)
Creates a new graph that corresponds to the subgraph of this graph when exploring the spanning tree f...
Definition: DGraph.java:4487
boolean isIsomorphicTo(DGraph other)
Checks if this graph is "DENOPTIM-isomorphic" to the other one given.
Definition: DGraph.java:3682
ArrayList< Ring > getRingsInvolvingVertex(Vertex v)
Returns the list of rings that include the given vertex in their fundamental cycle.
Definition: DGraph.java:1054
void getChildrenTree(Vertex vertex, List< Vertex > children)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:3000
String getLocalMsg()
Definition: DGraph.java:287
void removeVertex(Vertex vertex)
Remove a vertex from this graph.
Definition: DGraph.java:1347
int indexOf(Vertex v)
Returns the index of a vertex in the list of vertices of this graph.
Definition: DGraph.java:2798
Vertex getVertexAtPosition(int pos)
Returns the vertex that is in the given position of the list of vertices belonging to this graph.
Definition: DGraph.java:2743
Vertex getDeepestAmongThese(List< Vertex > list)
Identify the oldest ancestor (i.e., most great grandparent) in the given collection.
Definition: DGraph.java:3352
String getBranchIdOfVertexAsStr(Vertex v)
Returns the branch identifier as a literal string.
Definition: DGraph.java:3207
List< AttachmentPoint > getAvailableAPsThroughout()
Returns the list of attachment points contained in this graph that are available throughout the templ...
Definition: DGraph.java:4240
void appendVertexOnAP(AttachmentPoint srcAP, AttachmentPoint trgAP)
Append a vertex to this graph: adds the new vertex to the list of vertices belonging to the graph,...
Definition: DGraph.java:6005
List< AttachmentPoint > getInterfaceAPs(List< Vertex > subGraphB)
Searches for all AttachmentPoints that represent the interface between a subgraph,...
Definition: DGraph.java:7376
DGraph clone()
Returns almost "deep-copy" of this graph.
Definition: DGraph.java:3415
boolean replaceSubGraph(List< Vertex > subGrpVrtxs, DGraph incomingGraph, LinkedHashMap< AttachmentPoint, AttachmentPoint > apMap, FragmentSpace fragSpace)
Replaced the subgraph represented by a given collection of vertices that belong to this graph.
Definition: DGraph.java:1909
int getLevel(Vertex v)
Calculates the level of a vertex in this graph.
Definition: DGraph.java:5555
void addSymmetricSetOfVertices(SymmetricVertexes symSet)
Adds a symmetric set of vertices to this graph.
Definition: DGraph.java:889
SymmetricVertexes getSymSetForVertex(Vertex v)
Returns the set of vertexes symmetric to the given one.
Definition: DGraph.java:861
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:7411
void addRing(Ring ring)
Definition: DGraph.java:1258
boolean hasSymmetryInvolvingVertex(Vertex v)
Definition: DGraph.java:301
boolean insertVertex(Edge edge, int bbId, BBType bbt, LinkedHashMap< AttachmentPoint, Integer > apMap, FragmentSpace fragSpace)
Inserts a given vertex in between two vertices connected by the given edge.
Definition: DGraph.java:2589
void getChildTreeLimited(Vertex vertex, List< Vertex > children, boolean stopBeforeRCVs)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:3257
boolean removeBranchStartingAt(Vertex v, boolean symmetry)
Deletes the branch, i.e., the specified vertex and its children.
Definition: DGraph.java:5017
Template getTemplateJacket()
Definition: DGraph.java:7195
boolean removeChainUpToBranching(Vertex v, FragmentSpace fragSpace)
Mutates the graph by removing the chain where a given vertex is located up to the first branching (i....
Definition: DGraph.java:5107
void setLocalMsg(String msg)
Definition: DGraph.java:279
boolean isIsostructuralTo(DGraph other)
Checks if this graph is "DENOPTIM-isostructural" to the other one given.
Definition: DGraph.java:3809
This class represents the edge between two vertices.
Definition: Edge.java:38
AttachmentPoint getTrgAP()
Definition: Edge.java:115
long getSrcVertex()
Definition: Edge.java:122
AttachmentPoint getSrcAP()
Definition: Edge.java:94
APClass getTrgAPClass()
Definition: Edge.java:157
APClass getSrcAPClass()
Definition: Edge.java:150
This class represents the closure of a ring in a spanning tree.
Definition: Ring.java:40
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...
ContractLevel getContractLevel()
Returns the contract level of this template, i.e., to what extent the content of this template can be...
Definition: Template.java:203
void clearIAtomContainer()
Removes the molecular representation.
Definition: Template.java:600
A vertex is a data structure that has an identity and holds a list of AttachmentPoints.
Definition: Vertex.java:61
abstract Vertex clone()
Returns a deep-copy of this vertex.
List< AttachmentPoint > getAPsWithAPClassStartingWith(String root)
Finds only APs that have APClass starting with the given string.
Definition: Vertex.java:260
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
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
Object getProperty(Object property)
Definition: Vertex.java:1223
abstract int getHeavyAtomsCount()
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
ClosableChain represents a chain of fragments (chain links) that is closable (or candidate closable).
This object represents a path in a DGraph.
int getPathLength()
Returns the length of the list of edges involved in this path.
List< Vertex > getVertecesPath()
Returns the list of verteces involved.
A class for iterating over sets of ring combinations generated by considering any constrain and setti...
The RingClosingAttractor represent the available valence/connection that allows to close a ring.
static final Map< APClass, APClass > RCAAPCMAP
Recognized APClasses on RingClosingAttractor and compatible types.
Parameters and setting related to handling ring closures.
Utility methods for input/output.
static void writeGraphToSDF(File file, DGraph graph, boolean append, boolean make3D, Logger logger, Randomizer randomizer)
Writes the graph to SDF file.
A collection of counters user to count actions taken by the evolutionary algorithm.
Definition: Monitor.java:37
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.
RunTimeParameters getParameters(ParametersType type)
Randomizer getRandomizer()
Returns the current program-specific randomizer.
Parameters for genetic algorithm.
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
Tool to generate random numbers and random decisions.
Definition: Randomizer.java:35
boolean nextBoolean()
Returns the next pseudo-random, uniformly distributed boolean value from this random number generator...
public< T > T randomlyChooseOne(Collection< T > c)
Chooses one member among the given collection.
Enum specifying to what extent the template's inner graph can be changed.
Definition: Template.java:104
FIXED
Inner graphs are effectively equivalent to the Fragment class, as no change in the inner structure is...
Definition: Template.java:116
FIXED_STRUCT
Inner graph keep the same structure, but the identify of vertices can change.
Definition: Template.java:124
The type of building block.
Definition: Vertex.java:86
static BBType parseInt(int i)
Translates the integer into the enum.
Definition: Vertex.java:103
Identifier of a counter.
Definition: CounterID.java:29
FS_PARAMS
Parameters pertaining the definition of the fragment space.
RC_PARAMS
Parameters pertaining to ring closures in graphs.
Types of crossover defined.
SUBGRAPH
Swaps a portion of a branch trying to retain cyclicity.
BRANCH
Swaps the entire branch starting from a given vertex.
Types of mutation defined in relation to what happens to the target vertex (i.e., the actual mutation...
DELETECHAIN
Removes a vertex and all its neighbors recursively until a branching point, i.e., until a vertex that...