$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);
219 PathSubGraph pathB = new PathSubGraph(vB, endOnB);
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 = null;
451 try {
452 pathA = new PathSubGraph(vA, endOnA);
453 } catch (DENOPTIMException e) {
454 e.printStackTrace();
455 }
456 PathSubGraph pathB = null;
457 try {
458 pathB = new PathSubGraph(vB, endOnB);
459 } catch (DENOPTIMException e) {
460 e.printStackTrace();
461 }
462 subGraphEndInA.add(endOnA);
463 subGraphEndInB.add(endOnB);
464 alreadyIncludedFromA.addAll(pathA.getVertecesPath());
465 alreadyIncludedFromB.addAll(pathB.getVertecesPath());
466 }
467 ArrayList<Vertex> subGraphA = new ArrayList<Vertex>();
468 subGraphA.add(vA);
469 if (!subGraphEndInA.contains(vA))
470 gA.getChildTreeLimited(vA, subGraphA, subGraphEndInA, true);
471
472 ArrayList<Vertex> subGraphB = new ArrayList<Vertex>();
473 subGraphB.add(vB);
474 if (!subGraphEndInB.contains(vB))
475 gB.getChildTreeLimited(vB, subGraphB, subGraphEndInB, true);
476
477 // The two subgraphs must not be isomorfic to prevent unproductive crossover
478 if (subGraphA.size()>1 && subGraphB.size()>1)
479 {
480 DGraph subGraphCloneA = gA.extractSubgraph(subGraphA);
481 DGraph subGraphCloneB = gB.extractSubgraph(subGraphB);
482 if (subGraphCloneA.isIsomorphicTo(subGraphCloneB))
483 return;
484 } else {
485 if (subGraphA.get(0).sameAs(subGraphB.get(0), new StringBuilder()))
486 return;
487 }
488
489 checkAndAddXoverSites(fragSpace, subGraphA, subGraphB,
490 CrossoverType.SUBGRAPH, collector);
491 }
492
493//------------------------------------------------------------------------------
494
504 private static void checkAndAddXoverSites(FragmentSpace fragSpace,
505 List<Vertex> subGraphA,
506 List<Vertex> subGraphB, CrossoverType xoverType,
507 List<XoverSite> collector)
508 {
509 DGraph gOwnerA = subGraphA.get(0).getGraphOwner();
510 DGraph gOwnerB = subGraphB.get(0).getGraphOwner();
511
512 // What APs need to find a corresponding AP in the other
513 // subgraph in order to allow swapping?
514 List<AttachmentPoint> needyAPsA = gOwnerA.getInterfaceAPs(
515 subGraphA);
516 List<AttachmentPoint> allAPsA = gOwnerA.getSubgraphAPs(
517 subGraphA);
518 List<AttachmentPoint> needyAPsB = gOwnerB.getInterfaceAPs(
519 subGraphB);
520 List<AttachmentPoint> allAPsB = gOwnerB.getSubgraphAPs(
521 subGraphB);
522 if (allAPsA.size() < needyAPsB.size()
523 || allAPsB.size() < needyAPsA.size())
524 {
525 // Impossible to satisfy needy APs. Crossover site is not usable.
526 return;
527 }
528
529 // Shortcut: since the compatibility of one AP that is needed to do
530 // branch swapping is guaranteed by the identification of the seeds of
531 // swappable subgraphs, we can avoid searching for a valid A mapping
532 // when the graphs are not embedded. This because any AP that is not
533 // the one connecting the subgraph to the parent can be left free or
534 // removed without side effects on templates that embed the graph
535 // because there is no such template.
536 Template jacketTmplA = gOwnerA.getTemplateJacket();
537 Template jacketTmplB = gOwnerB.getTemplateJacket();
538 if (xoverType == CrossoverType.BRANCH
539 && jacketTmplA==null
540 && jacketTmplB==null)
541 {
542 XoverSite xos = new XoverSite(subGraphA, needyAPsA, subGraphB,
543 needyAPsB, xoverType);
544 if (!collector.contains(xos))
545 collector.add(xos);
546 return;
547 }
548
549 if ((jacketTmplA!=null && jacketTmplA.getContractLevel()
551 || (jacketTmplB!=null && jacketTmplB.getContractLevel()
553 {
554 // Avoid to alter cyclicity of inner graphs
555 for (Vertex v : subGraphA)
556 if (v.isRCV() && !gOwnerA.getRingsInvolvingVertex(v).isEmpty())
557 return;
558 for (Vertex v : subGraphB)
559 if (v.isRCV() && !gOwnerB.getRingsInvolvingVertex(v).isEmpty())
560 return;
561
562 // Avoid to change the structure of inner graphs
563 DGraph subGraphCloneA = gOwnerA.extractSubgraph(subGraphA);
564 DGraph subGraphCloneB = gOwnerB.extractSubgraph(subGraphB);
565 if (!subGraphCloneA.isIsostructuralTo(subGraphCloneB))
566 return;
567 }
568
569 // Retain connection to parent to keep directionality of spanning tree!
570 // To this end, identify the seed of the subgraphs...
571 Vertex seedOnA = gOwnerA.getDeepestAmongThese(subGraphA);
572 Vertex seedOnB = gOwnerB.getDeepestAmongThese(subGraphB);
573 //...and ensure we use the same APs to link to the parent graph.
574 APMapping fixedRootAPs = new APMapping();
575 fixedRootAPs.put(seedOnA.getEdgeToParent().getTrgAP(),
576 seedOnB.getEdgeToParent().getTrgAP());
577
578 APMapFinder apmf = new APMapFinder(fragSpace,
579 allAPsA, needyAPsA, allAPsB, needyAPsB,
580 fixedRootAPs,
581 false, // false: we stop at the first good mapping
582 true, // true: only complete mapping
583 false); // false: free APs are not compatible by default
584 if (apmf.foundMapping())
585 {
586 XoverSite xos = new XoverSite(subGraphA, needyAPsA,
587 subGraphB, needyAPsB, xoverType);
588 if (!collector.contains(xos))
589 collector.add(xos);
590 }
591 }
592
593//------------------------------------------------------------------------------
594
606 private static boolean isCrossoverPossible(Edge eA, Edge eB,
607 FragmentSpace fragSpace)
608 {
609 APClass apClassSrcA = eA.getSrcAPClass();
610 APClass apClassTrgA = eA.getTrgAPClass();
611 APClass apClassSrcB = eB.getSrcAPClass();
612 APClass apClassTrgB = eB.getTrgAPClass();
613
614 if (apClassSrcA.isCPMapCompatibleWith(apClassTrgB, fragSpace))
615 {
616 if (apClassSrcB.isCPMapCompatibleWith(apClassTrgA, fragSpace))
617 {
618 return true;
619 }
620 }
621 return false;
622 }
623
624//------------------------------------------------------------------------------
625
637 protected static boolean deleteLink(Vertex vertex,
638 int chosenVrtxIdx, Monitor mnt, FragmentSpace fragSpace)
639 throws DENOPTIMException
640 {
641 DGraph graph = vertex.getGraphOwner();
642 boolean done = graph.removeVertexAndWeld(vertex, fragSpace);
643 if (!done)
644 {
646 }
647 return done;
648 }
649
650//------------------------------------------------------------------------------
651
668 protected static boolean substituteLink(Vertex vertex,
669 int chosenVrtxIdx, Monitor mnt, FragmentSpace fragSpace)
670 throws DENOPTIMException
671 {
672 //TODO: for reproducibility, the AP mapping should become an optional
673 // parameter: if given we try to use it, if not given, GraphLinkFinder
674 // will try to find a suitable mapping.
675
676 GraphLinkFinder glf = null;
677 if (chosenVrtxIdx<0)
678 {
679 glf = new GraphLinkFinder(fragSpace, vertex);
680 } else {
681 glf = new GraphLinkFinder(fragSpace, vertex, chosenVrtxIdx);
682 }
683 if (!glf.foundAlternativeLink())
684 {
686 return false;
687 }
688
689 DGraph graph = vertex.getGraphOwner();
690 boolean done = graph.replaceVertex(vertex,
694 fragSpace);
695 if (!done)
696 {
697 mnt.increase(
699 }
700 return done;
701 }
702
703//------------------------------------------------------------------------------
704
720 public static boolean extendLink(Vertex vertex,
721 int chosenAPId, Monitor mnt, FragmentSpace fragSpace)
722 throws DENOPTIMException
723 {
724 return extendLink(vertex, chosenAPId, -1 , mnt, fragSpace);
725 }
726
727//------------------------------------------------------------------------------
728
746 public static boolean extendLink(Vertex vertex, int chosenAPId,
747 int chosenNewVrtxId, Monitor mnt, FragmentSpace fragSpace)
748 throws DENOPTIMException
749 {
750 AttachmentPoint ap = vertex.getAP(chosenAPId);
751 if (ap == null)
752 {
753 throw new DENOPTIMException("No AP "+chosenAPId+" in vertex "
754 +vertex+".");
755 }
757
758 if (e == null)
759 {
760 throw new DENOPTIMException("AP "+chosenAPId+" in vertex "
761 +vertex+" has no edge user.");
762 }
763 if (e.getSrcAP().getOwner() != vertex)
764 {
765 throw new DENOPTIMException("Request to extend a link from a child "
766 + "vertex (AP "+chosenAPId+" of vertex "+vertex+").");
767 }
768 return extendLink(e, chosenNewVrtxId, mnt, fragSpace);
769 }
770
771//------------------------------------------------------------------------------
772
785 public static boolean extendLink(Edge edge, int chosenBBIdx,
786 Monitor mnt, FragmentSpace fragSpace) throws DENOPTIMException
787 {
788 //TODO: for reproducibility, the AP mapping should become an optional
789 // parameter: if given we try to use it, if not given we GraphLinkFinder
790 // will try to find a suitable mapping.
791
792 GraphLinkFinder glf = null;
793 if (chosenBBIdx < 0)
794 {
795 glf = new GraphLinkFinder(fragSpace, edge);
796 } else {
797 glf = new GraphLinkFinder(fragSpace, edge,chosenBBIdx);
798 }
799 if (!glf.foundAlternativeLink())
800 {
802 return false;
803 }
804
805 // Need to convert the mapping to make it independent from the instance
806 // or the new link.
807 LinkedHashMap<AttachmentPoint,Integer> apMap =
808 new LinkedHashMap<AttachmentPoint,Integer>();
809 for (Entry<AttachmentPoint, AttachmentPoint> e :
810 glf.getChosenAPMapping().entrySet())
811 {
812 apMap.put(e.getKey(), e.getValue().getIndexInOwner());
813 }
814
815 DGraph graph = edge.getSrcAP().getOwner().getGraphOwner();
816 boolean done = graph.insertVertex(edge,
819 apMap, fragSpace);
820 if (!done)
821 {
822 mnt.increase(
824 }
825 return done;
826 }
827
828//------------------------------------------------------------------------------
829
851 protected static boolean rebuildBranch(Vertex vertex,
852 boolean force, int chosenVrtxIdx, int chosenApId,
853 GAParameters settings) throws DENOPTIMException
854 {
855 DGraph g = vertex.getGraphOwner();
856
857 // first get the edge with the parent
858 Edge e = vertex.getEdgeToParent();
859 if (e == null)
860 {
861 String msg = "Program Bug in substituteFragment: Unable to locate "
862 + "parent edge for vertex "+vertex+" in graph "+g;
863 settings.getLogger().log(Level.SEVERE, msg);
864 throw new DENOPTIMException(msg);
865 }
866
867 // vertex id of the parent
868 long pvid = e.getSrcVertex();
869 Vertex parentVrt = g.getVertexWithId(pvid);
870
871 // Need to remember symmetry because we are deleting the symm. vertices
872 boolean symmetry = g.hasSymmetryInvolvingVertex(vertex);
873
874 // delete the vertex and its children and all its symmetric partners
875 deleteFragment(vertex);
876
877 // extend the graph at this vertex but without recursion
878 return extendGraph(parentVrt,false,symmetry,force,chosenVrtxIdx,
879 chosenApId, settings);
880 }
881
882//------------------------------------------------------------------------------
883
892 protected static boolean deleteFragment(Vertex vertex)
893 throws DENOPTIMException
894 {
895 long vid = vertex.getVertexId();
896 DGraph molGraph = vertex.getGraphOwner();
897
898 if (molGraph.hasSymmetryInvolvingVertex(vertex))
899 {
900 List<Vertex> toRemove = new ArrayList<Vertex>();
901 toRemove.addAll(molGraph.getSymSetForVertex(vertex));
902 for (Vertex v : toRemove)
903 {
904 molGraph.removeBranchStartingAt(v);
905 }
906 }
907 else
908 {
909 molGraph.removeBranchStartingAt(vertex);
910 }
911
912 if (molGraph.getVertexWithId(vid) == null && molGraph.getVertexCount() > 1)
913 return true;
914
915 return false;
916 }
917
918//------------------------------------------------------------------------------
919
932 protected static boolean deleteChain(Vertex vertex, Monitor mnt,
933 FragmentSpace fragSpace) throws DENOPTIMException
934 {
935 long vid = vertex.getVertexId();
936 DGraph molGraph = vertex.getGraphOwner();
937
938 if (molGraph.hasSymmetryInvolvingVertex(vertex))
939 {
940 List<Vertex> toRemove = new ArrayList<Vertex>();
941 toRemove.addAll(molGraph.getSymSetForVertex(vertex));
942 for (Vertex v : toRemove)
943 {
944 if (!v.getMutationTypes(new ArrayList<MutationType>())
945 .contains(MutationType.DELETECHAIN))
946 continue;
947 molGraph.removeChainUpToBranching(v, fragSpace);
948 }
949 }
950 else
951 {
952 molGraph.removeChainUpToBranching(vertex, fragSpace);
953 }
954
955 if (molGraph.getVertexWithId(vid) == null && molGraph.getVertexCount() > 1)
956 return true;
957 return false;
958 }
959
960//------------------------------------------------------------------------------
961
977 protected static boolean addRing(Vertex vertex, Monitor mnt, boolean force,
978 FragmentSpace fragSpace, GAParameters settings)
979 throws DENOPTIMException
980 {
981 // get settings //TODO: this should happen inside RunTimeParameters
983 if (settings.containsParameters(ParametersType.RC_PARAMS))
984 {
985 rcParams = (RingClosureParameters)settings.getParameters(
987 }
988 Randomizer rng = settings.getRandomizer();
989
990 // First of all we remove capping groups in the graph
991 vertex.getGraphOwner().removeCappingGroups();
992
993 List<AttachmentPoint> freeeAPs = vertex.getFreeAPThroughout();
994 if (freeeAPs.size()==0)
995 {
997 return false;
998 }
999 DGraph originalGraph = vertex.getGraphOwner();
1000 DGraph tmpGraph = originalGraph.clone();
1001
1002 Vertex headVrtx = tmpGraph.getVertexAtPosition(originalGraph.indexOf(
1003 vertex));
1004
1005 // Define the set of rings on the cloned (tmp) graph
1006 List<Ring> setOfRingsOnTmpGraph = null;
1007 for (AttachmentPoint srcAP : headVrtx.getFreeAPThroughout())
1008 {
1009 APClass apc = srcAP.getAPClass();
1010
1011 // Skip if the APClass is not allowed to form ring closures
1012 if (!fragSpace.getRCCompatibilityMatrix().containsKey(apc))
1013 {
1014 continue;
1015 }
1016 List<APClass> rcTrgAPCs = fragSpace.getRCCompatibilityMatrix().get(
1017 apc);
1018
1019 // NB: the fragment space may or may not have a RCV for this AP
1020 Vertex rcvOnSrcAP = null;
1021 List<Vertex> candidateRCVs = fragSpace.getRCVsForAPClass(apc);
1022 boolean rcvIsChosenArbitrarily = false;
1023 if (candidateRCVs.size()>0)
1024 {
1025 rcvOnSrcAP = rng.randomlyChooseOne(candidateRCVs);
1026 } else {
1027 rcvIsChosenArbitrarily = true;
1028 rcvOnSrcAP = fragSpace.getPolarizedRCV(true);
1029 }
1030
1031 // Add the RCV on this AP
1032 List<Vertex> rcvAddedToGraph = new ArrayList<Vertex>();
1033 tmpGraph.appendVertexOnAP(srcAP, rcvOnSrcAP.getAP(0));
1034 rcvAddedToGraph.add(rcvOnSrcAP);
1035
1036 // Add a few RCVs in the rest of the system
1037 // WARNING: hard-coded max number of attempts. It should not be too
1038 // high to prevent combinatorial explosion.
1039 for (int i=0; i<20; i++)
1040 {
1041 // Do it only on APs that APClass-compatible with chord formation
1042 List<AttachmentPoint> apsToTry =
1043 tmpGraph.getAvailableAPsThroughout();
1044 int numberOfAttempts = apsToTry.size();
1045 AttachmentPoint trgAP = null;
1046 for (int iap=0; iap<numberOfAttempts; iap++)
1047 {
1048 AttachmentPoint candidate = rng.randomlyChooseOne(apsToTry);
1049 if (rcTrgAPCs.contains(candidate.getAPClass()))
1050 {
1051 trgAP = candidate;
1052 break;
1053 }
1054 apsToTry.remove(trgAP);
1055 }
1056 if (trgAP==null)
1057 {
1058 // No more AP can be used to form rings with srcAP
1059 break;
1060 }
1061
1062 // Choose type of RCV
1063 Vertex rcvOnTrgAP = null;
1064 if (rcvIsChosenArbitrarily)
1065 {
1066 rcvOnTrgAP = fragSpace.getPolarizedRCV(false);
1067 } else {
1068 List<Vertex> candRCVs = fragSpace.getRCVsForAPClass(
1069 trgAP.getAPClass());
1070 if (candRCVs.size()>0)
1071 {
1072 APClass requiredAPC = RingClosingAttractor.RCAAPCMAP.get(
1073 rcvOnSrcAP.getAP(0).getAPClass());
1074 List<Vertex> keptRCVs = new ArrayList<Vertex>();
1075 for (Vertex rcv : candRCVs)
1076 {
1077 if (requiredAPC.equals(rcv.getAP(0).getAPClass()))
1078 keptRCVs.add(rcv);
1079 }
1080 rcvOnTrgAP = rng.randomlyChooseOne(keptRCVs);
1081 if (rcvOnTrgAP==null)
1082 {
1083 // no RCV is both usable and compatible with the
1084 // one already selected for srcAP
1085 continue;
1086 }
1087 } else {
1088 // The APClass settings and RCV compatibility rules
1089 // do not allow to identify a suitable RCV
1090 continue;
1091 }
1092 }
1093
1094 // append RCV
1095 tmpGraph.appendVertexOnAP(trgAP, rcvOnTrgAP.getAP(0));
1096 rcvAddedToGraph.add(rcvOnTrgAP);
1097 }
1098 if (rcvAddedToGraph.size() < 2)
1099 {
1100 // TODO: we could consider counting these to see what is the
1101 // most frequent cause of this mutation to fail
1102 continue;
1103 }
1104
1105 // Define rings to close in tmp graph
1107 settings.getLogger(), rng);
1108 t3d.setAlignBBsIn3D(false); //3D not needed
1109 IAtomContainer mol = t3d.convertGraphTo3DAtomContainer(tmpGraph,true);
1111 mol,
1112 tmpGraph,
1113 settings.getMaxRingsAddedByMutation(),
1114 fragSpace, rcParams);
1115
1116 //TODO: possibility to generate multiple combinations, rank them,
1117 // and pick the best one. Though definition of comparator is not
1118 // unambiguous.
1119
1120 setOfRingsOnTmpGraph = rCombIter.next();
1121
1122 // Termination of search over trgAPs
1123 if (setOfRingsOnTmpGraph.size()>0)
1124 break;
1125
1126 // Cleanup before starting new iteration
1127 for (Vertex toRemove : rcvAddedToGraph)
1128 tmpGraph.removeVertex(toRemove);
1129 }
1130 if (setOfRingsOnTmpGraph==null || setOfRingsOnTmpGraph.size()==0)
1131 {
1133 return false;
1134 }
1135
1136 // Project rings into the actual graph
1137 boolean done = false;
1138 for (Ring rOnTmp : setOfRingsOnTmpGraph)
1139 {
1140 // Project head RCV and all info to attach it to original graph
1141 Vertex vToHeadRCV = originalGraph.getVertexAtPosition(
1142 tmpGraph.indexOf(rOnTmp.getHeadVertex().getParent()));
1143 AttachmentPoint apToHeadRCV = vToHeadRCV.getAP(
1144 rOnTmp.getHeadVertex().getEdgeToParent().getSrcAP()
1145 .getIndexInOwner());
1146 Vertex headRCV = null;
1147 if (!apToHeadRCV.isAvailable())
1148 {
1149 headRCV = apToHeadRCV.getLinkedAP().getOwner();
1150 } else {
1151 headRCV = rOnTmp.getHeadVertex().clone();
1153 // And append head RCV on original graph
1154 originalGraph.appendVertexOnAP(apToHeadRCV, headRCV.getAP(0));
1155 }
1156
1157 // Project tail RCV and all info to attach it to original graph
1158 Vertex vToTailRCV = originalGraph.getVertexAtPosition(
1159 tmpGraph.indexOf(rOnTmp.getTailVertex().getParent()));
1160 AttachmentPoint apToTailRCV = vToTailRCV.getAP(
1161 rOnTmp.getTailVertex().getEdgeToParent().getSrcAP()
1162 .getIndexInOwner());
1163 Vertex tailRCV = null;
1164 if (!apToTailRCV.isAvailable())
1165 {
1166 tailRCV = apToTailRCV.getLinkedAP().getOwner();
1167 } else {
1168 tailRCV = rOnTmp.getTailVertex().clone();
1170 // And append tail RCV on original graph
1171 originalGraph.appendVertexOnAP(apToTailRCV, tailRCV.getAP(0));
1172 }
1173
1174 // Add ring
1175 originalGraph.addRing(headRCV, tailRCV);
1176 done = true;
1177 }
1178
1179 // Restore capping groups
1180 vertex.getGraphOwner().addCappingGroups(fragSpace);
1181
1182 return done;
1183 }
1184
1185//------------------------------------------------------------------------------
1186
1202 protected static boolean addFusedRing(Vertex vertex, Monitor mnt,
1203 boolean force, FragmentSpace fragSpace, GAParameters settings)
1204 throws DENOPTIMException
1205 {
1206 // get settings //TODO: this should happen inside RunTimeParameters
1208 if (settings.containsParameters(ParametersType.RC_PARAMS))
1209 {
1210 rcParams = (RingClosureParameters)settings.getParameters(
1212 }
1213
1214 Randomizer rng = settings.getRandomizer();
1215
1216 // First of all we remove capping groups in the graph
1217 vertex.getGraphOwner().removeCappingGroups();
1218
1219 List<AttachmentPoint> freeAPs = vertex.getFreeAPThroughout();
1220 if (freeAPs.size()==0)
1221 {
1223 return false;
1224 }
1225
1226 DGraph graph = vertex.getGraphOwner();
1227
1228 // Define where to add a bridge. Multiple sites are the result of
1229 // symmetry, so they all correspond to the same kind of operation
1230 // performed on symmetry-related sites
1231 List<List<RelatedAPPair>> candidatePairsSets =
1233 graph,
1234 fragSpace,
1235 rcParams,
1236 rng.nextBoolean(settings.getSymmetryProbability()),
1237 settings.getLogger(), rng);
1238 if (candidatePairsSets.size()==0)
1239 {
1241 return false;
1242 }
1243
1244 // Bias by potential ring size considering the existing part of the
1245 // to-be-created ring.
1246 // NB: we have to do this twice because some sites may be used to
1247 // form rings with different sizes. So, see below for the second time...
1248 List<List<RelatedAPPair>> szBiasedCandidatePairsSets =
1249 new ArrayList<List<RelatedAPPair>>();
1250 for (List<RelatedAPPair> pairSet : candidatePairsSets)
1251 {
1253 pairSet.get(0).property;
1254 int existingBridgeLength = bhfrOfPair.getExistingBridgeLength();
1255 int[] allowedBridgeLengths = bhfrOfPair.getAllowedBridgeLength(
1256 rcParams.getMaxRingSize());
1257 for (int i=0; i<allowedBridgeLengths.length; i++)
1258 {
1259 int allowedBridgeLength = allowedBridgeLengths[i];
1260 int possibleRingSize = allowedBridgeLength
1261 + existingBridgeLength;
1262 int weight = 1; // weight of a ring size
1263 if (possibleRingSize < rcParams.getMaxRingSize())
1264 {
1265 weight = rcParams.getRingSizeBias().get(possibleRingSize);
1266 }
1267
1268 // We add copies of the same set to the list of candidate
1269 // sets, so when we randomly choose we are more likely to
1270 // choose a set that leads to preferred ring sizes.
1271 for (int z=0; z<weight; z++)
1272 {
1273 szBiasedCandidatePairsSets.add(pairSet);
1274 }
1275 }
1276 }
1277 if (szBiasedCandidatePairsSets.size()==0)
1278 {
1280 return false;
1281 }
1282
1283 // Select one combination
1284 List<RelatedAPPair> chosenPairsSet = rng.randomlyChooseOne(
1285 szBiasedCandidatePairsSets);
1286
1287 // Based on the chosen pair, decide on the number of electrons to use
1288 // in the incoming fragment that will be used to close the ring
1289 // the pairs are all the same kind of ring fusion, so just take the 1st
1290 String elsInHalfFrag = chosenPairsSet.get(0).propID.substring(0,1);
1291 if (elsInHalfFrag.matches("[a-zA-Z]"))
1292 elsInHalfFrag = "0";
1293 boolean newRingIsAromatic = true;
1294 String elInIncomingFrag = "0el";
1295 switch (elsInHalfFrag)
1296 {
1297 case "0":
1298 case "1":
1299 // no aromaticity to be retained: use non-aromatic chords
1300 elInIncomingFrag = "0el";
1301 newRingIsAromatic = false;
1302 break;
1303
1304 case "2":
1305 // Formally we can use any fragment delivering 4n electrons.
1306 // Effectively, we have only 4-el fragments
1307 elInIncomingFrag = "4el";
1308 break;
1309
1310 case "3":
1311 // We could use a 5-el fragment, but the 8-el aromatic system is
1312 // so rare that we avoid it. So, we can only use 3-el fragment
1313 elInIncomingFrag = "3el";
1314 break;
1315
1316 case "4":
1317 // Effectively can only use 2-el fragments
1318 elInIncomingFrag = "2el";
1319 break;
1320
1321 case "5":
1322 // We could use a 3-el fragment, but the 8-el aromatic system is
1323 // so rare that we avoid it. This could become a tunable config
1324 elInIncomingFrag = "1el";
1325 break;
1326 default:
1327 throw new Error("Unknown number of pi-electrons in fragment to "
1328 + "be used for ring fusion operation.");
1329 }
1330
1331 // Collect fragment that can be used as ring-closing bridge based on the
1332 // number of aromatic electrons and number of atoms
1334 chosenPairsSet.get(0).property;
1335
1336 List<Vertex> usableBridges = null;
1337 if (newRingIsAromatic)
1338 {
1339 usableBridges = EAUtils.getUsableAromaticBridges(
1340 elInIncomingFrag,
1341 bhfr.getAllowedBridgeLength(rcParams.getMaxRingSize()),
1342 fragSpace);
1343 } else {
1344 // NB: we keep track of which APs are supposed to be used to form
1345 // the bridge by recording their index in a property of the vertex
1346 usableBridges = EAUtils.getUsableAliphaticBridges(
1347 chosenPairsSet.get(0).apA.getAPClass(),
1348 chosenPairsSet.get(0).apB.getAPClass(),
1349 bhfr.getAllowedBridgeLength(rcParams.getMaxRingSize()),
1350 fragSpace);
1351 }
1352
1353 if (usableBridges.size()==0)
1354 {
1356 return false;
1357 }
1358
1359 // Select size of the incoming bridge based on ring-size biases
1360 // NB: we have to do this twice because some sites may be used to
1361 // form rings with different sizes. So, see above for the first time...
1362 List<Vertex> szBiasedUsableBridges = new ArrayList<Vertex>();
1363 for (Vertex candidateBridge : usableBridges)
1364 {
1365 int thisBridgeLength = (int) candidateBridge.getProperty(
1367 int existingBridgeLength = bhfr.getExistingBridgeLength();
1368 int resultingRingSize = existingBridgeLength + thisBridgeLength;
1369 int weigth = 1; // weight of a ring size
1370 if (resultingRingSize < rcParams.getMaxRingSize())
1371 {
1372 weigth = rcParams.getRingSizeBias().get(resultingRingSize);
1373 }
1374
1375 // We add copies of the same vertex to the list of candidate
1376 // vertexes, so when we randomly choose we are more likely to
1377 // choose those leading to preferred ring sizes.
1378 for (int z=0; z<weigth; z++)
1379 {
1380 szBiasedUsableBridges.add(candidateBridge);
1381 }
1382 }
1383
1384 if (szBiasedUsableBridges.size()==0)
1385 {
1387 return false;
1388 }
1389
1390 Vertex incomingVertex = rng.randomlyChooseOne(szBiasedUsableBridges);
1391
1392 // Decide which aps on the bridge are used as head/tail
1393 List<AttachmentPoint> apsInFusion = new ArrayList<AttachmentPoint>();
1394 int[] idApOnBridge = new int[2];
1395 if (newRingIsAromatic)
1396 {
1397 apsInFusion.addAll(incomingVertex.getAPsWithAPClassStartingWith(
1398 elInIncomingFrag));
1399 if (rng.nextBoolean())
1400 {
1401 idApOnBridge[0] = apsInFusion.get(0).getIndexInOwner();
1402 idApOnBridge[1] = apsInFusion.get(1).getIndexInOwner();
1403 } else {
1404 idApOnBridge[0] = apsInFusion.get(1).getIndexInOwner();
1405 idApOnBridge[1] = apsInFusion.get(0).getIndexInOwner();
1406 }
1407 } else {
1408 idApOnBridge[0] = Integer.parseInt(incomingVertex.getProperty(
1410 idApOnBridge[1] = Integer.parseInt(incomingVertex.getProperty(
1412 }
1413
1414 boolean done = false;
1415 for (RelatedAPPair pairOfAPs : chosenPairsSet)
1416 {
1417 AttachmentPoint apHead = pairOfAPs.apA;
1418 AttachmentPoint apTail = pairOfAPs.apB;
1419
1420 Vertex bridgeClone = incomingVertex.clone();
1421 bridgeClone.setVertexId(graph.getMaxVertexId()+1);
1422
1423 graph.appendVertexOnAP(apHead, bridgeClone.getAP(idApOnBridge[0]));
1424
1425 Vertex rcvBridge = fragSpace.getPolarizedRCV(true);
1426 graph.appendVertexOnAP(bridgeClone.getAP(idApOnBridge[1]),
1427 rcvBridge.getAP(0));
1428
1429 Vertex rcvTail = fragSpace.getPolarizedRCV(false);
1430 graph.appendVertexOnAP(apTail, rcvTail.getAP(0));
1431 graph.addRing(rcvBridge, rcvTail);
1432 done = true;
1433 }
1434
1435 // Restore capping groups
1436 vertex.getGraphOwner().addCappingGroups(fragSpace);
1437
1438 return done;
1439 }
1440
1441//------------------------------------------------------------------------------
1442
1457 protected static boolean extendGraph(Vertex curVertex,
1458 boolean extend,
1459 boolean symmetryOnAps,
1460 GAParameters settings)
1461 throws DENOPTIMException
1462 {
1463 return extendGraph(curVertex, extend, symmetryOnAps, false, -1, -1,
1464 settings);
1465 }
1466
1467//------------------------------------------------------------------------------
1468
1492 protected static boolean extendGraph(Vertex curVrtx,
1493 boolean extend,
1494 boolean symmetryOnAps,
1495 boolean force,
1496 int chosenVrtxIdx,
1497 int chosenApId,
1498 GAParameters settings)
1499 throws DENOPTIMException
1500 {
1501 // get settings //TODO: this should happen inside RunTimeParameters
1503 if (settings.containsParameters(ParametersType.RC_PARAMS))
1504 {
1505 rcParams = (RingClosureParameters)settings.getParameters(
1507 }
1509 if (settings.containsParameters(ParametersType.FS_PARAMS))
1510 {
1511 fsParams = (FragmentSpaceParameters)settings.getParameters(
1513 }
1514 int maxHeavyAtoms = fsParams.getMaxHeavyAtom();
1515
1516 // return true if the append has been successful
1517 boolean status = false;
1518
1519 // check if the fragment has available APs
1520 if (!curVrtx.hasFreeAP())
1521 {
1522 return status;
1523 }
1524
1525 DGraph molGraph = curVrtx.getGraphOwner();
1526 int lvl = molGraph.getLevel(curVrtx);
1527
1528 ArrayList<Long> addedVertices = new ArrayList<>();
1529
1530 List<AttachmentPoint> lstDaps = curVrtx.getAttachmentPoints();
1531 List<AttachmentPoint> toDoAPs = new ArrayList<AttachmentPoint>();
1532 toDoAPs.addAll(lstDaps);
1533 for (int i=0; i<lstDaps.size(); i++)
1534 {
1535 // WARNING: randomization decouples 'i' from the index of the AP
1536 // in the vertex's list of APs! So 'i' is just the i-th attempt on
1537 // the curVertex.
1538
1539 AttachmentPoint ap = settings.getRandomizer().randomlyChooseOne(
1540 toDoAPs);
1541 toDoAPs.remove(ap);
1542 int apId = ap.getIndexInOwner();
1543
1544 // is it possible to extend on this AP?
1545 if (!ap.isAvailable())
1546 {
1547 continue;
1548 }
1549
1550 // NB: this is done also in addRing()
1551 // Ring closure does not change the size of the molecule, so we
1552 // give it an extra chance to occur irrespectively on molecular size
1553 // limit, while still subject of crowdedness probability.
1554 boolean allowOnlyRingClosure = false;
1555 if (!force)
1556 {
1557 // Decide whether we want to extend the graph at this AP?
1558 // Note that depending on the criterion (level/molSize) one
1559 // of these two first factors is 1.0.
1560 double molSizeProb = EAUtils.getMolSizeProbability(molGraph,
1561 settings);
1562 double byLevelProb = EAUtils.getGrowthByLevelProbability(lvl,
1563 settings);
1564 double crowdingProb = EAUtils.getCrowdingProbability(ap,
1565 settings);
1566 double extendGraphProb = molSizeProb * byLevelProb * crowdingProb;
1567 boolean fgrow = settings.getRandomizer().nextBoolean(
1568 extendGraphProb);
1569 if (!fgrow)
1570 {
1571 if (rcParams.allowRingClosures()
1572 && settings.getRandomizer().nextBoolean(byLevelProb
1573 * crowdingProb))
1574 {
1575 allowOnlyRingClosure = true;
1576 } else {
1577 continue;
1578 }
1579 }
1580 }
1581
1582 // Apply closability bias in selection of next fragment
1583 if (!allowOnlyRingClosure
1584 && rcParams.allowRingClosures()
1586 {
1587 boolean successful = attachFragmentInClosableChain(curVrtx,
1588 apId, molGraph, addedVertices, settings);
1589 if (successful)
1590 {
1591 continue;
1592 }
1593 }
1594
1595 // find a compatible combination of fragment and AP
1596 IdFragmentAndAP chosenFrgAndAp = null;
1597 if (allowOnlyRingClosure)
1598 {
1599 // NB: this works only for RCVs that are in the BBSpace, does
1600 // not generate a default RCV on-the-fly. So if no RCV is found
1601 // we'll get a pointer to nothing, which is what we check in the
1602 // next IF-block.
1603 chosenFrgAndAp = getRCVForSrcAp(curVrtx, apId,
1604 fsParams.getFragmentSpace());
1605 } else {
1606 chosenFrgAndAp = getFrgApForSrcAp(curVrtx,
1607 apId, chosenVrtxIdx, chosenApId, fsParams.getFragmentSpace());
1608 }
1609 int fid = chosenFrgAndAp.getVertexMolId();
1610 if (fid == -1)
1611 {
1612 continue;
1613 }
1614
1615 // Get the vertex that we'll add to the graph
1616 Vertex incomingVertex = Vertex.newVertexFromLibrary(-1,
1617 chosenFrgAndAp.getVertexMolId(),
1619 fsParams.getFragmentSpace());
1620
1621 // Stop if graph is already too big
1622 if ((curVrtx.getGraphOwner().getHeavyAtomsCount() +
1623 incomingVertex.getHeavyAtomsCount()) > maxHeavyAtoms)
1624 {
1625 continue;
1626 }
1627
1628 // Decide on symmetric substitution within this vertex...
1629 boolean cpOnSymAPs = applySymmetry(
1631 ap.getAPClass()),
1632 settings.getSymmetryProbability(),
1633 fsParams.getRandomizer());
1634 SymmetricAPs symAPs = new SymmetricAPs();
1635 if (curVrtx.getSymmetricAPs(ap).size()!=0
1636 && (cpOnSymAPs || symmetryOnAps)
1637 && !allowOnlyRingClosure)
1638 {
1639 symAPs.addAll(curVrtx.getSymmetricAPs(ap));
1640
1641 // Are symmetric APs rooted on same atom?
1642 boolean allOnSameSrc = true;
1643 for (AttachmentPoint symAP : symAPs)
1644 {
1645 if (!symAP.hasSameSrcAtom(ap))
1646 {
1647 allOnSameSrc = false;
1648 break;
1649 }
1650 }
1651
1652 if (allOnSameSrc)
1653 {
1654 // If the APs are rooted on the same src atom, we want to
1655 // apply the crowdedness probability to avoid over crowded
1656 // atoms
1657
1658 int crowdedness = EAUtils.getCrowdedness(ap);
1659
1660 SymmetricAPs toKeep = new SymmetricAPs();
1661
1662 // Start by keeping "ap"
1663 toKeep.add(ap);
1664 crowdedness = crowdedness + 1;
1665
1666 // Pick the accepted value once (used to decide how much
1667 // crowdedness we accept)
1668 double shot = settings.getRandomizer().nextDouble();
1669
1670 // Keep as many as allowed by the crowdedness decision
1671 for (AttachmentPoint symAP : symAPs)
1672 {
1673 if (symAP == ap)
1674 continue;
1675
1676 double crowdProb = EAUtils.getCrowdingProbability(
1677 crowdedness, settings);
1678
1679 if (shot > crowdProb)
1680 break;
1681
1682 toKeep.add(symAP);
1683 crowdedness = crowdedness + 1;
1684 }
1685
1686 // Adjust the list of symmetric APs to work with
1687 symAPs = toKeep;
1688 }
1689 } else {
1690 symAPs = new SymmetricAPs();
1691 symAPs.add(ap);
1692 }
1693
1694 // ...and inherit symmetry from previous levels
1695 boolean cpOnSymVrts = molGraph.hasSymmetryInvolvingVertex(curVrtx);
1696 SymmetricVertexes symVerts = new SymmetricVertexes();
1697 if (cpOnSymVrts)
1698 {
1699 symVerts = molGraph.getSymSetForVertex(curVrtx);
1700 }
1701 else
1702 {
1703 symVerts.add(curVrtx);
1704 }
1705
1706 // Consider size after application of symmetry
1707 if ((curVrtx.getGraphOwner().getHeavyAtomsCount() +
1708 incomingVertex.getHeavyAtomsCount() * symVerts.size()
1709 * symAPs.size()) > maxHeavyAtoms)
1710 {
1711 continue;
1712 }
1713
1714 // Collects all sym APs: within the vertex and outside it
1715 List<AttachmentPoint> allAPsFromSymVerts = new ArrayList<>();
1716 for (Vertex symVrt : symVerts)
1717 {
1718 for (AttachmentPoint apOnVrt : symAPs)
1719 {
1720 AttachmentPoint apOnSymVrt = symVrt.getAP(
1721 apOnVrt.getIndexInOwner());
1722 // This check is most often not needed, but it prevents that
1723 // misleading symmetry relations are used to break APClass
1724 // compatibility constraints
1725 if (apOnVrt.sameAs(apOnSymVrt)
1726 // Also ignore previously found APs
1727 && !symAPs.contains(apOnSymVrt))
1728 {
1729 allAPsFromSymVerts.add(apOnSymVrt);
1730 }
1731 }
1732 }
1733 symAPs.addAll(allAPsFromSymVerts);
1734
1736
1737 // loop on all symmetric vertices, but can be only one.
1738 SymmetricVertexes newSymSetOfVertices = new SymmetricVertexes();
1739 for (AttachmentPoint symAP : symAPs)
1740 {
1741 if (!symAP.isAvailable())
1742 {
1743 continue;
1744 }
1745
1746 // Finally add the fragment on a symmetric AP
1747 long newVrtId = GraphUtils.getUniqueVertexIndex();
1748 Vertex fragVertex = Vertex.newVertexFromLibrary(newVrtId,
1749 chosenFrgAndAp.getVertexMolId(),
1751 fsParams.getFragmentSpace());
1752 AttachmentPoint trgAP = fragVertex.getAP(
1753 chosenFrgAndAp.getApId());
1754
1755 molGraph.appendVertexOnAP(symAP, trgAP);
1756
1757 addedVertices.add(newVrtId);
1758 newSymSetOfVertices.add(fragVertex);
1759 }
1760
1761 // If any, store symmetry of new vertices in the graph
1762 if (newSymSetOfVertices.size() > 1)
1763 {
1764 molGraph.addSymmetricSetOfVertices(newSymSetOfVertices);
1765 }
1766 } // end loop over APs
1767
1768 if (extend)
1769 {
1770 // attempt to further extend each of the newly added vertices
1771 for (int i=0; i<addedVertices.size(); i++)
1772 {
1773 long vid = addedVertices.get(i);
1774 Vertex v = molGraph.getVertexWithId(vid);
1775 extendGraph(v, extend, symmetryOnAps, settings);
1776 }
1777 }
1778
1779 if (addedVertices.size() > 0)
1780 status = true;
1781
1782 return status;
1783 }
1784
1785//------------------------------------------------------------------------------
1786
1798 protected static IdFragmentAndAP getFrgApForSrcAp(Vertex curVertex,
1799 int dapidx, FragmentSpace fragSpace) throws DENOPTIMException
1800 {
1801 return getFrgApForSrcAp(curVertex, dapidx, -1, -1, fragSpace);
1802 }
1803
1804//------------------------------------------------------------------------------
1805
1823 protected static IdFragmentAndAP getFrgApForSrcAp(Vertex curVertex,
1824 int dapidx, int chosenVrtxIdx, int chosenApId,
1825 FragmentSpace fragSpace) throws DENOPTIMException
1826 {
1827 List<AttachmentPoint> lstDaps = curVertex.getAttachmentPoints();
1828 AttachmentPoint curDap = lstDaps.get(dapidx);
1829
1830 // Initialize with an empty pointer
1831 IdFragmentAndAP res = new IdFragmentAndAP(-1, -1, BBType.FRAGMENT, -1,
1832 -1, -1);
1833 if (!fragSpace.useAPclassBasedApproach())
1834 {
1835 int fid = fragSpace.getRandomizer().nextInt(
1836 fragSpace.getFragmentLibrary().size());
1837 res = new IdFragmentAndAP(-1,fid,BBType.FRAGMENT,-1,-1,-1);
1838 }
1839 else
1840 {
1841 List<IdFragmentAndAP> candidates =
1842 fragSpace.getFragAPsCompatibleWithClass(
1843 curDap.getAPClass());
1844 if (candidates.size() > 0)
1845 {
1846 if (chosenVrtxIdx>-1 && chosenApId>-1)
1847 {
1848 // We have asked to force the selection
1849 res = new IdFragmentAndAP(-1,chosenVrtxIdx,BBType.FRAGMENT,
1850 chosenApId,-1,-1);
1851 } else {
1852 res = fragSpace.getRandomizer().randomlyChooseOne(candidates);
1853 }
1854 }
1855 }
1856 return res;
1857 }
1858
1859//------------------------------------------------------------------------------
1860
1872 protected static IdFragmentAndAP getRCVForSrcAp(Vertex curVertex,
1873 int dapidx, FragmentSpace fragSpace) throws DENOPTIMException
1874 {
1875 AttachmentPoint ap = curVertex.getAP(dapidx);
1876
1877 Randomizer rng = fragSpace.getRandomizer();
1878 List<Vertex> rcvs = fragSpace.getRCVs();
1879 Vertex chosen = null;
1880 if (!fragSpace.useAPclassBasedApproach())
1881 {
1882 chosen = rng.randomlyChooseOne(rcvs);
1883 } else {
1884 List<Vertex> candidates = fragSpace.getRCVsForAPClass(
1885 ap.getAPClass());
1886 if (candidates.size() > 0)
1887 {
1888 chosen = rng.randomlyChooseOne(candidates);
1889 }
1890 }
1891
1892 IdFragmentAndAP pointer = new IdFragmentAndAP();
1893 if (chosen!=null)
1894 pointer = new IdFragmentAndAP(-1, chosen.getBuildingBlockId(),
1895 chosen.getBuildingBlockType(), 0, -1, -1);
1896 return pointer;
1897 }
1898
1899//------------------------------------------------------------------------------
1900
1901 protected static boolean attachFragmentInClosableChain(
1902 Vertex curVertex, int dapidx, DGraph molGraph,
1903 ArrayList<Long> addedVertices, GAParameters settings)
1904 throws DENOPTIMException
1905 {
1906 boolean res = false;
1908 if (settings.containsParameters(ParametersType.FS_PARAMS))
1909 {
1910 fsParams = (FragmentSpaceParameters)settings.getParameters(
1912 }
1913
1914 // Get candidate fragments
1915 ArrayList<FragForClosabChains> lscFfCc = getFragmentForClosableChain(
1916 curVertex, dapidx, molGraph);
1917
1918 // Here we can get:
1919 // 1) a selection of fragments that allow to close rings
1920 // 2) an empty list because no fragments allow to close rings
1921 // 3) "-1" as molID that means there are closable chains that
1922 // terminate at the current level, so we let the standard
1923 // routine proceeds selecting an extension of the chain
1924 // or cap this end.
1925
1926 // Choose a candidate and attach it to the graph
1927 int numCands = lscFfCc.size();
1928 if (numCands > 0)
1929 {
1930 int chosenId = settings.getRandomizer().nextInt(numCands);
1931 FragForClosabChains chosenFfCc = lscFfCc.get(chosenId);
1932 ArrayList<Integer> newFragIds = chosenFfCc.getFragIDs();
1933 int molIdNewFrag = newFragIds.get(0);
1934 BBType typeNewFrag = BBType.parseInt(newFragIds.get(1));
1935 int dapNewFrag = newFragIds.get(2);
1936 if (molIdNewFrag != -1)
1937 {
1938 long newvid = GraphUtils.getUniqueVertexIndex();
1940 newvid, molIdNewFrag, typeNewFrag,
1941 fsParams.getFragmentSpace());
1942
1943 molGraph.appendVertexOnAP(curVertex.getAP(dapidx),
1944 newVrtx.getAP(dapNewFrag));
1945
1946 if (newvid != -1)
1947 {
1948 addedVertices.add(newvid);
1949 // update list of candidate closable chains
1950 molGraph.getClosableChains().removeAll(
1951 chosenFfCc.getIncompatibleCC());
1952 APClass apc = curVertex.getAttachmentPoints().get(
1953 dapidx).getAPClass();
1954 if (applySymmetry(
1956 settings.getSymmetryProbability(),
1957 fsParams.getRandomizer()))
1958 {
1959//TODO: implement symmetric substitution with closability bias
1960 }
1961 res = true;
1962 }
1963 else
1964 {
1965 String msg = "BUG: Incorrect vertex num. Contact author.";
1966 settings.getLogger().log(Level.SEVERE, msg);
1967 throw new DENOPTIMException(msg);
1968 }
1969 }
1970 }
1971 return res;
1972 }
1973
1974//------------------------------------------------------------------------------
1975
1980 private static class FragForClosabChains
1981 {
1982 private ArrayList<ClosableChain> compatChains;
1983 private ArrayList<ClosableChain> incompatChains;
1984 private ArrayList<Integer> fragIds;
1985
1986 //----------------------------------------------------------------------
1987
1988 public FragForClosabChains(ArrayList<ClosableChain> compatChains,
1989 ArrayList<ClosableChain> incompatChains,
1990 ArrayList<Integer> fragIds)
1991 {
1992 this.compatChains = compatChains;
1993 this.incompatChains = incompatChains;
1994 this.fragIds = fragIds;
1995 }
1996
1997 //----------------------------------------------------------------------
1998
2000 {
2001 compatChains.add(icc);
2002 }
2003
2004 //----------------------------------------------------------------------
2005
2006 public ArrayList<ClosableChain> getCompatibleCC()
2007 {
2008 return compatChains;
2009 }
2010
2011 //----------------------------------------------------------------------
2012
2013 public ArrayList<ClosableChain> getIncompatibleCC()
2014 {
2015 return incompatChains;
2016 }
2017
2018 //----------------------------------------------------------------------
2019
2020 public ArrayList<Integer> getFragIDs()
2021 {
2022 return fragIds;
2023 }
2024
2025 //----------------------------------------------------------------------
2026 }
2027
2028//------------------------------------------------------------------------------
2029
2035 protected static ArrayList<FragForClosabChains> getFragmentForClosableChain(
2036 Vertex curVertex,
2037 int dapidx,
2038 DGraph molGraph)
2039 throws DENOPTIMException
2040 {
2041 // Select candidate fragments respecting the closability conditions
2042 ArrayList<FragForClosabChains> lstChosenFfCc =
2043 new ArrayList<FragForClosabChains>();
2044
2045 if (molGraph.getClosableChains().size() == 0)
2046 {
2047 return lstChosenFfCc;
2048 }
2049
2050 if (curVertex.getBuildingBlockType() == BBType.SCAFFOLD)
2051 {
2052 for (ClosableChain cc : molGraph.getClosableChains())
2053 {
2054 int posInCc = cc.involvesVertex(curVertex);
2055 ChainLink cLink = cc.getLink(posInCc);
2056 int nfid = -1;
2057 BBType nfty = BBType.UNDEFINED;
2058 int nfap = -1;
2059
2060 if (cLink.getApIdToLeft() != dapidx &&
2061 cLink.getApIdToRight() != dapidx)
2062 {
2063 // Chain does not involve AP dapidx
2064 continue;
2065 }
2066
2067 if (cLink.getApIdToRight() == dapidx)
2068 {
2069 if (cc.getSize() > (posInCc+1))
2070 {
2071 // cLink is NOT the rightmost chain link
2072 ChainLink nextChainLink = cc.getLink(posInCc+1);
2073 nfid = nextChainLink.getIdx();
2074 nfty = nextChainLink.getFragType();
2075 nfap = nextChainLink.getApIdToLeft();
2076 }
2077 else
2078 {
2079 // cLink is the rightmost chain link
2080 // closability bias suggest NO fragment
2081 }
2082 }
2083 else if (cLink.getApIdToLeft() == dapidx)
2084 {
2085 if ((posInCc-1) >= 0)
2086 {
2087 // cLink is NOT the leftmost chain link
2088 ChainLink nextChainLink = cc.getLink(posInCc-1);
2089 nfid = nextChainLink.getIdx();
2090 nfty = nextChainLink.getFragType();
2091 nfap = nextChainLink.getApIdToRight();
2092 }
2093 else
2094 {
2095 // cLink is the leftmost chain link
2096 // closability bias suggest NO fragment
2097 }
2098 }
2099
2100 ArrayList<Integer> eligibleFrgId = new ArrayList<Integer>();
2101 eligibleFrgId.add(nfid);
2102 eligibleFrgId.add(nfty.toOldInt());
2103 eligibleFrgId.add(nfap);
2104 boolean found = false;
2105 for (FragForClosabChains ffcc : lstChosenFfCc)
2106 {
2107 int fidA = ffcc.getFragIDs().get(0);
2108 BBType ftyA = BBType.parseInt(ffcc.getFragIDs().get(1));
2109 int fapA = ffcc.getFragIDs().get(2);
2110 if (nfid==fidA && nfty==ftyA && nfap==fapA)
2111 {
2112 found = true;
2113 ffcc.getCompatibleCC().add(cc);
2114 }
2115 else
2116 {
2117 ffcc.getIncompatibleCC().add(cc);
2118 }
2119 }
2120 if (!found)
2121 {
2122 ArrayList<ClosableChain> compatChains =
2123 new ArrayList<ClosableChain>();
2124 ArrayList<ClosableChain> incompatChains =
2125 new ArrayList<ClosableChain>();
2126 for (FragForClosabChains otherFfCc : lstChosenFfCc)
2127 {
2128 incompatChains.addAll(otherFfCc.getCompatibleCC());
2129 }
2130 FragForClosabChains newChosenCc = new FragForClosabChains(
2131 compatChains,
2132 incompatChains,
2133 eligibleFrgId);
2134
2135 newChosenCc.addCompatibleCC(cc);
2136 lstChosenFfCc.add(newChosenCc);
2137 }
2138 }
2139 }
2140 else
2141 {
2142 Vertex parent = molGraph.getParent(curVertex);
2143 Edge edge = molGraph.getEdgeWithParent(
2144 curVertex.getVertexId());
2145 int prntId = parent.getBuildingBlockId();
2146 BBType prntTyp = parent.getBuildingBlockType();
2147 int prntAp = edge.getSrcAPID();
2148 int chidAp = edge.getTrgAPID();
2149 for (ClosableChain cc : molGraph.getClosableChains())
2150 {
2151 int posInCc = cc.involvesVertexAndAP(curVertex, dapidx, chidAp);
2152
2153 if (posInCc == -1)
2154 {
2155 // closable chain does not span this combination
2156 // of vertex and APs
2157 continue;
2158 }
2159
2160 ChainLink cLink = cc.getLink(posInCc);
2161 int nfid = -1;
2162 BBType nfty = BBType.UNDEFINED;
2163 int nfap = -1;
2164
2165 List<Integer> altertnativeDirections = new ArrayList<>();
2166 altertnativeDirections.add(-1);
2167 altertnativeDirections.add(+1);
2168 for (int altDir : altertnativeDirections)
2169 {
2170 ChainLink parentLink = cc.getLink(posInCc + altDir);
2171 int pLnkId = parentLink.getIdx();
2172 BBType pLnkTyp = parentLink.getFragType();
2173
2174 int pLnkAp = -1;
2175 int cApId = -1;
2176 if (altDir>0)
2177 {
2178 pLnkAp = parentLink.getApIdToRight();
2179 cApId = cLink.getApIdToLeft();
2180 } else {
2181 pLnkAp = parentLink.getApIdToLeft();
2182 cApId = cLink.getApIdToRight();
2183 }
2184 if (pLnkId==prntId && pLnkTyp==prntTyp && pLnkAp == prntAp &&
2185 cApId == chidAp)
2186 {
2187 if (cc.getSize() > (posInCc+altDir)
2188 && (posInCc+altDir) >= 0)
2189 {
2190 ChainLink nextChainLink = cc.getLink(posInCc + altDir);
2191 nfid = nextChainLink.getIdx();
2192 nfty = nextChainLink.getFragType();
2193 nfap = nextChainLink.getApIdToLeft();
2194 }
2195 else
2196 {
2197 // cLink is the rightmost chain link
2198 // closability bias suggests NO fragment
2199 }
2200 }
2201 else
2202 {
2203 // different parent link
2204 continue;
2205 }
2206 }
2207
2208 ArrayList<Integer> eligibleFrgId = new ArrayList<Integer>();
2209 eligibleFrgId.add(nfid);
2210 eligibleFrgId.add(nfty.toOldInt());
2211 eligibleFrgId.add(nfap);
2212 boolean found = false;
2213 for (FragForClosabChains ffcc : lstChosenFfCc)
2214 {
2215 int fidA = ffcc.getFragIDs().get(0);
2216 BBType ftyA = BBType.parseInt(ffcc.getFragIDs().get(1));
2217 int fapA = ffcc.getFragIDs().get(2);
2218 if (nfid==fidA && nfty==ftyA && nfap==fapA)
2219 {
2220 found = true;
2221 ffcc.getCompatibleCC().add(cc);
2222 }
2223 else
2224 {
2225 ffcc.getIncompatibleCC().add(cc);
2226 }
2227 }
2228 if (!found)
2229 {
2230 ArrayList<ClosableChain> compatChains =
2231 new ArrayList<ClosableChain>();
2232 ArrayList<ClosableChain> incompatChains =
2233 new ArrayList<ClosableChain>();
2234 for (FragForClosabChains otherFfCc : lstChosenFfCc)
2235 {
2236 incompatChains.addAll(otherFfCc.getCompatibleCC());
2237 }
2238 FragForClosabChains newChosenCc = new FragForClosabChains(
2239 compatChains,
2240 incompatChains,
2241 eligibleFrgId);
2242 newChosenCc.addCompatibleCC(cc);
2243 lstChosenFfCc.add(newChosenCc);
2244 }
2245 }
2246 }
2247 return lstChosenFfCc;
2248 }
2249
2250//------------------------------------------------------------------------------
2251
2262 public static boolean performCrossover(XoverSite site,
2263 FragmentSpace fragSpace) throws DENOPTIMException
2264 {
2265 DGraph gA = site.getA().get(0).getGraphOwner();
2266 DGraph gB = site.getB().get(0).getGraphOwner();
2267
2268 // All the APs that point away from the subgraph
2269 List<AttachmentPoint> allAPsOnA = gA.getSubgraphAPs(site.getA());
2270 List<AttachmentPoint> allAPsOnB = gB.getSubgraphAPs(site.getB());
2271
2272 // The APs that are required to have a mapping for proper crossover,
2273 // eg. because the change of subgraph needs to retain a super structure.
2274 List<AttachmentPoint> needyAPsOnA = site.getAPsNeedingMappingA();
2275 List<AttachmentPoint> needyAPsOnB = site.getAPsNeedingMappingB();
2276
2277 // APs that connects the subgraphs' root to the parent vertex
2278 AttachmentPoint apToParentA = null;
2279 AttachmentPoint apToParentB = null;
2280 for (AttachmentPoint ap : needyAPsOnA)
2281 {
2282 if (!ap.isSrcInUserThroughout())
2283 {
2284 apToParentA = ap;
2285 //WARNING: we assume there is one AND only one AP to parent!!!
2286 break;
2287 }
2288 }
2289 for (AttachmentPoint ap : needyAPsOnB)
2290 {
2291 if (!ap.isSrcInUserThroughout())
2292 {
2293 apToParentB = ap;
2294 //WARNING: we assume there is one AND only one AP to parent!!!
2295 break;
2296 }
2297 }
2298 if (apToParentA==null || apToParentB==null)
2299 {
2300 throw new DENOPTIMException("Could not identify any attachment "
2301 + "point connecting a subgraph to the rest of the graph. "
2302 + "This violates assumption that crossover does not "
2303 + "involve scaffold or vertexes without parent.");
2304 }
2305 // Check if the subgraphs can be used with reversed edge direction, or
2306 // bias the AP mapping to use the original source vertexes.
2307 APMapping fixedRootAPs = null;
2308 //TODO: REACTIVATE ONCE REVERSION of the subgrsph's spanning tree is in place.
2309 //if (!subG_M.isReversible() || !subG_F.isReversible())
2310 if (true)
2311 {
2312 // Constrain the AP mapping so that the AP originally used to
2313 // connect to the parent vertex, will also be used the same way.
2314 // Thus, forces retention of edge direction within the subgraph.
2315 fixedRootAPs = new APMapping();
2316 fixedRootAPs.put(apToParentA, apToParentB);
2317 }
2318
2319 // Find an AP mapping that satisfies both root-vertex constrain and
2320 // need to ensure the mapping of needy APs
2321 APMapFinder apmf = new APMapFinder(fragSpace,
2322 allAPsOnA, needyAPsOnA,
2323 allAPsOnB, needyAPsOnB, fixedRootAPs,
2324 false, // false means stop at the first compatible mapping.
2325 false, // false means we do not require complete mapping.
2326 false); // false means free AP are not considered compatible.
2327 if (!apmf.foundMapping())
2328 {
2329 // Since the xover site has been detected by searching for compatible
2330 // sites that do have a mapping there should always be at least one
2331 // mapping and this exception should never occur.
2332 throw new DENOPTIMException("Missing AP mapping for known XoverSite.");
2333 }
2334
2335 // To replace each subgraph in the original graphs, we need to
2336 // map the APs on the original A/B graph with those in the
2337 // corresponding incoming subgraph, which are clones of the original:
2338 DGraph subGraphA = gA.extractSubgraph(site.getA());
2339 DGraph subGraphB = gB.extractSubgraph(site.getB());
2340
2341 // Here we create the two AP mappings we need: one for A other for B.
2342 LinkedHashMap<AttachmentPoint,AttachmentPoint>
2343 apMapA = new LinkedHashMap<AttachmentPoint,AttachmentPoint>();
2344 LinkedHashMap<AttachmentPoint,AttachmentPoint>
2345 apMapB = new LinkedHashMap<AttachmentPoint,AttachmentPoint>();
2346 for (Map.Entry<AttachmentPoint, AttachmentPoint> e :
2347 apmf.getChosenAPMapping().entrySet())
2348 {
2349 AttachmentPoint apOnA = e.getKey();
2350 AttachmentPoint apOnB = e.getValue();
2351
2352 // NB: assumption that vertex IDs are healthy, AND that order of APs
2353 // is retained upon cloning of the subgraph!
2354 AttachmentPoint apOnSubGraphA = subGraphA.getVertexWithId(
2355 apOnA.getOwner().getVertexId()).getAP(
2356 apOnA.getIndexInOwner());
2357 AttachmentPoint apOnSubGraphB = subGraphB.getVertexWithId(
2358 apOnB.getOwner().getVertexId()).getAP(
2359 apOnB.getIndexInOwner());
2360 apMapA.put(apOnA, apOnSubGraphB);
2361 apMapB.put(apOnB, apOnSubGraphA);
2362 }
2363
2364 // Now we do the actual replacement of subgraphs
2365 if (!gA.replaceSubGraph(site.getA(), subGraphB, apMapA, fragSpace))
2366 return false;
2367 if (!gB.replaceSubGraph(site.getB(), subGraphA, apMapB, fragSpace))
2368 return false;
2369
2370 return true;
2371 }
2372
2373//------------------------------------------------------------------------------
2374
2387 protected static boolean applySymmetry(boolean apclassImposed,
2388 double symmetryProbability, Randomizer randomizer)
2389 {
2390 boolean r = false;
2391 if (apclassImposed)
2392 {
2393 r = true;
2394 }
2395 else
2396 {
2397 r = randomizer.nextBoolean(symmetryProbability);
2398 }
2399 return r;
2400 }
2401
2402//------------------------------------------------------------------------------
2403
2416 public static boolean performMutation(DGraph graph, Monitor mnt,
2417 GAParameters settings) throws DENOPTIMException
2418 {
2419 // Get vertices that can be mutated: they can be part of subgraphs
2420 // embedded in templates. Here, we consider only single-vertexes sites.
2421 // So sites for ADDRINGFUSION mutation are not added here.
2422 List<Vertex> mutable = graph.getMutableSites(
2423 settings.getExcludedMutationTypes());
2424 // Now, add also the sites that involve multiple vertexes, such sites for
2425 // ADDFUSEDRING mutation.
2426 for (List<RelatedAPPair> siteCombination : EAUtils.searchRingFusionSites(
2427 graph, settings))
2428 {
2429 for (RelatedAPPair site : siteCombination)
2430 {
2431 Vertex vA = site.apA.getOwner();
2432 Vertex vB = site.apB.getOwner();
2433 if (!mutable.contains(vA))
2434 mutable.add(vA);
2435 if (!mutable.contains(vB))
2436 mutable.add(vB);
2437 }
2438 }
2439
2440 if (mutable.size() == 0)
2441 {
2443 String msg = "Graph has no mutable site. Mutation aborted.";
2444 settings.getLogger().info(msg);
2445 return false;
2446 }
2447 boolean doneMutation = true;
2448 int numberOfMutations = EAUtils.chooseNumberOfSitesToMutate(
2449 settings.getMultiSiteMutationWeights(),
2450 settings.getRandomizer().nextDouble());
2451 for (int i=0; i<numberOfMutations; i++)
2452 {
2453 if (i>0)
2454 {
2455 mutable = graph.getMutableSites(
2456 settings.getExcludedMutationTypes());
2457 break;
2458 }
2459 Vertex v = settings.getRandomizer().randomlyChooseOne(mutable);
2460 doneMutation = performMutation(v, mnt, settings);
2461 if(!doneMutation)
2462 break;
2463 }
2464 return doneMutation;
2465 }
2466
2467//------------------------------------------------------------------------------
2468
2482 public static boolean performMutation(Vertex vertex, Monitor mnt,
2483 GAParameters settings) throws DENOPTIMException
2484 {
2485 List<MutationType> mTypes = vertex.getMutationTypes(
2486 settings.getExcludedMutationTypes());
2487 if (mTypes.size() == 0)
2488 {
2489 return false;
2490 }
2491 MutationType mType = settings.getRandomizer().randomlyChooseOne(mTypes);
2492 return performMutation(vertex, mType, mnt, settings);
2493 }
2494
2495//------------------------------------------------------------------------------
2496
2508 public static boolean performMutation(Vertex vertex,
2509 MutationType mType, Monitor mnt, GAParameters settings)
2510 throws DENOPTIMException
2511 {
2512 DGraph c = vertex.getGraphOwner().clone();
2513 int pos = vertex.getGraphOwner().indexOf(vertex);
2514 try
2515 {
2516 return performMutation(vertex, mType, false, -1 ,-1, mnt, settings);
2517 } catch (IllegalArgumentException|NullPointerException e)
2518 {
2519 String debugFile = "failedMutation_" + mType
2520 + "_" + vertex.getVertexId() + "(" + pos + ")_"
2521 + settings.timeStamp + ".sdf";
2522 DenoptimIO.writeGraphToSDF(new File(debugFile), c, false,
2523 settings.getLogger(), settings.getRandomizer());
2524 settings.getLogger().warning("Fatal exception while performing "
2525 + "mutation. See file '" + debugFile + "' to reproduce the "
2526 + "problem.");
2527 throw e;
2528 }
2529 }
2530
2531//------------------------------------------------------------------------------
2532
2558 public static boolean performMutation(Vertex vertex,
2559 MutationType mType, boolean force, int chosenVrtxIdx,
2560 int chosenApId, Monitor mnt, GAParameters settings)
2561 throws DENOPTIMException
2562 {
2564 if (settings.containsParameters(ParametersType.FS_PARAMS))
2565 {
2566 fsParams = (FragmentSpaceParameters)settings.getParameters(
2568 }
2569
2570 DGraph graph = vertex.getGraphOwner();
2571 if (graph == null)
2572 {
2574 settings.getLogger().info("Vertex has no owner - "
2575 + "Mutation aborted");
2576 return false;
2577 }
2578 if (!vertex.getMutationTypes(settings.getExcludedMutationTypes())
2579 .contains(mType))
2580 {
2582 settings.getLogger().info("Vertex does not allow mutation type "
2583 + "'" + mType + "' - Mutation aborted");
2584 return false;
2585 }
2586
2587 int graphId = graph.getGraphId();
2588 int positionOfVertex = graph.indexOf(vertex);
2589 //NB: since we have renumbered the vertexes, we use the old vertex ID
2590 // when reporting what vertex is being mutated. Also, note that the
2591 // identity of the candidate is already in the graph's local msg.
2592 String mutantOrigin = graph.getLocalMsg() + "|"
2593 + mType + "|"
2594 + vertex.getProperty(DENOPTIMConstants.STOREDVID)
2595 + " (" + positionOfVertex + ")";
2596 graph.setLocalMsg(mutantOrigin);
2597
2598 boolean done = false;
2599 switch (mType)
2600 {
2601 case CHANGEBRANCH:
2602 done = rebuildBranch(vertex, force, chosenVrtxIdx, chosenApId,
2603 settings);
2604 if (!done)
2605 mnt.increase(
2607 break;
2608
2609 case CHANGELINK:
2610 done = substituteLink(vertex, chosenVrtxIdx, mnt,
2611 fsParams.getFragmentSpace());
2612 if (!done)
2613 mnt.increase(
2615 break;
2616
2617 case DELETELINK:
2618 done = deleteLink(vertex, chosenApId, mnt,
2619 fsParams.getFragmentSpace());
2620 if (!done)
2621 mnt.increase(
2623 break;
2624
2625 case DELETECHAIN:
2626 done = deleteChain(vertex, mnt, fsParams.getFragmentSpace());
2627 if (!done)
2628 mnt.increase(
2630 break;
2631
2632 case ADDLINK:
2633 if (chosenApId < 0)
2634 {
2635 List<Integer> candidates = new ArrayList<Integer>();
2636 for (Vertex c : vertex.getChilddren())
2637 {
2638 candidates.add(c.getEdgeToParent().getSrcAP()
2639 .getIndexInOwner());
2640 }
2641 if (candidates.size() == 0)
2642 {
2643 mnt.increase(
2645 break;
2646 }
2647 chosenApId = settings.getRandomizer().randomlyChooseOne(
2648 candidates);
2649 }
2650 done = extendLink(vertex, chosenApId, chosenVrtxIdx, mnt,
2651 fsParams.getFragmentSpace());
2652 if (!done)
2653 mnt.increase(
2655 break;
2656
2657 case ADDRING:
2658 done = addRing(vertex, mnt, false, fsParams.getFragmentSpace(),
2659 settings);
2660 if (!done)
2662 break;
2663
2664 case ADDFUSEDRING:
2665 done = addFusedRing(vertex, mnt, false, fsParams.getFragmentSpace(),
2666 settings);
2667 if (!done)
2669 break;
2670
2671 case EXTEND:
2672 vertex.getGraphOwner().removeCappingGroupsOn(vertex);
2673 done = extendGraph(vertex, false, false, force, chosenVrtxIdx,
2674 chosenApId, settings);
2675 if (!done)
2677 break;
2678
2679 case DELETE:
2680 done = deleteFragment(vertex);
2681 if (!done)
2683 break;
2684 }
2685
2686 String msg = "Mutation '" + mType.toString() + "' on vertex "
2687 + vertex.toString() + " (position " + positionOfVertex
2688 + " in graph " + graphId+"): ";
2689 if (done)
2690 {
2691 msg = msg + "done";
2692
2693 // Triggers reconstruction of the molecular representation of
2694 // templates upon changes of the embedded graph
2695 if (graph.getTemplateJacket() != null)
2696 {
2698 }
2699 } else {
2700 msg = msg + "unsuccessful";
2701 }
2702 settings.getLogger().info(msg);
2703
2704 return done;
2705 }
2706
2707//------------------------------------------------------------------------------
2708
2709
2710
2711}
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:2344
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:3151
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:2367
static List< List< RelatedAPPair > > searchRingFusionSites(DGraph graph, GAParameters gaParams)
Definition: EAUtils.java:2584
static int getCrowdedness(AttachmentPoint ap)
Calculate the current crowdedness of the given attachment point.
Definition: EAUtils.java:2412
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:3107
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:2267
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:104
boolean removeVertexAndWeld(Vertex vertex, FragmentSpace fragSpace)
Remove a given vertex belonging to this graph and re-connects the resulting graph branches as much as...
Definition: DGraph.java:1489
boolean replaceVertex(Vertex vertex, int bbId, BBType bbt, LinkedHashMap< Integer, Integer > apIdMap, FragmentSpace fragSpace)
Replaced a given vertex belonging to this graph with a new vertex generated specifically for this pur...
Definition: DGraph.java:2908
Vertex getVertexWithId(long vid)
Searches for a vertex with the given identifier.
Definition: DGraph.java:3231
DGraph extractSubgraph(int index)
Creates a new graph that corresponds to the subgraph of this graph when exploring the spanning tree f...
Definition: DGraph.java:4908
boolean isIsomorphicTo(DGraph other)
Checks if this graph is "DENOPTIM-isomorphic" to the other one given.
Definition: DGraph.java:4103
ArrayList< Ring > getRingsInvolvingVertex(Vertex v)
Returns the list of rings that include the given vertex in their fundamental cycle.
Definition: DGraph.java:1082
void getChildrenTree(Vertex vertex, List< Vertex > children)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:3421
String getLocalMsg()
Definition: DGraph.java:289
void removeVertex(Vertex vertex)
Remove a vertex from this graph.
Definition: DGraph.java:1413
int indexOf(Vertex v)
Returns the index of a vertex in the list of vertices of this graph.
Definition: DGraph.java:3218
Vertex getVertexAtPosition(int pos)
Returns the vertex that is in the given position of the list of vertices belonging to this graph.
Definition: DGraph.java:3163
Vertex getDeepestAmongThese(List< Vertex > list)
Identify the oldest ancestor (i.e., most great grandparent) in the given collection.
Definition: DGraph.java:3773
String getBranchIdOfVertexAsStr(Vertex v)
Returns the branch identifier as a literal string.
Definition: DGraph.java:3628
List< AttachmentPoint > getAvailableAPsThroughout()
Returns the list of attachment points contained in this graph that are available throughout the templ...
Definition: DGraph.java:4661
void appendVertexOnAP(AttachmentPoint srcAP, AttachmentPoint trgAP)
Append a vertex to this graph: adds the new vertex to the list of vertices belonging to the graph,...
Definition: DGraph.java:6476
List< AttachmentPoint > getInterfaceAPs(List< Vertex > subGraphB)
Searches for all AttachmentPoints that represent the interface between a subgraph,...
Definition: DGraph.java:7783
DGraph clone()
Returns almost "deep-copy" of this graph.
Definition: DGraph.java:3836
boolean replaceSubGraph(List< Vertex > subGrpVrtxs, DGraph incomingGraph, LinkedHashMap< AttachmentPoint, AttachmentPoint > apMap, FragmentSpace fragSpace)
Replaced the subgraph represented by a given collection of vertices that belong to this graph.
Definition: DGraph.java:2002
int getLevel(Vertex v)
Calculates the level of a vertex in this graph.
Definition: DGraph.java:6026
void addSymmetricSetOfVertices(SymmetricVertexes symSet)
Adds a symmetric set of vertices to this graph.
Definition: DGraph.java:891
SymmetricVertexes getSymSetForVertex(Vertex v)
Returns the set of vertexes symmetric to the given one.
Definition: DGraph.java:863
List< AttachmentPoint > getSubgraphAPs(List< Vertex > subGraphB)
Searches for all AttachmentPoints that are owned by vertices in a subgraph but either available or us...
Definition: DGraph.java:7818
void addRing(Ring ring)
Definition: DGraph.java:1304
boolean hasSymmetryInvolvingVertex(Vertex v)
Definition: DGraph.java:303
boolean insertVertex(Edge edge, int bbId, BBType bbt, LinkedHashMap< AttachmentPoint, Integer > apMap, FragmentSpace fragSpace)
Inserts a given vertex in between two vertices connected by the given edge.
Definition: DGraph.java:3009
void getChildTreeLimited(Vertex vertex, List< Vertex > children, boolean stopBeforeRCVs)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:3678
boolean removeBranchStartingAt(Vertex v, boolean symmetry)
Deletes the branch, i.e., the specified vertex and its children.
Definition: DGraph.java:5488
Template getTemplateJacket()
Definition: DGraph.java:7602
boolean removeChainUpToBranching(Vertex v, FragmentSpace fragSpace)
Mutates the graph by removing the chain where a given vertex is located up to the first branching (i....
Definition: DGraph.java:5578
void setLocalMsg(String msg)
Definition: DGraph.java:281
boolean isIsostructuralTo(DGraph other)
Checks if this graph is "DENOPTIM-isostructural" to the other one given.
Definition: DGraph.java:4230
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:159
APClass getSrcAPClass()
Definition: Edge.java:152
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...