$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.HashSet;
25import java.util.LinkedHashMap;
26import java.util.List;
27import java.util.Map;
28import java.util.Map.Entry;
29import java.util.Set;
30import java.util.TreeMap;
31import java.util.logging.Level;
32import java.util.stream.Collectors;
33
34import org.openscience.cdk.interfaces.IAtomContainer;
35import org.paukov.combinatorics3.Generator;
36
37import denoptim.constants.DENOPTIMConstants;
38import denoptim.exception.DENOPTIMException;
39import denoptim.fragmenter.BridgeHeadFindingRule;
40import denoptim.fragspace.APMapFinder;
41import denoptim.fragspace.FragmentSpace;
42import denoptim.fragspace.FragmentSpaceParameters;
43import denoptim.fragspace.GraphLinkFinder;
44import denoptim.fragspace.IdFragmentAndAP;
45import denoptim.graph.APClass;
46import denoptim.graph.APMapping;
47import denoptim.graph.AttachmentPoint;
48import denoptim.graph.DGraph;
49import denoptim.graph.Edge;
50import denoptim.graph.RelatedAPPair;
51import denoptim.graph.Ring;
52import denoptim.graph.SymmetricAPs;
53import denoptim.graph.SymmetricVertexes;
54import denoptim.graph.Template;
55import denoptim.graph.Template.ContractLevel;
56import denoptim.graph.Vertex;
57import denoptim.graph.Vertex.BBType;
58import denoptim.graph.rings.ChainLink;
59import denoptim.graph.rings.ClosableChain;
60import denoptim.graph.rings.PathSubGraph;
61import denoptim.graph.rings.RandomCombOfRingsIterator;
62import denoptim.graph.rings.RingClosingAttractor;
63import denoptim.graph.rings.RingClosureParameters;
64import denoptim.io.DenoptimIO;
65import denoptim.logging.CounterID;
66import denoptim.logging.Monitor;
67import denoptim.molecularmodeling.ThreeDimTreeBuilder;
68import denoptim.programs.RunTimeParameters.ParametersType;
69import denoptim.programs.denovo.GAParameters;
70import denoptim.utils.CrossoverType;
71import denoptim.utils.GraphUtils;
72import denoptim.utils.MutationType;
73import denoptim.utils.Randomizer;
74
79public class GraphOperations
80{
81
82//------------------------------------------------------------------------------
83
107 public static List<XoverSite> locateCompatibleXOverPoints(
108 DGraph graphA, DGraph graphB, FragmentSpace fragSpace,
109 int maxSizeXoverSubGraph, int maxCompatibleVrtxPairs,
110 int maxEndPointsCombinations, int maxEndPointsPermutations,
111 int maxAPMappingCombinations)
112 throws DENOPTIMException
113 {
114 // First, we identify edges that allow crossover, and collect
115 // their target vertexes (i.e., potential seed vertexes of
116 // subgraphs that crossover could swap). If more than
117 // maxCompatibleVrtxPairs compatible pairs exist, we stop and
118 // re-collect from edge lists shuffled via Randomizer so the
119 // capped sample is randomized yet reproducible.
120 List<Vertex[]> compatibleVrtxPairs = new ArrayList<Vertex[]>();
121 boolean needsRandomCap = false;
122 scanCompatiblePairs:
123 for (Edge eA : graphA.getEdgeList())
124 {
125 Vertex vA = eA.getTrgAP().getOwner();
126 // We don't do genetic operations on capping vertexes
127 if (vA.getBuildingBlockType() == BBType.CAP)
128 continue;
129
130 for (Edge eB : graphB.getEdgeList())
131 {
132 Vertex vB = eB.getTrgAP().getOwner();
133 // We don't do genetic operations on capping vertexes
134 if (vB.getBuildingBlockType() == BBType.CAP)
135 continue;
136
137 //Check condition for considering this combination
138 if (isCrossoverPossible(eA, eB, fragSpace))
139 {
140 if (compatibleVrtxPairs.size() >= maxCompatibleVrtxPairs)
141 {
142 needsRandomCap = true;
143 break scanCompatiblePairs;
144 }
145 Vertex[] pair = new Vertex[]{vA,vB};
146 compatibleVrtxPairs.add(pair);
147 }
148 }
149 }
150 if (needsRandomCap)
151 {
152 fragSpace.getLogger().log(Level.WARNING,
153 "Capped list of compatible xover vertex pairs at "
154 + maxCompatibleVrtxPairs);
155
156 Randomizer rng = fragSpace.getRandomizer();
157 List<Edge> edgesA = new ArrayList<Edge>(graphA.getEdgeList());
158 List<Edge> edgesB = new ArrayList<Edge>(graphB.getEdgeList());
159 rng.shuffle(edgesA);
160 rng.shuffle(edgesB);
161
162 compatibleVrtxPairs = new ArrayList<Vertex[]>();
163 collectRandomCompatiblePairs:
164 for (Edge eA : edgesA)
165 {
166 Vertex vA = eA.getTrgAP().getOwner();
167 if (vA.getBuildingBlockType() == BBType.CAP)
168 continue;
169
170 for (Edge eB : edgesB)
171 {
172 Vertex vB = eB.getTrgAP().getOwner();
173 if (vB.getBuildingBlockType() == BBType.CAP)
174 continue;
175
176 if (isCrossoverPossible(eA, eB, fragSpace))
177 {
178 Vertex[] pair = new Vertex[]{vA,vB};
179 compatibleVrtxPairs.add(pair);
180 if (compatibleVrtxPairs.size() >= maxCompatibleVrtxPairs)
181 {
182 break collectRandomCompatiblePairs;
183 }
184 }
185 }
186 }
187 }
188
189 // The crossover sites are the combination of the above compatible
190 // vertexes that define subgraphs respecting the requirements for
191 // being swapped between the two graphs.
192 ArrayList<XoverSite> sites = new ArrayList<XoverSite>();
193 for (Vertex[] pair : compatibleVrtxPairs)
194 {
195 Vertex vA = pair[0];
196 Vertex vB = pair[1];
197 DGraph gA = vA.getGraphOwner();
198 DGraph gB = vB.getGraphOwner();
199
200 // Here we also identify the branch identity of each descendant
201 List<Vertex> descendantsA = new ArrayList<Vertex>();
202 gA.getChildrenTree(vA, descendantsA, true);
203 List<Vertex> descendantsB = new ArrayList<Vertex>();
204 gB.getChildrenTree(vB, descendantsB, true);
205
206 // Branches that are isomorphic are not considered for crossover
207 DGraph test1 = gA.clone();
208 DGraph test2 = gB.clone();
209 try
210 {
211 DGraph subGraph1 = test1.extractSubgraph(gA.indexOf(vA));
212 DGraph subGraph2 = test2.extractSubgraph(gB.indexOf(vB));
213 if (maxSizeXoverSubGraph >= Math.max(subGraph1.getVertexCount(),
214 subGraph2.getVertexCount()))
215 {
216 if (!subGraph1.isIsomorphicTo(subGraph2))
217 {
218 List<Vertex> branchOnVA = new ArrayList<Vertex>();
219 branchOnVA.add(vA);
220 branchOnVA.addAll(descendantsA);
221 List<Vertex> branchOnVB = new ArrayList<Vertex>();
222 branchOnVB.add(vB);
223 branchOnVB.addAll(descendantsB);
224
225 checkAndAddXoverSites(fragSpace, branchOnVA, branchOnVB,
226 CrossoverType.BRANCH, sites,
227 maxAPMappingCombinations);
228 }
229 }
230 } catch (DENOPTIMException e)
231 {
232 //We should never end up here.
233 e.printStackTrace();
234 }
235
236 // To limit the number of combination, we first get rid of end-point
237 // candidates that cannot be used
238 List<Vertex[]> usablePairs = new ArrayList<Vertex[]>();
239
240 // To identify subgraphs smaller than the full branch we need to find
241 // where such subgraphs end, i.e., the vertexes at the end of
242 // such subgraphs (included in them), a.k.a. the subgraph ends.
243 // Since these subgraph ends will need to allow connection with the
244 // rest of the original graph, they are related to the
245 // already-identified crossover-compatible
246 // sites, i.e., they are the parents of the vertexes collected in
247 // compatibleVrtxPairs. Yet, we can combine them
248 // * in any number from 1 to all of them,
249 // * in any combination of the chosen number of them.
250 // Also, note that the ends need not to cover all the branches. So,
251 // some combinations will have to cut some branches short while
252 // taking some other branches completely till their last leaf.
253 for (Vertex[] otherPair : compatibleVrtxPairs)
254 {
255 // NB: the xover compatible sites are the child vertexes of the
256 // subgraph ends. So we need to get the parent
257 Vertex nextToEndOnA = otherPair[0];
258 Vertex nextToEndOnB = otherPair[1];
259 Vertex endOnA = nextToEndOnA.getParent();
260 Vertex endOnB = nextToEndOnB.getParent();
261 if (endOnA==null || endOnB==null)
262 continue;
263
264 // Exclude vertexes that are not downstream to the seed of the subgraph
265 if (!descendantsA.contains(endOnA) && endOnA!=vA
266 || !descendantsB.contains(endOnB) && endOnB!=vB)
267 continue;
268
269 // If any partner is a fixed-structure templates...
270 if ((gA.getTemplateJacket()!=null
273 || (gB.getTemplateJacket()!=null
276 {
277 //...the two paths must have same length. This would be
278 // checked anyway later when checking for isostructural
279 // subgraphs, but here it helps reducing the size of the
280 // combinatorial problem.
281 PathSubGraph pathA = new PathSubGraph(vA, endOnA);
282 PathSubGraph pathB = new PathSubGraph(vB, endOnB);
283 if (pathA.getPathLength()!=pathB.getPathLength())
284 continue;
285 }
286 Vertex[] pairOfEnds = new Vertex[]{endOnA,endOnB};
287 if (!usablePairs.contains(pairOfEnds))
288 usablePairs.add(pairOfEnds);
289 }
290
291 // We classify the pairs by branch ownership
292 TreeMap<String,List<Vertex[]>> sitesByBranchIdA =
293 new TreeMap<String,List<Vertex[]>>();
294 TreeMap<String,List<Vertex[]>> sitesByBranchIdB =
295 new TreeMap<String,List<Vertex[]>>();
296 for (Vertex[] pp : usablePairs)
297 {
298 String branchIdA = gA.getBranchIdOfVertexAsStr(pp[0]);
299 String branchIdB = gB.getBranchIdOfVertexAsStr(pp[1]);
300 if (sitesByBranchIdA.containsKey(branchIdA))
301 {
302 sitesByBranchIdA.get(branchIdA).add(pp);
303 } else {
304 ArrayList<Vertex[]> lst = new ArrayList<Vertex[]>();
305 lst.add(pp);
306 sitesByBranchIdA.put(branchIdA, lst);
307 }
308 if (sitesByBranchIdB.containsKey(branchIdB))
309 {
310 sitesByBranchIdB.get(branchIdB).add(pp);
311 } else {
312 ArrayList<Vertex[]> lst = new ArrayList<Vertex[]>();
313 lst.add(pp);
314 sitesByBranchIdB.put(branchIdB, lst);
315 }
316 }
317
318 // The side with the smallest set of branches determines the max
319 // number of pairs that can define a subgraph.
320 TreeMap<String,List<Vertex[]>> fewestBranchesSide = null;
321 if (sitesByBranchIdA.size() <= sitesByBranchIdB.size())
322 fewestBranchesSide = sitesByBranchIdA;
323 else
324 fewestBranchesSide = sitesByBranchIdB;
325
326 // Add the empty, i.e., the branch with empty is not cut short.
327 for (List<Vertex[]> val : fewestBranchesSide.values())
328 val.add(new Vertex[]{null,null});
329
330 // Generate the combinations: Cartesian product of multiple lists.
331 // NB: this combinatorial generator retains the
332 // sequence of generated subsets (important for reproducibility)
333 List<List<Vertex[]>> preCombsOfEnds = Generator.cartesianProduct(
334 fewestBranchesSide.values())
335 .stream()
336 .limit(maxEndPointsCombinations) //Prevent explosion!!!
337 .collect(Collectors.<List<Vertex[]>>toList());
338
339 // Remove the 'null,null' place holders that indicate the use of no
340 // end-point on a specific branch.
341 List<List<Vertex[]>> combsOfEnds = new ArrayList<List<Vertex[]>>();
342 for (List<Vertex[]> comb : preCombsOfEnds)
343 {
344 List<Vertex[]> nullPurgedComb = new ArrayList<Vertex[]>();
345 for (Vertex[] inPair : comb)
346 {
347 if (inPair[0]!=null && inPair[1]!=null)
348 nullPurgedComb.add(inPair);
349 }
350 // the case where all entries are null corresponds to use no
351 // end point on any branch, which is already considered above.
352 if (nullPurgedComb.size()>0)
353 combsOfEnds.add(nullPurgedComb);
354 }
355
356 // This would be a strategy to parallelize. However, this type of
357 // parallelization is not compatible with ensuring reproducibility.
358 // Perhaps, we could guarantee reproducibility by acting on the
359 // collector of sites as to ensure the list is sorted
360 // at the end of the generation of all possibilities.
361 /*
362 combsOfEnds
363 .parallelStream()
364 .limit(maxEndPointsCombinations) // Prevent explosion!
365 .forEach(c -> processCombinationOfEndPoints(pair, c, sites,
366 fragSpace, maxEndPointsPermutations,
367 maxAPMappingCombinations));
368 */
369
370 combsOfEnds.stream()
371 .limit(maxEndPointsCombinations) // Prevent explosion!
372 .forEach(c -> processCombinationOfEndPoints(pair, c, sites,
373 fragSpace, maxEndPointsPermutations,
374 maxAPMappingCombinations));
375 }
376
377 // NB: we consider only templates that are at the same level of embedding
378 for (Vertex vA : graphA.getVertexList())
379 {
380 if (!(vA instanceof Template))
381 continue;
382 Template tA = (Template) vA;
383
385 continue;
386
387 for (Vertex vB : graphB.getVertexList())
388 {
389 if (!(vB instanceof Template))
390 continue;
391 Template tB = (Template) vB;
392
394 continue;
395
397 tA.getInnerGraph(), tB.getInnerGraph(), fragSpace,
398 maxSizeXoverSubGraph, maxCompatibleVrtxPairs,
399 maxEndPointsCombinations, maxEndPointsPermutations,
400 maxAPMappingCombinations))
401 {
402 if (!sites.contains(xos))
403 sites.add(xos);
404 }
405 }
406 }
407 return sites;
408 }
409
410//------------------------------------------------------------------------------
411
426 private static void processCombinationOfEndPoints(Vertex[] pair,
427 List<Vertex[]> cominationOfEnds,
428 List<XoverSite> collector, FragmentSpace fragSpace,
429 int maxEndPointsPermutations, int maxAPMappingCombinations)
430 {
431 // Empty set corresponds to using the entire branch and subgraph and
432 // has been already dealt with at this point
433 if (cominationOfEnds.size()==0)
434 return;
435
436 // This would be a strategy to parallelize. However, this type of
437 // parallelization is not compatible with ensuring reproducibility.
438 // Perhaps, we could guarantee reproducibility by acting on the
439 // collector as to ensure the list of collected results is sorted
440 // at the end of the generation of all possibilities
441 /*
442 List<List<Vertex[]>> permutsOfEnds = new ArrayList<List<Vertex[]>>();
443 Generator.subset(cominationOfEnds)
444 .simple()
445 .stream()
446 .limit(100) // Prevent explosion!
447 .forEach(c -> permutsOfEnds.add(c));
448 permutsOfEnds
449 .parallelStream()
450 .forEach(c -> processPermutationOfEndPoints(pair, c, collector,
451 fragSpace, maxAPMappingCombinations));
452 */
453
454 Generator.permutation(cominationOfEnds)
455 .simple()
456 .stream()
457 .limit(maxEndPointsPermutations) // Prevent explosion!
458 .forEach(c -> processPermutationOfEndPoints(pair, c, collector,
459 fragSpace, maxAPMappingCombinations));
460 }
461
462//------------------------------------------------------------------------------
463
477 private static void processPermutationOfEndPoints(Vertex[] pair,
478 List<Vertex[]> chosenSequenceOfEndpoints,
479 List<XoverSite> collector, FragmentSpace fragSpace,
480 int maxAPMappingCombinations)
481 {
482 Vertex vA = pair[0];
483 Vertex vB = pair[1];
484 DGraph gA = vA.getGraphOwner();
485 DGraph gB = vB.getGraphOwner();
486
487 // Exclude overlapping combinations
488 boolean exclude = false;
489 for (Vertex[] pairA : chosenSequenceOfEndpoints)
490 {
491 for (Vertex[] pairB : chosenSequenceOfEndpoints)
492 {
493 if (pairA==pairB)
494 continue;
495
496 if (pairA[0]==pairB[0] || pairA[1]==pairB[1])
497 {
498 exclude = true;
499 break;
500 }
501 }
502 if (exclude)
503 break;
504 }
505 if (exclude)
506 return;
507
508 List<Vertex> subGraphEndInA = new ArrayList<Vertex>();
509 List<Vertex> subGraphEndInB = new ArrayList<Vertex>();
510 List<Vertex> alreadyIncludedFromA = new ArrayList<Vertex>();
511 List<Vertex> alreadyIncludedFromB = new ArrayList<Vertex>();
512 for (Vertex[] otherPair : chosenSequenceOfEndpoints)
513 {
514 Vertex endOnA = otherPair[0];
515 Vertex endOnB = otherPair[1];
516
517 // Ignore vertexes that are already part of the subgraph
518 if (alreadyIncludedFromA.contains(endOnA)
519 || alreadyIncludedFromB.contains(endOnB))
520 continue;
521
522 PathSubGraph pathA = null;
523 try {
524 pathA = new PathSubGraph(vA, endOnA);
525 } catch (DENOPTIMException e) {
526 e.printStackTrace();
527 }
528 PathSubGraph pathB = null;
529 try {
530 pathB = new PathSubGraph(vB, endOnB);
531 } catch (DENOPTIMException e) {
532 e.printStackTrace();
533 }
534 subGraphEndInA.add(endOnA);
535 subGraphEndInB.add(endOnB);
536 alreadyIncludedFromA.addAll(pathA.getVertecesPath());
537 alreadyIncludedFromB.addAll(pathB.getVertecesPath());
538 }
539 ArrayList<Vertex> subGraphA = new ArrayList<Vertex>();
540 subGraphA.add(vA);
541 if (!subGraphEndInA.contains(vA))
542 gA.getChildTreeLimited(vA, subGraphA, subGraphEndInA, true);
543
544 ArrayList<Vertex> subGraphB = new ArrayList<Vertex>();
545 subGraphB.add(vB);
546 if (!subGraphEndInB.contains(vB))
547 gB.getChildTreeLimited(vB, subGraphB, subGraphEndInB, true);
548
549 // The two subgraphs must not be isomorfic to prevent unproductive crossover
550 if (subGraphA.size()>1 && subGraphB.size()>1)
551 {
552 DGraph subGraphCloneA = gA.extractSubgraph(subGraphA);
553 DGraph subGraphCloneB = gB.extractSubgraph(subGraphB);
554 if (subGraphCloneA.isIsomorphicTo(subGraphCloneB))
555 return;
556 } else {
557 if (subGraphA.get(0).sameAs(subGraphB.get(0), new StringBuilder()))
558 return;
559 }
560
561 checkAndAddXoverSites(fragSpace, subGraphA, subGraphB,
562 CrossoverType.SUBGRAPH, collector, maxAPMappingCombinations);
563 }
564
565//------------------------------------------------------------------------------
566
576 private static void checkAndAddXoverSites(FragmentSpace fragSpace,
577 List<Vertex> subGraphA,
578 List<Vertex> subGraphB, CrossoverType xoverType,
579 List<XoverSite> collector, int maxAPMappingCombinations)
580 {
581 DGraph gOwnerA = subGraphA.get(0).getGraphOwner();
582 DGraph gOwnerB = subGraphB.get(0).getGraphOwner();
583
584 // What APs need to find a corresponding AP in the other
585 // subgraph in order to allow swapping?
586 List<AttachmentPoint> needyAPsA = gOwnerA.getInterfaceAPs(
587 subGraphA);
588 List<AttachmentPoint> allAPsA = gOwnerA.getSubgraphAPs(
589 subGraphA);
590 List<AttachmentPoint> needyAPsB = gOwnerB.getInterfaceAPs(
591 subGraphB);
592 List<AttachmentPoint> allAPsB = gOwnerB.getSubgraphAPs(
593 subGraphB);
594 if (allAPsA.size() < needyAPsB.size()
595 || allAPsB.size() < needyAPsA.size())
596 {
597 // Impossible to satisfy needy APs. Crossover site is not usable.
598 return;
599 }
600
601 // Shortcut: since the compatibility of one AP that is needed to do
602 // branch swapping is guaranteed by the identification of the seeds of
603 // swappable subgraphs, we can avoid searching for a valid A mapping
604 // when the graphs are not embedded. This because any AP that is not
605 // the one connecting the subgraph to the parent can be left free or
606 // removed without side effects on templates that embed the graph
607 // because there is no such template.
608 Template jacketTmplA = gOwnerA.getTemplateJacket();
609 Template jacketTmplB = gOwnerB.getTemplateJacket();
610 if (xoverType == CrossoverType.BRANCH
611 && jacketTmplA==null
612 && jacketTmplB==null)
613 {
614 XoverSite xos = new XoverSite(subGraphA, needyAPsA, subGraphB,
615 needyAPsB, xoverType);
616 if (!collector.contains(xos))
617 collector.add(xos);
618 return;
619 }
620
621 if ((jacketTmplA!=null && jacketTmplA.getContractLevel()
623 || (jacketTmplB!=null && jacketTmplB.getContractLevel()
625 {
626 // Avoid to alter cyclicity of inner graphs
627 for (Vertex v : subGraphA)
628 if (v.isRCV() && !gOwnerA.getRingsInvolvingVertex(v).isEmpty())
629 return;
630 for (Vertex v : subGraphB)
631 if (v.isRCV() && !gOwnerB.getRingsInvolvingVertex(v).isEmpty())
632 return;
633
634 // Avoid to change the structure of inner graphs
635 DGraph subGraphCloneA = gOwnerA.extractSubgraph(subGraphA);
636 DGraph subGraphCloneB = gOwnerB.extractSubgraph(subGraphB);
637 if (!subGraphCloneA.isIsostructuralTo(subGraphCloneB))
638 return;
639 }
640
641 // Retain connection to parent to keep directionality of spanning tree!
642 // To this end, identify the seed of the subgraphs...
643 Vertex seedOnA = gOwnerA.getDeepestAmongThese(subGraphA);
644 Vertex seedOnB = gOwnerB.getDeepestAmongThese(subGraphB);
645 //...and ensure we use the same APs to link to the parent graph.
646 APMapping fixedRootAPs = new APMapping();
647 fixedRootAPs.put(seedOnA.getEdgeToParent().getTrgAP(),
648 seedOnB.getEdgeToParent().getTrgAP());
649
650 APMapFinder apmf = new APMapFinder(fragSpace,
651 allAPsA, needyAPsA, allAPsB, needyAPsB,
652 fixedRootAPs,
653 false, // false: we stop at the first good mapping
654 true, // true: only complete mapping
655 false, // false: free APs are not compatible by default
656 maxAPMappingCombinations);
657 if (apmf.foundMapping())
658 {
659 XoverSite xos = new XoverSite(subGraphA, needyAPsA,
660 subGraphB, needyAPsB, xoverType);
661 if (!collector.contains(xos))
662 collector.add(xos);
663 }
664 }
665
666//------------------------------------------------------------------------------
667
679 private static boolean isCrossoverPossible(Edge eA, Edge eB,
680 FragmentSpace fragSpace)
681 {
682 APClass apClassSrcA = eA.getSrcAPClass();
683 APClass apClassTrgA = eA.getTrgAPClass();
684 APClass apClassSrcB = eB.getSrcAPClass();
685 APClass apClassTrgB = eB.getTrgAPClass();
686
687 if (apClassSrcA.isCPMapCompatibleWith(apClassTrgB, fragSpace))
688 {
689 if (apClassSrcB.isCPMapCompatibleWith(apClassTrgA, fragSpace))
690 {
691 return true;
692 }
693 }
694 return false;
695 }
696
697//------------------------------------------------------------------------------
698
710 protected static boolean deleteLink(Vertex vertex,
711 int chosenVrtxIdx, Monitor mnt, FragmentSpace fragSpace)
712 throws DENOPTIMException
713 {
714 DGraph graph = vertex.getGraphOwner();
715 boolean done = graph.removeVertexAndWeld(vertex, fragSpace);
716 if (!done)
717 {
719 }
720 return done;
721 }
722
723//------------------------------------------------------------------------------
724
741 protected static boolean substituteLink(Vertex vertex,
742 int chosenVrtxIdx, Monitor mnt, FragmentSpace fragSpace)
743 throws DENOPTIMException
744 {
745 //TODO: for reproducibility, the AP mapping should become an optional
746 // parameter: if given we try to use it, if not given, GraphLinkFinder
747 // will try to find a suitable mapping.
748
749 GraphLinkFinder glf = null;
750 if (chosenVrtxIdx<0)
751 {
752 glf = new GraphLinkFinder(fragSpace, vertex);
753 } else {
754 glf = new GraphLinkFinder(fragSpace, vertex, chosenVrtxIdx);
755 }
756 if (!glf.foundAlternativeLink())
757 {
759 return false;
760 }
761
762 DGraph graph = vertex.getGraphOwner();
763 boolean done = graph.replaceVertex(vertex,
767 fragSpace);
768 if (!done)
769 {
770 mnt.increase(
772 }
773 return done;
774 }
775
776//------------------------------------------------------------------------------
777
793 public static boolean extendLink(Vertex vertex,
794 int chosenAPId, Monitor mnt, FragmentSpace fragSpace)
795 throws DENOPTIMException
796 {
797 return extendLink(vertex, chosenAPId, -1 , mnt, fragSpace);
798 }
799
800//------------------------------------------------------------------------------
801
819 public static boolean extendLink(Vertex vertex, int chosenAPId,
820 int chosenNewVrtxId, Monitor mnt, FragmentSpace fragSpace)
821 throws DENOPTIMException
822 {
823 AttachmentPoint ap = vertex.getAP(chosenAPId);
824 if (ap == null)
825 {
826 throw new DENOPTIMException("No AP "+chosenAPId+" in vertex "
827 +vertex+".");
828 }
830
831 if (e == null)
832 {
833 throw new DENOPTIMException("AP "+chosenAPId+" in vertex "
834 +vertex+" has no edge user.");
835 }
836 if (e.getSrcAP().getOwner() != vertex)
837 {
838 throw new DENOPTIMException("Request to extend a link from a child "
839 + "vertex (AP "+chosenAPId+" of vertex "+vertex+").");
840 }
841 return extendLink(e, chosenNewVrtxId, mnt, fragSpace);
842 }
843
844//------------------------------------------------------------------------------
845
858 public static boolean extendLink(Edge edge, int chosenBBIdx,
859 Monitor mnt, FragmentSpace fragSpace) throws DENOPTIMException
860 {
861 //TODO: for reproducibility, the AP mapping should become an optional
862 // parameter: if given we try to use it, if not given we GraphLinkFinder
863 // will try to find a suitable mapping.
864
865 GraphLinkFinder glf = null;
866 if (chosenBBIdx < 0)
867 {
868 glf = new GraphLinkFinder(fragSpace, edge);
869 } else {
870 glf = new GraphLinkFinder(fragSpace, edge,chosenBBIdx);
871 }
872 if (!glf.foundAlternativeLink())
873 {
875 return false;
876 }
877
878 // Need to convert the mapping to make it independent from the instance
879 // or the new link.
880 LinkedHashMap<AttachmentPoint,Integer> apMap =
881 new LinkedHashMap<AttachmentPoint,Integer>();
882 for (Entry<AttachmentPoint, AttachmentPoint> e :
883 glf.getChosenAPMapping().entrySet())
884 {
885 apMap.put(e.getKey(), e.getValue().getIndexInOwner());
886 }
887
888 DGraph graph = edge.getSrcAP().getOwner().getGraphOwner();
889 boolean done = graph.insertVertex(edge,
892 apMap, fragSpace);
893 if (!done)
894 {
895 mnt.increase(
897 }
898 return done;
899 }
900
901//------------------------------------------------------------------------------
902
924 protected static boolean rebuildBranch(Vertex vertex,
925 boolean force, int chosenVrtxIdx, int chosenApId,
926 GAParameters settings) throws DENOPTIMException
927 {
928 DGraph g = vertex.getGraphOwner();
929
930 // first get the edge with the parent
931 Edge e = vertex.getEdgeToParent();
932 if (e == null)
933 {
934 String msg = "Program Bug in substituteFragment: Unable to locate "
935 + "parent edge for vertex "+vertex+" in graph "+g;
936 settings.getLogger().log(Level.SEVERE, msg);
937 throw new DENOPTIMException(msg);
938 }
939
940 // vertex id of the parent
941 long pvid = e.getSrcVertex();
942 Vertex parentVrt = g.getVertexWithId(pvid);
943
944 // Need to remember symmetry because we are deleting the symm. vertices
945 boolean symmetry = g.hasSymmetryInvolvingVertex(vertex);
946
947 // delete the vertex and its children and all its symmetric partners
948 deleteFragment(vertex);
949
950 // extend the graph at this vertex but without recursion
951 return extendGraph(parentVrt,false,symmetry,force,chosenVrtxIdx,
952 chosenApId, settings);
953 }
954
955//------------------------------------------------------------------------------
956
965 protected static boolean deleteFragment(Vertex vertex)
966 throws DENOPTIMException
967 {
968 long vid = vertex.getVertexId();
969 DGraph molGraph = vertex.getGraphOwner();
970
971 if (molGraph.hasSymmetryInvolvingVertex(vertex))
972 {
973 List<Vertex> toRemove = new ArrayList<Vertex>();
974 toRemove.addAll(molGraph.getSymSetForVertex(vertex));
975 for (Vertex v : toRemove)
976 {
977 molGraph.removeBranchStartingAt(v);
978 }
979 }
980 else
981 {
982 molGraph.removeBranchStartingAt(vertex);
983 }
984
985 if (molGraph.getVertexWithId(vid) == null && molGraph.getVertexCount() > 1)
986 return true;
987
988 return false;
989 }
990
991//------------------------------------------------------------------------------
992
1005 protected static boolean deleteChain(Vertex vertex, Monitor mnt,
1006 FragmentSpace fragSpace) throws DENOPTIMException
1007 {
1008 long vid = vertex.getVertexId();
1009 DGraph molGraph = vertex.getGraphOwner();
1010
1011 if (molGraph.hasSymmetryInvolvingVertex(vertex))
1012 {
1013 List<Vertex> toRemove = new ArrayList<Vertex>();
1014 toRemove.addAll(molGraph.getSymSetForVertex(vertex));
1015 for (Vertex v : toRemove)
1016 {
1017 if (!v.getMutationTypes(new ArrayList<MutationType>())
1018 .contains(MutationType.DELETECHAIN))
1019 continue;
1020 molGraph.removeChainUpToBranching(v, fragSpace);
1021 }
1022 }
1023 else
1024 {
1025 molGraph.removeChainUpToBranching(vertex, fragSpace);
1026 }
1027
1028 if (molGraph.getVertexWithId(vid) == null && molGraph.getVertexCount() > 1)
1029 return true;
1030 return false;
1031 }
1032
1033//------------------------------------------------------------------------------
1034
1050 protected static boolean addRing(Vertex vertex, Monitor mnt, boolean force,
1051 FragmentSpace fragSpace, GAParameters settings)
1052 throws DENOPTIMException
1053 {
1054 // get settings //TODO: this should happen inside RunTimeParameters
1056 if (settings.containsParameters(ParametersType.RC_PARAMS))
1057 {
1058 rcParams = (RingClosureParameters)settings.getParameters(
1060 }
1061 Randomizer rng = settings.getRandomizer();
1062
1063 // First of all we remove capping groups in the graph
1064 vertex.getGraphOwner().removeCappingGroups();
1065
1066 List<AttachmentPoint> freeeAPs = vertex.getFreeAPThroughout();
1067 if (freeeAPs.size()==0)
1068 {
1070 return false;
1071 }
1072 DGraph originalGraph = vertex.getGraphOwner();
1073 DGraph tmpGraph = originalGraph.clone();
1074
1075 Vertex headVrtx = tmpGraph.getVertexAtPosition(originalGraph.indexOf(
1076 vertex));
1077
1078 // Define the set of rings on the cloned (tmp) graph
1079 List<Ring> setOfRingsOnTmpGraph = null;
1080 for (AttachmentPoint srcAP : headVrtx.getFreeAPThroughout())
1081 {
1082 APClass apc = srcAP.getAPClass();
1083
1084 // Skip if the APClass is not allowed to form ring closures
1085 if (!fragSpace.getRCCompatibilityMatrix().containsKey(apc))
1086 {
1087 continue;
1088 }
1089 List<APClass> rcTrgAPCs = fragSpace.getRCCompatibilityMatrix().get(
1090 apc);
1091
1092 // NB: the fragment space may or may not have a RCV for this AP
1093 Vertex rcvOnSrcAP = null;
1094 List<Vertex> candidateRCVs = fragSpace.getRCVsForAPClass(apc);
1095 boolean rcvIsChosenArbitrarily = false;
1096 if (candidateRCVs.size()>0)
1097 {
1098 rcvOnSrcAP = rng.randomlyChooseOne(candidateRCVs);
1099 } else {
1100 rcvIsChosenArbitrarily = true;
1101 rcvOnSrcAP = fragSpace.getPolarizedRCV(true);
1102 }
1103
1104 // Add the RCV on this AP
1105 List<Vertex> rcvAddedToGraph = new ArrayList<Vertex>();
1106 tmpGraph.appendVertexOnAP(srcAP, rcvOnSrcAP.getAP(0));
1107 rcvAddedToGraph.add(rcvOnSrcAP);
1108
1109 // Add a few RCVs in the rest of the system
1110 // WARNING: hard-coded max number of attempts. It should not be too
1111 // high to prevent combinatorial explosion.
1112 for (int i=0; i<20; i++)
1113 {
1114 // Do it only on APs that APClass-compatible with chord formation
1115 List<AttachmentPoint> apsToTry =
1116 tmpGraph.getAvailableAPsThroughout();
1117 int numberOfAttempts = apsToTry.size();
1118 AttachmentPoint trgAP = null;
1119 for (int iap=0; iap<numberOfAttempts; iap++)
1120 {
1121 AttachmentPoint candidate = rng.randomlyChooseOne(apsToTry);
1122 if (rcTrgAPCs.contains(candidate.getAPClass()))
1123 {
1124 trgAP = candidate;
1125 break;
1126 }
1127 apsToTry.remove(trgAP);
1128 }
1129 if (trgAP==null)
1130 {
1131 // No more AP can be used to form rings with srcAP
1132 break;
1133 }
1134
1135 // Choose type of RCV
1136 Vertex rcvOnTrgAP = null;
1137 if (rcvIsChosenArbitrarily)
1138 {
1139 rcvOnTrgAP = fragSpace.getPolarizedRCV(false);
1140 } else {
1141 List<Vertex> candRCVs = fragSpace.getRCVsForAPClass(
1142 trgAP.getAPClass());
1143 if (candRCVs.size()>0)
1144 {
1145 APClass requiredAPC = RingClosingAttractor.RCAAPCMAP.get(
1146 rcvOnSrcAP.getAP(0).getAPClass());
1147 List<Vertex> keptRCVs = new ArrayList<Vertex>();
1148 for (Vertex rcv : candRCVs)
1149 {
1150 if (requiredAPC.equals(rcv.getAP(0).getAPClass()))
1151 keptRCVs.add(rcv);
1152 }
1153 rcvOnTrgAP = rng.randomlyChooseOne(keptRCVs);
1154 if (rcvOnTrgAP==null)
1155 {
1156 // no RCV is both usable and compatible with the
1157 // one already selected for srcAP
1158 continue;
1159 }
1160 } else {
1161 // The APClass settings and RCV compatibility rules
1162 // do not allow to identify a suitable RCV
1163 continue;
1164 }
1165 }
1166
1167 // append RCV
1168 tmpGraph.appendVertexOnAP(trgAP, rcvOnTrgAP.getAP(0));
1169 rcvAddedToGraph.add(rcvOnTrgAP);
1170 }
1171 if (rcvAddedToGraph.size() < 2)
1172 {
1173 // TODO: we could consider counting these to see what is the
1174 // most frequent cause of this mutation to fail
1175 continue;
1176 }
1177
1178 // Define rings to close in tmp graph
1180 settings.getLogger(), rng);
1181 t3d.setAlignBBsIn3D(false); //3D not needed
1182 IAtomContainer mol = t3d.convertGraphTo3DAtomContainer(tmpGraph,true);
1184 mol,
1185 tmpGraph,
1186 settings.getMaxRingsAddedByMutation(),
1187 fragSpace, rcParams);
1188
1189 //TODO: possibility to generate multiple combinations, rank them,
1190 // and pick the best one. Though definition of comparator is not
1191 // unambiguous.
1192
1193 setOfRingsOnTmpGraph = rCombIter.next();
1194
1195 // Termination of search over trgAPs
1196 if (setOfRingsOnTmpGraph.size()>0)
1197 break;
1198
1199 // Cleanup before starting new iteration
1200 for (Vertex toRemove : rcvAddedToGraph)
1201 tmpGraph.removeVertex(toRemove);
1202 }
1203 if (setOfRingsOnTmpGraph==null || setOfRingsOnTmpGraph.size()==0)
1204 {
1206 return false;
1207 }
1208
1209 // Project rings into the actual graph
1210 boolean done = false;
1211 for (Ring rOnTmp : setOfRingsOnTmpGraph)
1212 {
1213 // Project head RCV and all info to attach it to original graph
1214 Vertex vToHeadRCV = originalGraph.getVertexAtPosition(
1215 tmpGraph.indexOf(rOnTmp.getHeadVertex().getParent()));
1216 AttachmentPoint apToHeadRCV = vToHeadRCV.getAP(
1217 rOnTmp.getHeadVertex().getEdgeToParent().getSrcAP()
1218 .getIndexInOwner());
1219 Vertex headRCV = null;
1220 if (!apToHeadRCV.isAvailable())
1221 {
1222 headRCV = apToHeadRCV.getLinkedAP().getOwner();
1223 } else {
1224 headRCV = rOnTmp.getHeadVertex().clone();
1226 // And append head RCV on original graph
1227 originalGraph.appendVertexOnAP(apToHeadRCV, headRCV.getAP(0));
1228 }
1229
1230 // Project tail RCV and all info to attach it to original graph
1231 Vertex vToTailRCV = originalGraph.getVertexAtPosition(
1232 tmpGraph.indexOf(rOnTmp.getTailVertex().getParent()));
1233 AttachmentPoint apToTailRCV = vToTailRCV.getAP(
1234 rOnTmp.getTailVertex().getEdgeToParent().getSrcAP()
1235 .getIndexInOwner());
1236 Vertex tailRCV = null;
1237 if (!apToTailRCV.isAvailable())
1238 {
1239 tailRCV = apToTailRCV.getLinkedAP().getOwner();
1240 } else {
1241 tailRCV = rOnTmp.getTailVertex().clone();
1243 // And append tail RCV on original graph
1244 originalGraph.appendVertexOnAP(apToTailRCV, tailRCV.getAP(0));
1245 }
1246
1247 // Add ring
1248 originalGraph.addRing(headRCV, tailRCV);
1249 done = true;
1250 }
1251
1252 // Restore capping groups
1253 vertex.getGraphOwner().addCappingGroups(fragSpace);
1254
1255 return done;
1256 }
1257
1258//------------------------------------------------------------------------------
1259
1275 protected static boolean addFusedRing(Vertex vertex, Monitor mnt,
1276 boolean force, FragmentSpace fragSpace, GAParameters settings)
1277 throws DENOPTIMException
1278 {
1279 // get settings //TODO: this should happen inside RunTimeParameters
1281 if (settings.containsParameters(ParametersType.RC_PARAMS))
1282 {
1283 rcParams = (RingClosureParameters)settings.getParameters(
1285 }
1286
1287 Randomizer rng = settings.getRandomizer();
1288
1289 // First of all we remove capping groups in the graph
1290 vertex.getGraphOwner().removeCappingGroups();
1291
1292 List<AttachmentPoint> freeAPs = vertex.getFreeAPThroughout();
1293 if (freeAPs.size()==0)
1294 {
1296 return false;
1297 }
1298
1299 DGraph graph = vertex.getGraphOwner();
1300
1301 // Define where to add a bridge. Multiple sites are the result of
1302 // symmetry, so they all correspond to the same kind of operation
1303 // performed on symmetry-related sites
1304 List<List<RelatedAPPair>> candidatePairsSets =
1306 graph,
1307 fragSpace,
1308 rcParams,
1309 rng.nextBoolean(settings.getSymmetryProbability()),
1310 settings.getLogger(), rng);
1311 if (candidatePairsSets.size()==0)
1312 {
1314 return false;
1315 }
1316
1317 // Bias by potential ring size considering the existing part of the
1318 // to-be-created ring.
1319 // NB: we have to do this twice because some sites may be used to
1320 // form rings with different sizes. So, see below for the second time...
1321 List<List<RelatedAPPair>> szBiasedCandidatePairsSets =
1322 new ArrayList<List<RelatedAPPair>>();
1323 for (List<RelatedAPPair> pairSet : candidatePairsSets)
1324 {
1326 pairSet.get(0).property;
1327 int existingBridgeLength = bhfrOfPair.getExistingBridgeLength();
1328 int[] allowedBridgeLengths = bhfrOfPair.getAllowedBridgeLength(
1329 rcParams.getMaxRingSize());
1330 for (int i=0; i<allowedBridgeLengths.length; i++)
1331 {
1332 int allowedBridgeLength = allowedBridgeLengths[i];
1333 int possibleRingSize = allowedBridgeLength
1334 + existingBridgeLength;
1335 int weight = 1; // weight of a ring size
1336 if (possibleRingSize < rcParams.getMaxRingSize())
1337 {
1338 weight = rcParams.getRingSizeBias().get(possibleRingSize);
1339 }
1340
1341 // We add copies of the same set to the list of candidate
1342 // sets, so when we randomly choose we are more likely to
1343 // choose a set that leads to preferred ring sizes.
1344 for (int z=0; z<weight; z++)
1345 {
1346 szBiasedCandidatePairsSets.add(pairSet);
1347 }
1348 }
1349 }
1350 if (szBiasedCandidatePairsSets.size()==0)
1351 {
1353 return false;
1354 }
1355
1356 // Select one combination
1357 List<RelatedAPPair> chosenPairsSet = rng.randomlyChooseOne(
1358 szBiasedCandidatePairsSets);
1359
1360 // Based on the chosen pair, decide on the number of electrons to use
1361 // in the incoming fragment that will be used to close the ring
1362 // the pairs are all the same kind of ring fusion, so just take the 1st
1363 String elsInHalfFrag = chosenPairsSet.get(0).propID.substring(0,1);
1364 if (elsInHalfFrag.matches("[a-zA-Z]"))
1365 elsInHalfFrag = "0";
1366 boolean newRingIsAromatic = true;
1367 String elInIncomingFrag = "0el";
1368 switch (elsInHalfFrag)
1369 {
1370 case "0":
1371 case "1":
1372 // no aromaticity to be retained: use non-aromatic chords
1373 elInIncomingFrag = "0el";
1374 newRingIsAromatic = false;
1375 break;
1376
1377 case "2":
1378 // Formally we can use any fragment delivering 4n electrons.
1379 // Effectively, we have only 4-el fragments
1380 elInIncomingFrag = "4el";
1381 break;
1382
1383 case "3":
1384 // We could use a 5-el fragment, but the 8-el aromatic system is
1385 // so rare that we avoid it. So, we can only use 3-el fragment
1386 elInIncomingFrag = "3el";
1387 break;
1388
1389 case "4":
1390 // Effectively can only use 2-el fragments
1391 elInIncomingFrag = "2el";
1392 break;
1393
1394 case "5":
1395 // We could use a 3-el fragment, but the 8-el aromatic system is
1396 // so rare that we avoid it. This could become a tunable config
1397 elInIncomingFrag = "1el";
1398 break;
1399 default:
1400 throw new Error("Unknown number of pi-electrons in fragment to "
1401 + "be used for ring fusion operation.");
1402 }
1403
1404 // Collect fragment that can be used as ring-closing bridge based on the
1405 // number of aromatic electrons and number of atoms
1407 chosenPairsSet.get(0).property;
1408
1409 List<Vertex> usableBridges = null;
1410 if (newRingIsAromatic)
1411 {
1412 usableBridges = EAUtils.getUsableAromaticBridges(
1413 elInIncomingFrag,
1414 bhfr.getAllowedBridgeLength(rcParams.getMaxRingSize()),
1415 fragSpace);
1416 } else {
1417 // NB: we keep track of which APs are supposed to be used to form
1418 // the bridge by recording their index in a property of the vertex
1419 usableBridges = EAUtils.getUsableAliphaticBridges(
1420 chosenPairsSet.get(0).apA.getAPClass(),
1421 chosenPairsSet.get(0).apB.getAPClass(),
1422 bhfr.getAllowedBridgeLength(rcParams.getMaxRingSize()),
1423 fragSpace);
1424 }
1425
1426 if (usableBridges.size()==0)
1427 {
1429 return false;
1430 }
1431
1432 // Select size of the incoming bridge based on ring-size biases
1433 // NB: we have to do this twice because some sites may be used to
1434 // form rings with different sizes. So, see above for the first time...
1435 List<Vertex> szBiasedUsableBridges = new ArrayList<Vertex>();
1436 for (Vertex candidateBridge : usableBridges)
1437 {
1438 int thisBridgeLength = (int) candidateBridge.getProperty(
1440 int existingBridgeLength = bhfr.getExistingBridgeLength();
1441 int resultingRingSize = existingBridgeLength + thisBridgeLength;
1442 int weigth = 1; // weight of a ring size
1443 if (resultingRingSize < rcParams.getMaxRingSize())
1444 {
1445 weigth = rcParams.getRingSizeBias().get(resultingRingSize);
1446 }
1447
1448 // We add copies of the same vertex to the list of candidate
1449 // vertexes, so when we randomly choose we are more likely to
1450 // choose those leading to preferred ring sizes.
1451 for (int z=0; z<weigth; z++)
1452 {
1453 szBiasedUsableBridges.add(candidateBridge);
1454 }
1455 }
1456
1457 if (szBiasedUsableBridges.size()==0)
1458 {
1460 return false;
1461 }
1462
1463 Vertex incomingVertex = rng.randomlyChooseOne(szBiasedUsableBridges);
1464
1465 // Decide which aps on the bridge are used as head/tail
1466 List<AttachmentPoint> apsInFusion = new ArrayList<AttachmentPoint>();
1467 int[] idApOnBridge = new int[2];
1468 if (newRingIsAromatic)
1469 {
1470 apsInFusion.addAll(incomingVertex.getAPsWithAPClassStartingWith(
1471 elInIncomingFrag));
1472 if (rng.nextBoolean())
1473 {
1474 idApOnBridge[0] = apsInFusion.get(0).getIndexInOwner();
1475 idApOnBridge[1] = apsInFusion.get(1).getIndexInOwner();
1476 } else {
1477 idApOnBridge[0] = apsInFusion.get(1).getIndexInOwner();
1478 idApOnBridge[1] = apsInFusion.get(0).getIndexInOwner();
1479 }
1480 } else {
1481 idApOnBridge[0] = Integer.parseInt(incomingVertex.getProperty(
1483 idApOnBridge[1] = Integer.parseInt(incomingVertex.getProperty(
1485 }
1486
1487 if (idApOnBridge[0] == idApOnBridge[1])
1488 {
1490 return false;
1491 }
1492
1493 boolean done = false;
1494 for (RelatedAPPair pairOfAPs : chosenPairsSet)
1495 {
1496 AttachmentPoint apHead = pairOfAPs.apA;
1497 AttachmentPoint apTail = pairOfAPs.apB;
1498 if (apHead == apTail
1499 || !apHead.isAvailableThroughout()
1500 || !apTail.isAvailableThroughout())
1501 {
1502 continue;
1503 }
1504
1505 Vertex bridgeClone = incomingVertex.clone();
1506 bridgeClone.setVertexId(graph.getMaxVertexId()+1);
1507
1508 graph.appendVertexOnAP(apHead, bridgeClone.getAP(idApOnBridge[0]));
1509
1510 Vertex rcvBridge = fragSpace.getPolarizedRCV(true);
1511 graph.appendVertexOnAP(bridgeClone.getAP(idApOnBridge[1]),
1512 rcvBridge.getAP(0));
1513
1514 Vertex rcvTail = fragSpace.getPolarizedRCV(false);
1515 graph.appendVertexOnAP(apTail, rcvTail.getAP(0));
1516 graph.addRing(rcvBridge, rcvTail);
1517 done = true;
1518 }
1519
1520 // Restore capping groups
1521 vertex.getGraphOwner().addCappingGroups(fragSpace);
1522
1523 return done;
1524 }
1525
1526//------------------------------------------------------------------------------
1527
1542 protected static boolean extendGraph(Vertex curVertex,
1543 boolean extend,
1544 boolean symmetryOnAps,
1545 GAParameters settings)
1546 throws DENOPTIMException
1547 {
1548 return extendGraph(curVertex, extend, symmetryOnAps, false, -1, -1,
1549 settings);
1550 }
1551
1552//------------------------------------------------------------------------------
1553
1577 protected static boolean extendGraph(Vertex curVrtx,
1578 boolean extend,
1579 boolean symmetryOnAps,
1580 boolean force,
1581 int chosenVrtxIdx,
1582 int chosenApId,
1583 GAParameters settings)
1584 throws DENOPTIMException
1585 {
1586 // get settings //TODO: this should happen inside RunTimeParameters
1588 if (settings.containsParameters(ParametersType.RC_PARAMS))
1589 {
1590 rcParams = (RingClosureParameters)settings.getParameters(
1592 }
1594 if (settings.containsParameters(ParametersType.FS_PARAMS))
1595 {
1596 fsParams = (FragmentSpaceParameters)settings.getParameters(
1598 }
1599 int maxHeavyAtoms = fsParams.getMaxHeavyAtom();
1600
1601 // return true if the append has been successful
1602 boolean status = false;
1603
1604 // check if the fragment has available APs
1605 if (!curVrtx.hasFreeAP())
1606 {
1607 return status;
1608 }
1609
1610 DGraph molGraph = curVrtx.getGraphOwner();
1611 int lvl = molGraph.getLevel(curVrtx);
1612
1613 ArrayList<Long> addedVertices = new ArrayList<>();
1614
1615 List<AttachmentPoint> lstDaps = curVrtx.getAttachmentPoints();
1616 List<AttachmentPoint> toDoAPs = new ArrayList<AttachmentPoint>();
1617 toDoAPs.addAll(lstDaps);
1618 for (int i=0; i<lstDaps.size(); i++)
1619 {
1620 // WARNING: randomization decouples 'i' from the index of the AP
1621 // in the vertex's list of APs! So 'i' is just the i-th attempt on
1622 // the curVertex.
1623
1624 AttachmentPoint ap = settings.getRandomizer().randomlyChooseOne(
1625 toDoAPs);
1626 toDoAPs.remove(ap);
1627 int apId = ap.getIndexInOwner();
1628
1629 // is it possible to extend on this AP?
1630 if (!ap.isAvailable())
1631 {
1632 continue;
1633 }
1634
1635 // NB: this is done also in addRing()
1636 // Ring closure does not change the size of the molecule, so we
1637 // give it an extra chance to occur irrespectively on molecular size
1638 // limit, while still subject of crowdedness probability.
1639 boolean allowOnlyRingClosure = false;
1640 if (!force)
1641 {
1642 // Decide whether we want to extend the graph at this AP?
1643 // Note that depending on the criterion (level/molSize) one
1644 // of these two first factors is 1.0.
1645 double molSizeProb = EAUtils.getMolSizeProbability(molGraph,
1646 settings);
1647 double byLevelProb = EAUtils.getGrowthByLevelProbability(lvl,
1648 settings);
1649 double crowdingProb = EAUtils.getCrowdingProbability(ap,
1650 settings);
1651 double extendGraphProb = molSizeProb * byLevelProb * crowdingProb;
1652 boolean fgrow = settings.getRandomizer().nextBoolean(
1653 extendGraphProb);
1654 if (!fgrow)
1655 {
1656 if (rcParams.allowRingClosures()
1657 && settings.getRandomizer().nextBoolean(byLevelProb
1658 * crowdingProb))
1659 {
1660 allowOnlyRingClosure = true;
1661 } else {
1662 continue;
1663 }
1664 }
1665 }
1666
1667 // Apply closability bias in selection of next fragment
1668 if (!allowOnlyRingClosure
1669 && rcParams.allowRingClosures()
1671 {
1672 boolean successful = attachFragmentInClosableChain(curVrtx,
1673 apId, molGraph, addedVertices, settings);
1674 if (successful)
1675 {
1676 continue;
1677 }
1678 }
1679
1680 // find a compatible combination of fragment and AP
1681 IdFragmentAndAP chosenFrgAndAp = null;
1682 if (allowOnlyRingClosure)
1683 {
1684 // NB: this works only for RCVs that are in the BBSpace, does
1685 // not generate a default RCV on-the-fly. So if no RCV is found
1686 // we'll get a pointer to nothing, which is what we check in the
1687 // next IF-block.
1688 chosenFrgAndAp = getRCVForSrcAp(curVrtx, apId,
1689 fsParams.getFragmentSpace());
1690 } else {
1691 chosenFrgAndAp = getFrgApForSrcAp(curVrtx,
1692 apId, chosenVrtxIdx, chosenApId, fsParams.getFragmentSpace());
1693 }
1694 int fid = chosenFrgAndAp.getVertexMolId();
1695 if (fid == -1)
1696 {
1697 continue;
1698 }
1699
1700 // Get the vertex that we'll add to the graph
1701 Vertex incomingVertex = Vertex.newVertexFromLibrary(-1,
1702 chosenFrgAndAp.getVertexMolId(),
1704 fsParams.getFragmentSpace());
1705
1706 // Stop if graph is already too big
1707 if ((curVrtx.getGraphOwner().getHeavyAtomsCount() +
1708 incomingVertex.getHeavyAtomsCount()) > maxHeavyAtoms)
1709 {
1710 continue;
1711 }
1712
1713 // Decide on symmetric substitution within this vertex...
1714 boolean cpOnSymAPs = applySymmetry(
1716 ap.getAPClass()),
1717 settings.getSymmetryProbability(),
1718 fsParams.getRandomizer());
1719 SymmetricAPs symAPs = new SymmetricAPs();
1720 if (curVrtx.getSymmetricAPs(ap).size()!=0
1721 && (cpOnSymAPs || symmetryOnAps)
1722 && !allowOnlyRingClosure)
1723 {
1724 symAPs.addAll(curVrtx.getSymmetricAPs(ap));
1725
1726 // Are symmetric APs rooted on same atom?
1727 boolean allOnSameSrc = true;
1728 for (AttachmentPoint symAP : symAPs)
1729 {
1730 if (!symAP.hasSameSrcAtom(ap))
1731 {
1732 allOnSameSrc = false;
1733 break;
1734 }
1735 }
1736
1737 if (allOnSameSrc)
1738 {
1739 // If the APs are rooted on the same src atom, we want to
1740 // apply the crowdedness probability to avoid over crowded
1741 // atoms
1742
1743 int crowdedness = EAUtils.getCrowdedness(ap);
1744
1745 SymmetricAPs toKeep = new SymmetricAPs();
1746
1747 // Start by keeping "ap"
1748 toKeep.add(ap);
1749 crowdedness = crowdedness + 1;
1750
1751 // Pick the accepted value once (used to decide how much
1752 // crowdedness we accept)
1753 double shot = settings.getRandomizer().nextDouble();
1754
1755 // Keep as many as allowed by the crowdedness decision
1756 for (AttachmentPoint symAP : symAPs)
1757 {
1758 if (symAP == ap)
1759 continue;
1760
1761 double crowdProb = EAUtils.getCrowdingProbability(
1762 crowdedness, settings);
1763
1764 if (shot > crowdProb)
1765 break;
1766
1767 toKeep.add(symAP);
1768 crowdedness = crowdedness + 1;
1769 }
1770
1771 // Adjust the list of symmetric APs to work with
1772 symAPs = toKeep;
1773 }
1774 } else {
1775 symAPs = new SymmetricAPs();
1776 symAPs.add(ap);
1777 }
1778
1779 // ...and inherit symmetry from previous levels
1780 boolean cpOnSymVrts = molGraph.hasSymmetryInvolvingVertex(curVrtx);
1781 SymmetricVertexes symVerts = new SymmetricVertexes();
1782 if (cpOnSymVrts)
1783 {
1784 symVerts = molGraph.getSymSetForVertex(curVrtx);
1785 }
1786 else
1787 {
1788 symVerts.add(curVrtx);
1789 }
1790
1791 // Consider size after application of symmetry
1792 if ((curVrtx.getGraphOwner().getHeavyAtomsCount() +
1793 incomingVertex.getHeavyAtomsCount() * symVerts.size()
1794 * symAPs.size()) > maxHeavyAtoms)
1795 {
1796 continue;
1797 }
1798
1799 // Collects all sym APs: within the vertex and outside it
1800 List<AttachmentPoint> allAPsFromSymVerts = new ArrayList<>();
1801 for (Vertex symVrt : symVerts)
1802 {
1803 for (AttachmentPoint apOnVrt : symAPs)
1804 {
1805 AttachmentPoint apOnSymVrt = symVrt.getAP(
1806 apOnVrt.getIndexInOwner());
1807 // This check is most often not needed, but it prevents that
1808 // misleading symmetry relations are used to break APClass
1809 // compatibility constraints
1810 if (apOnVrt.sameAs(apOnSymVrt)
1811 // Also ignore previously found APs
1812 && !symAPs.contains(apOnSymVrt))
1813 {
1814 allAPsFromSymVerts.add(apOnSymVrt);
1815 }
1816 }
1817 }
1818 symAPs.addAll(allAPsFromSymVerts);
1819
1821
1822 // loop on all symmetric vertices, but can be only one.
1823 SymmetricVertexes newSymSetOfVertices = new SymmetricVertexes();
1824 for (AttachmentPoint symAP : symAPs)
1825 {
1826 if (!symAP.isAvailable())
1827 {
1828 continue;
1829 }
1830
1831 // Finally add the fragment on a symmetric AP
1832 long newVrtId = GraphUtils.getUniqueVertexIndex();
1833 Vertex fragVertex = Vertex.newVertexFromLibrary(newVrtId,
1834 chosenFrgAndAp.getVertexMolId(),
1836 fsParams.getFragmentSpace());
1837 AttachmentPoint trgAP = fragVertex.getAP(
1838 chosenFrgAndAp.getApId());
1839
1840 molGraph.appendVertexOnAP(symAP, trgAP);
1841
1842 addedVertices.add(newVrtId);
1843 newSymSetOfVertices.add(fragVertex);
1844 }
1845
1846 // If any, store symmetry of new vertices in the graph
1847 if (newSymSetOfVertices.size() > 1)
1848 {
1849 molGraph.addSymmetricSetOfVertices(newSymSetOfVertices);
1850 }
1851 } // end loop over APs
1852
1853 if (extend)
1854 {
1855 // attempt to further extend each of the newly added vertices
1856 for (int i=0; i<addedVertices.size(); i++)
1857 {
1858 long vid = addedVertices.get(i);
1859 Vertex v = molGraph.getVertexWithId(vid);
1860 extendGraph(v, extend, symmetryOnAps, settings);
1861 }
1862 }
1863
1864 if (addedVertices.size() > 0)
1865 status = true;
1866
1867 return status;
1868 }
1869
1870//------------------------------------------------------------------------------
1871
1883 protected static IdFragmentAndAP getFrgApForSrcAp(Vertex curVertex,
1884 int dapidx, FragmentSpace fragSpace) throws DENOPTIMException
1885 {
1886 return getFrgApForSrcAp(curVertex, dapidx, -1, -1, fragSpace);
1887 }
1888
1889//------------------------------------------------------------------------------
1890
1908 protected static IdFragmentAndAP getFrgApForSrcAp(Vertex curVertex,
1909 int dapidx, int chosenVrtxIdx, int chosenApId,
1910 FragmentSpace fragSpace) throws DENOPTIMException
1911 {
1912 List<AttachmentPoint> lstDaps = curVertex.getAttachmentPoints();
1913 AttachmentPoint curDap = lstDaps.get(dapidx);
1914
1915 // Initialize with an empty pointer
1916 IdFragmentAndAP res = new IdFragmentAndAP(-1, -1, BBType.FRAGMENT, -1,
1917 -1, -1);
1918 if (!fragSpace.useAPclassBasedApproach())
1919 {
1920 int fid = fragSpace.getRandomizer().nextInt(
1921 fragSpace.getFragmentLibrary().size());
1922 res = new IdFragmentAndAP(-1,fid,BBType.FRAGMENT,-1,-1,-1);
1923 }
1924 else
1925 {
1926 List<IdFragmentAndAP> candidates =
1927 fragSpace.getFragAPsCompatibleWithClass(
1928 curDap.getAPClass());
1929 if (candidates.size() > 0)
1930 {
1931 if (chosenVrtxIdx>-1 && chosenApId>-1)
1932 {
1933 // We have asked to force the selection
1934 res = new IdFragmentAndAP(-1,chosenVrtxIdx,BBType.FRAGMENT,
1935 chosenApId,-1,-1);
1936 } else {
1937 res = fragSpace.getRandomizer().randomlyChooseOne(candidates);
1938 }
1939 }
1940 }
1941 return res;
1942 }
1943
1944//------------------------------------------------------------------------------
1945
1957 protected static IdFragmentAndAP getRCVForSrcAp(Vertex curVertex,
1958 int dapidx, FragmentSpace fragSpace) throws DENOPTIMException
1959 {
1960 AttachmentPoint ap = curVertex.getAP(dapidx);
1961
1962 Randomizer rng = fragSpace.getRandomizer();
1963 List<Vertex> rcvs = fragSpace.getRCVs();
1964 Vertex chosen = null;
1965 if (!fragSpace.useAPclassBasedApproach())
1966 {
1967 chosen = rng.randomlyChooseOne(rcvs);
1968 } else {
1969 List<Vertex> candidates = fragSpace.getRCVsForAPClass(
1970 ap.getAPClass());
1971 if (candidates.size() > 0)
1972 {
1973 chosen = rng.randomlyChooseOne(candidates);
1974 }
1975 }
1976
1977 IdFragmentAndAP pointer = new IdFragmentAndAP();
1978 if (chosen!=null)
1979 pointer = new IdFragmentAndAP(-1, chosen.getBuildingBlockId(),
1980 chosen.getBuildingBlockType(), 0, -1, -1);
1981 return pointer;
1982 }
1983
1984//------------------------------------------------------------------------------
1985
1986 protected static boolean attachFragmentInClosableChain(
1987 Vertex curVertex, int dapidx, DGraph molGraph,
1988 ArrayList<Long> addedVertices, GAParameters settings)
1989 throws DENOPTIMException
1990 {
1991 boolean res = false;
1993 if (settings.containsParameters(ParametersType.FS_PARAMS))
1994 {
1995 fsParams = (FragmentSpaceParameters)settings.getParameters(
1997 }
1998
1999 // Get candidate fragments
2000 ArrayList<FragForClosabChains> lscFfCc = getFragmentForClosableChain(
2001 curVertex, dapidx, molGraph);
2002
2003 // Here we can get:
2004 // 1) a selection of fragments that allow to close rings
2005 // 2) an empty list because no fragments allow to close rings
2006 // 3) "-1" as molID that means there are closable chains that
2007 // terminate at the current level, so we let the standard
2008 // routine proceeds selecting an extension of the chain
2009 // or cap this end.
2010
2011 // Choose a candidate and attach it to the graph
2012 int numCands = lscFfCc.size();
2013 if (numCands > 0)
2014 {
2015 int chosenId = settings.getRandomizer().nextInt(numCands);
2016 FragForClosabChains chosenFfCc = lscFfCc.get(chosenId);
2017 ArrayList<Integer> newFragIds = chosenFfCc.getFragIDs();
2018 int molIdNewFrag = newFragIds.get(0);
2019 BBType typeNewFrag = BBType.parseInt(newFragIds.get(1));
2020 int dapNewFrag = newFragIds.get(2);
2021 if (molIdNewFrag != -1)
2022 {
2023 long newvid = GraphUtils.getUniqueVertexIndex();
2025 newvid, molIdNewFrag, typeNewFrag,
2026 fsParams.getFragmentSpace());
2027
2028 molGraph.appendVertexOnAP(curVertex.getAP(dapidx),
2029 newVrtx.getAP(dapNewFrag));
2030
2031 if (newvid != -1)
2032 {
2033 addedVertices.add(newvid);
2034 // update list of candidate closable chains
2035 molGraph.getClosableChains().removeAll(
2036 chosenFfCc.getIncompatibleCC());
2037 APClass apc = curVertex.getAttachmentPoints().get(
2038 dapidx).getAPClass();
2039 if (applySymmetry(
2041 settings.getSymmetryProbability(),
2042 fsParams.getRandomizer()))
2043 {
2044//TODO: implement symmetric substitution with closability bias
2045 }
2046 res = true;
2047 }
2048 else
2049 {
2050 String msg = "BUG: Incorrect vertex num. Contact author.";
2051 settings.getLogger().log(Level.SEVERE, msg);
2052 throw new DENOPTIMException(msg);
2053 }
2054 }
2055 }
2056 return res;
2057 }
2058
2059//------------------------------------------------------------------------------
2060
2065 private static class FragForClosabChains
2066 {
2067 private ArrayList<ClosableChain> compatChains;
2068 private ArrayList<ClosableChain> incompatChains;
2069 private ArrayList<Integer> fragIds;
2070
2071 //----------------------------------------------------------------------
2072
2073 public FragForClosabChains(ArrayList<ClosableChain> compatChains,
2074 ArrayList<ClosableChain> incompatChains,
2075 ArrayList<Integer> fragIds)
2076 {
2077 this.compatChains = compatChains;
2078 this.incompatChains = incompatChains;
2079 this.fragIds = fragIds;
2080 }
2081
2082 //----------------------------------------------------------------------
2083
2085 {
2086 compatChains.add(icc);
2087 }
2088
2089 //----------------------------------------------------------------------
2090
2091 public ArrayList<ClosableChain> getCompatibleCC()
2092 {
2093 return compatChains;
2094 }
2095
2096 //----------------------------------------------------------------------
2097
2098 public ArrayList<ClosableChain> getIncompatibleCC()
2099 {
2100 return incompatChains;
2101 }
2102
2103 //----------------------------------------------------------------------
2104
2105 public ArrayList<Integer> getFragIDs()
2106 {
2107 return fragIds;
2108 }
2109
2110 //----------------------------------------------------------------------
2111 }
2112
2113//------------------------------------------------------------------------------
2114
2120 protected static ArrayList<FragForClosabChains> getFragmentForClosableChain(
2121 Vertex curVertex,
2122 int dapidx,
2123 DGraph molGraph)
2124 throws DENOPTIMException
2125 {
2126 // Select candidate fragments respecting the closability conditions
2127 ArrayList<FragForClosabChains> lstChosenFfCc =
2128 new ArrayList<FragForClosabChains>();
2129
2130 if (molGraph.getClosableChains().size() == 0)
2131 {
2132 return lstChosenFfCc;
2133 }
2134
2135 if (curVertex.getBuildingBlockType() == BBType.SCAFFOLD)
2136 {
2137 for (ClosableChain cc : molGraph.getClosableChains())
2138 {
2139 int posInCc = cc.involvesVertex(curVertex);
2140 ChainLink cLink = cc.getLink(posInCc);
2141 int nfid = -1;
2142 BBType nfty = BBType.UNDEFINED;
2143 int nfap = -1;
2144
2145 if (cLink.getApIdToLeft() != dapidx &&
2146 cLink.getApIdToRight() != dapidx)
2147 {
2148 // Chain does not involve AP dapidx
2149 continue;
2150 }
2151
2152 if (cLink.getApIdToRight() == dapidx)
2153 {
2154 if (cc.getSize() > (posInCc+1))
2155 {
2156 // cLink is NOT the rightmost chain link
2157 ChainLink nextChainLink = cc.getLink(posInCc+1);
2158 nfid = nextChainLink.getIdx();
2159 nfty = nextChainLink.getFragType();
2160 nfap = nextChainLink.getApIdToLeft();
2161 }
2162 else
2163 {
2164 // cLink is the rightmost chain link
2165 // closability bias suggest NO fragment
2166 }
2167 }
2168 else if (cLink.getApIdToLeft() == dapidx)
2169 {
2170 if ((posInCc-1) >= 0)
2171 {
2172 // cLink is NOT the leftmost chain link
2173 ChainLink nextChainLink = cc.getLink(posInCc-1);
2174 nfid = nextChainLink.getIdx();
2175 nfty = nextChainLink.getFragType();
2176 nfap = nextChainLink.getApIdToRight();
2177 }
2178 else
2179 {
2180 // cLink is the leftmost chain link
2181 // closability bias suggest NO fragment
2182 }
2183 }
2184
2185 ArrayList<Integer> eligibleFrgId = new ArrayList<Integer>();
2186 eligibleFrgId.add(nfid);
2187 eligibleFrgId.add(nfty.toOldInt());
2188 eligibleFrgId.add(nfap);
2189 boolean found = false;
2190 for (FragForClosabChains ffcc : lstChosenFfCc)
2191 {
2192 int fidA = ffcc.getFragIDs().get(0);
2193 BBType ftyA = BBType.parseInt(ffcc.getFragIDs().get(1));
2194 int fapA = ffcc.getFragIDs().get(2);
2195 if (nfid==fidA && nfty==ftyA && nfap==fapA)
2196 {
2197 found = true;
2198 ffcc.getCompatibleCC().add(cc);
2199 }
2200 else
2201 {
2202 ffcc.getIncompatibleCC().add(cc);
2203 }
2204 }
2205 if (!found)
2206 {
2207 ArrayList<ClosableChain> compatChains =
2208 new ArrayList<ClosableChain>();
2209 ArrayList<ClosableChain> incompatChains =
2210 new ArrayList<ClosableChain>();
2211 for (FragForClosabChains otherFfCc : lstChosenFfCc)
2212 {
2213 incompatChains.addAll(otherFfCc.getCompatibleCC());
2214 }
2215 FragForClosabChains newChosenCc = new FragForClosabChains(
2216 compatChains,
2217 incompatChains,
2218 eligibleFrgId);
2219
2220 newChosenCc.addCompatibleCC(cc);
2221 lstChosenFfCc.add(newChosenCc);
2222 }
2223 }
2224 }
2225 else
2226 {
2227 Vertex parent = molGraph.getParent(curVertex);
2228 Edge edge = molGraph.getEdgeWithParent(
2229 curVertex.getVertexId());
2230 int prntId = parent.getBuildingBlockId();
2231 BBType prntTyp = parent.getBuildingBlockType();
2232 int prntAp = edge.getSrcAPID();
2233 int chidAp = edge.getTrgAPID();
2234 for (ClosableChain cc : molGraph.getClosableChains())
2235 {
2236 int posInCc = cc.involvesVertexAndAP(curVertex, dapidx, chidAp);
2237
2238 if (posInCc == -1)
2239 {
2240 // closable chain does not span this combination
2241 // of vertex and APs
2242 continue;
2243 }
2244
2245 ChainLink cLink = cc.getLink(posInCc);
2246 int nfid = -1;
2247 BBType nfty = BBType.UNDEFINED;
2248 int nfap = -1;
2249
2250 List<Integer> altertnativeDirections = new ArrayList<>();
2251 altertnativeDirections.add(-1);
2252 altertnativeDirections.add(+1);
2253 for (int altDir : altertnativeDirections)
2254 {
2255 ChainLink parentLink = cc.getLink(posInCc + altDir);
2256 int pLnkId = parentLink.getIdx();
2257 BBType pLnkTyp = parentLink.getFragType();
2258
2259 int pLnkAp = -1;
2260 int cApId = -1;
2261 if (altDir>0)
2262 {
2263 pLnkAp = parentLink.getApIdToRight();
2264 cApId = cLink.getApIdToLeft();
2265 } else {
2266 pLnkAp = parentLink.getApIdToLeft();
2267 cApId = cLink.getApIdToRight();
2268 }
2269 if (pLnkId==prntId && pLnkTyp==prntTyp && pLnkAp == prntAp &&
2270 cApId == chidAp)
2271 {
2272 if (cc.getSize() > (posInCc+altDir)
2273 && (posInCc+altDir) >= 0)
2274 {
2275 ChainLink nextChainLink = cc.getLink(posInCc + altDir);
2276 nfid = nextChainLink.getIdx();
2277 nfty = nextChainLink.getFragType();
2278 nfap = nextChainLink.getApIdToLeft();
2279 }
2280 else
2281 {
2282 // cLink is the rightmost chain link
2283 // closability bias suggests NO fragment
2284 }
2285 }
2286 else
2287 {
2288 // different parent link
2289 continue;
2290 }
2291 }
2292
2293 ArrayList<Integer> eligibleFrgId = new ArrayList<Integer>();
2294 eligibleFrgId.add(nfid);
2295 eligibleFrgId.add(nfty.toOldInt());
2296 eligibleFrgId.add(nfap);
2297 boolean found = false;
2298 for (FragForClosabChains ffcc : lstChosenFfCc)
2299 {
2300 int fidA = ffcc.getFragIDs().get(0);
2301 BBType ftyA = BBType.parseInt(ffcc.getFragIDs().get(1));
2302 int fapA = ffcc.getFragIDs().get(2);
2303 if (nfid==fidA && nfty==ftyA && nfap==fapA)
2304 {
2305 found = true;
2306 ffcc.getCompatibleCC().add(cc);
2307 }
2308 else
2309 {
2310 ffcc.getIncompatibleCC().add(cc);
2311 }
2312 }
2313 if (!found)
2314 {
2315 ArrayList<ClosableChain> compatChains =
2316 new ArrayList<ClosableChain>();
2317 ArrayList<ClosableChain> incompatChains =
2318 new ArrayList<ClosableChain>();
2319 for (FragForClosabChains otherFfCc : lstChosenFfCc)
2320 {
2321 incompatChains.addAll(otherFfCc.getCompatibleCC());
2322 }
2323 FragForClosabChains newChosenCc = new FragForClosabChains(
2324 compatChains,
2325 incompatChains,
2326 eligibleFrgId);
2327 newChosenCc.addCompatibleCC(cc);
2328 lstChosenFfCc.add(newChosenCc);
2329 }
2330 }
2331 }
2332 return lstChosenFfCc;
2333 }
2334
2335//------------------------------------------------------------------------------
2336
2347 public static boolean performCrossover(XoverSite site,
2348 FragmentSpace fragSpace) throws DENOPTIMException
2349 {
2350 return performCrossover(site, fragSpace,
2352 }
2353
2354//------------------------------------------------------------------------------
2355
2367 public static boolean performCrossover(XoverSite site,
2368 FragmentSpace fragSpace, int maxAPMappingCombinations)
2369 throws DENOPTIMException
2370 {
2371 DGraph gA = site.getA().get(0).getGraphOwner();
2372 DGraph gB = site.getB().get(0).getGraphOwner();
2373
2374 // All the APs that point away from the subgraph
2375 List<AttachmentPoint> allAPsOnA = gA.getSubgraphAPs(site.getA());
2376 List<AttachmentPoint> allAPsOnB = gB.getSubgraphAPs(site.getB());
2377
2378 // The APs that are required to have a mapping for proper crossover,
2379 // eg. because the change of subgraph needs to retain a super structure.
2380 List<AttachmentPoint> needyAPsOnA = site.getAPsNeedingMappingA();
2381 List<AttachmentPoint> needyAPsOnB = site.getAPsNeedingMappingB();
2382
2383 // APs that connects the subgraphs' root to the parent vertex
2384 AttachmentPoint apToParentA = null;
2385 AttachmentPoint apToParentB = null;
2386 for (AttachmentPoint ap : needyAPsOnA)
2387 {
2388 if (!ap.isSrcInUserThroughout())
2389 {
2390 apToParentA = ap;
2391 //WARNING: we assume there is one AND only one AP to parent!!!
2392 break;
2393 }
2394 }
2395 for (AttachmentPoint ap : needyAPsOnB)
2396 {
2397 if (!ap.isSrcInUserThroughout())
2398 {
2399 apToParentB = ap;
2400 //WARNING: we assume there is one AND only one AP to parent!!!
2401 break;
2402 }
2403 }
2404 if (apToParentA==null || apToParentB==null)
2405 {
2406 throw new DENOPTIMException("Could not identify any attachment "
2407 + "point connecting a subgraph to the rest of the graph. "
2408 + "This violates assumption that crossover does not "
2409 + "involve scaffold or vertexes without parent.");
2410 }
2411 // Check if the subgraphs can be used with reversed edge direction, or
2412 // bias the AP mapping to use the original source vertexes.
2413 APMapping fixedRootAPs = null;
2414 //TODO: REACTIVATE ONCE REVERSION of the subgrsph's spanning tree is in place.
2415 //if (!subG_M.isReversible() || !subG_F.isReversible())
2416 if (true)
2417 {
2418 // Constrain the AP mapping so that the AP originally used to
2419 // connect to the parent vertex, will also be used the same way.
2420 // Thus, forces retention of edge direction within the subgraph.
2421 fixedRootAPs = new APMapping();
2422 fixedRootAPs.put(apToParentA, apToParentB);
2423 }
2424
2425 // Find an AP mapping that satisfies both root-vertex constrain and
2426 // need to ensure the mapping of needy APs
2427 APMapFinder apmf = new APMapFinder(fragSpace,
2428 allAPsOnA, needyAPsOnA,
2429 allAPsOnB, needyAPsOnB, fixedRootAPs,
2430 false, // false means stop at the first compatible mapping.
2431 false, // false means we do not require complete mapping.
2432 false, // false means free AP are not considered compatible.
2433 maxAPMappingCombinations);
2434 if (!apmf.foundMapping())
2435 {
2436 // Since the xover site has been detected by searching for compatible
2437 // sites that do have a mapping there should always be at least one
2438 // mapping and this exception should never occur.
2439 throw new DENOPTIMException("Missing AP mapping for known XoverSite.");
2440 }
2441
2442 // To replace each subgraph in the original graphs, we need to
2443 // map the APs on the original A/B graph with those in the
2444 // corresponding incoming subgraph, which are clones of the original:
2445 DGraph subGraphA = gA.extractSubgraph(site.getA());
2446 DGraph subGraphB = gB.extractSubgraph(site.getB());
2447
2448 // Here we create the two AP mappings we need: one for A other for B.
2449 LinkedHashMap<AttachmentPoint,AttachmentPoint>
2450 apMapA = new LinkedHashMap<AttachmentPoint,AttachmentPoint>();
2451 LinkedHashMap<AttachmentPoint,AttachmentPoint>
2452 apMapB = new LinkedHashMap<AttachmentPoint,AttachmentPoint>();
2453 for (Map.Entry<AttachmentPoint, AttachmentPoint> e :
2454 apmf.getChosenAPMapping().entrySet())
2455 {
2456 AttachmentPoint apOnA = e.getKey();
2457 AttachmentPoint apOnB = e.getValue();
2458
2459 // NB: assumption that vertex IDs are healthy, AND that order of APs
2460 // is retained upon cloning of the subgraph!
2461 AttachmentPoint apOnSubGraphA = subGraphA.getVertexWithId(
2462 apOnA.getOwner().getVertexId()).getAP(
2463 apOnA.getIndexInOwner());
2464 AttachmentPoint apOnSubGraphB = subGraphB.getVertexWithId(
2465 apOnB.getOwner().getVertexId()).getAP(
2466 apOnB.getIndexInOwner());
2467 apMapA.put(apOnA, apOnSubGraphB);
2468 apMapB.put(apOnB, apOnSubGraphA);
2469 }
2470
2471 // Now we do the actual replacement of subgraphs
2472 if (!gA.replaceSubGraph(site.getA(), subGraphB, apMapA, fragSpace))
2473 return false;
2474 if (!gB.replaceSubGraph(site.getB(), subGraphA, apMapB, fragSpace))
2475 return false;
2476
2477 return true;
2478 }
2479
2480//------------------------------------------------------------------------------
2481
2494 protected static boolean applySymmetry(boolean apclassImposed,
2495 double symmetryProbability, Randomizer randomizer)
2496 {
2497 boolean r = false;
2498 if (apclassImposed)
2499 {
2500 r = true;
2501 }
2502 else
2503 {
2504 r = randomizer.nextBoolean(symmetryProbability);
2505 }
2506 return r;
2507 }
2508
2509//------------------------------------------------------------------------------
2510
2523 public static boolean performMutation(DGraph graph, Monitor mnt,
2524 GAParameters settings) throws DENOPTIMException
2525 {
2526 // Get vertices that can be mutated: they can be part of subgraphs
2527 // embedded in templates. Here, we consider only single-vertexes sites.
2528 // So sites for ADDRINGFUSION mutation are not added here.
2529 List<Vertex> mutable = graph.getMutableSites(
2530 settings.getExcludedMutationTypes());
2531 // Now, add also the sites that involve multiple vertexes, such sites for
2532 // ADDFUSEDRING mutation.
2533 for (List<RelatedAPPair> siteCombination : EAUtils.searchRingFusionSites(
2534 graph, settings))
2535 {
2536 for (RelatedAPPair site : siteCombination)
2537 {
2538 Vertex vA = site.apA.getOwner();
2539 Vertex vB = site.apB.getOwner();
2540 if (!mutable.contains(vA))
2541 mutable.add(vA);
2542 if (!mutable.contains(vB))
2543 mutable.add(vB);
2544 }
2545 }
2546
2547 if (mutable.size() == 0)
2548 {
2550 String msg = "Graph has no mutable site. Mutation aborted.";
2551 settings.getLogger().info(msg);
2552 return false;
2553 }
2554 boolean doneMutation = true;
2555 int numberOfMutations = EAUtils.chooseNumberOfSitesToMutate(
2556 settings.getMultiSiteMutationWeights(),
2557 settings.getRandomizer().nextDouble());
2558 for (int i=0; i<numberOfMutations; i++)
2559 {
2560 if (i>0)
2561 {
2562 mutable = graph.getMutableSites(
2563 settings.getExcludedMutationTypes());
2564 break;
2565 }
2566 Vertex v = settings.getRandomizer().randomlyChooseOne(mutable);
2567 doneMutation = performMutation(v, mnt, settings);
2568 if(!doneMutation)
2569 break;
2570 }
2571 return doneMutation;
2572 }
2573
2574//------------------------------------------------------------------------------
2575
2589 public static boolean performMutation(Vertex vertex, Monitor mnt,
2590 GAParameters settings) throws DENOPTIMException
2591 {
2592 List<MutationType> mTypes = vertex.getMutationTypes(
2593 settings.getExcludedMutationTypes());
2594 if (mTypes.size() == 0)
2595 {
2596 return false;
2597 }
2598 MutationType mType = settings.getRandomizer().randomlyChooseOne(mTypes);
2599 return performMutation(vertex, mType, mnt, settings);
2600 }
2601
2602//------------------------------------------------------------------------------
2603
2615 public static boolean performMutation(Vertex vertex,
2616 MutationType mType, Monitor mnt, GAParameters settings)
2617 throws DENOPTIMException
2618 {
2619 DGraph c = vertex.getGraphOwner().clone();
2620 int pos = vertex.getGraphOwner().indexOf(vertex);
2621 try
2622 {
2623 return performMutation(vertex, mType, false, -1 ,-1, mnt, settings);
2624 } catch (IllegalArgumentException|NullPointerException e)
2625 {
2626 String debugFile = "failedMutation_" + mType
2627 + "_" + vertex.getVertexId() + "(" + pos + ")_"
2628 + settings.timeStamp + ".sdf";
2629 DenoptimIO.writeGraphToSDF(new File(debugFile), c, false,
2630 settings.getLogger(), settings.getRandomizer());
2631 settings.getLogger().warning("Fatal exception while performing "
2632 + "mutation. See file '" + debugFile + "' to reproduce the "
2633 + "problem.");
2634 throw e;
2635 }
2636 }
2637
2638//------------------------------------------------------------------------------
2639
2665 public static boolean performMutation(Vertex vertex,
2666 MutationType mType, boolean force, int chosenVrtxIdx,
2667 int chosenApId, Monitor mnt, GAParameters settings)
2668 throws DENOPTIMException
2669 {
2671 if (settings.containsParameters(ParametersType.FS_PARAMS))
2672 {
2673 fsParams = (FragmentSpaceParameters)settings.getParameters(
2675 }
2676
2677 DGraph graph = vertex.getGraphOwner();
2678 if (graph == null)
2679 {
2681 settings.getLogger().info("Vertex has no owner - "
2682 + "Mutation aborted");
2683 return false;
2684 }
2685 if (!vertex.getMutationTypes(settings.getExcludedMutationTypes())
2686 .contains(mType))
2687 {
2689 settings.getLogger().info("Vertex does not allow mutation type "
2690 + "'" + mType + "' - Mutation aborted");
2691 return false;
2692 }
2693
2694 int graphId = graph.getGraphId();
2695 int positionOfVertex = graph.indexOf(vertex);
2696 //NB: since we have renumbered the vertexes, we use the old vertex ID
2697 // when reporting what vertex is being mutated. Also, note that the
2698 // identity of the candidate is already in the graph's local msg.
2699 String mutantOrigin = graph.getLocalMsg() + "|"
2700 + mType + "|"
2701 + vertex.getProperty(DENOPTIMConstants.STOREDVID)
2702 + " (" + positionOfVertex + ")";
2703 graph.setLocalMsg(mutantOrigin);
2704
2705 boolean done = false;
2706 switch (mType)
2707 {
2708 case CHANGEBRANCH:
2709 done = rebuildBranch(vertex, force, chosenVrtxIdx, chosenApId,
2710 settings);
2711 if (!done)
2712 mnt.increase(
2714 break;
2715
2716 case CHANGELINK:
2717 done = substituteLink(vertex, chosenVrtxIdx, mnt,
2718 fsParams.getFragmentSpace());
2719 if (!done)
2720 mnt.increase(
2722 break;
2723
2724 case DELETELINK:
2725 done = deleteLink(vertex, chosenApId, mnt,
2726 fsParams.getFragmentSpace());
2727 if (!done)
2728 mnt.increase(
2730 break;
2731
2732 case DELETECHAIN:
2733 done = deleteChain(vertex, mnt, fsParams.getFragmentSpace());
2734 if (!done)
2735 mnt.increase(
2737 break;
2738
2739 case ADDLINK:
2740 if (chosenApId < 0)
2741 {
2742 List<Integer> candidates = new ArrayList<Integer>();
2743 for (Vertex c : vertex.getChilddren())
2744 {
2745 candidates.add(c.getEdgeToParent().getSrcAP()
2746 .getIndexInOwner());
2747 }
2748 if (candidates.size() == 0)
2749 {
2750 mnt.increase(
2752 break;
2753 }
2754 chosenApId = settings.getRandomizer().randomlyChooseOne(
2755 candidates);
2756 }
2757 done = extendLink(vertex, chosenApId, chosenVrtxIdx, mnt,
2758 fsParams.getFragmentSpace());
2759 if (!done)
2760 mnt.increase(
2762 break;
2763
2764 case ADDRING:
2765 done = addRing(vertex, mnt, false, fsParams.getFragmentSpace(),
2766 settings);
2767 if (!done)
2769 break;
2770
2771 case ADDFUSEDRING:
2772 done = addFusedRing(vertex, mnt, false, fsParams.getFragmentSpace(),
2773 settings);
2774 if (!done)
2776 break;
2777
2778 case EXTEND:
2779 vertex.getGraphOwner().removeCappingGroupsOn(vertex);
2780 done = extendGraph(vertex, false, false, force, chosenVrtxIdx,
2781 chosenApId, settings);
2782 if (!done)
2784 break;
2785
2786 case DELETE:
2787 done = deleteFragment(vertex);
2788 if (!done)
2790 break;
2791 }
2792
2793 String msg = "Mutation '" + mType.toString() + "' on vertex "
2794 + vertex.toString() + " (position " + positionOfVertex
2795 + " in graph " + graphId+"): ";
2796 if (done)
2797 {
2798 msg = msg + "done";
2799
2800 // Triggers reconstruction of the molecular representation of
2801 // templates upon changes of the embedded graph
2802 if (graph.getTemplateJacket() != null)
2803 {
2805 }
2806 } else {
2807 msg = msg + "unsuccessful";
2808 }
2809 settings.getLogger().info(msg);
2810
2811 return done;
2812 }
2813
2814//------------------------------------------------------------------------------
2815
2816
2817
2818}
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.
static final int DEFAULT_MAX_COMBS
Default maximum number of combinations when none is specified.
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:2345
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:3185
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:2368
static List< List< RelatedAPPair > > searchRingFusionSites(DGraph graph, GAParameters gaParams)
Definition: EAUtils.java:2585
static int getCrowdedness(AttachmentPoint ap)
Calculate the current crowdedness of the given attachment point.
Definition: EAUtils.java:2413
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:3141
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:2268
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 boolean applySymmetry(boolean apclassImposed, double symmetryProbability, Randomizer randomizer)
Decides whether to apply constitutional symmetry or not.
static void processPermutationOfEndPoints(Vertex[] pair, List< Vertex[]> chosenSequenceOfEndpoints, List< XoverSite > collector, FragmentSpace fragSpace, int maxAPMappingCombinations)
Given a pair of seed vertexes that define where a pair of subgraphs stars in the corresponding origin...
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 List< XoverSite > locateCompatibleXOverPoints(DGraph graphA, DGraph graphB, FragmentSpace fragSpace, int maxSizeXoverSubGraph, int maxCompatibleVrtxPairs, int maxEndPointsCombinations, int maxEndPointsPermutations, int maxAPMappingCombinations)
Identify crossover sites, i.e., subgraphs that can be swapped between two graphs (i....
static boolean isCrossoverPossible(Edge eA, Edge eB, FragmentSpace fragSpace)
Evaluate AP class-compatibility of a pair of edges with respect to crossover.
static boolean attachFragmentInClosableChain(Vertex curVertex, int dapidx, DGraph molGraph, ArrayList< Long > addedVertices, GAParameters settings)
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 performCrossover(XoverSite site, FragmentSpace fragSpace, int maxAPMappingCombinations)
Performs crossover as defined by the given XoverSite.
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 void processCombinationOfEndPoints(Vertex[] pair, List< Vertex[]> cominationOfEnds, List< XoverSite > collector, FragmentSpace fragSpace, int maxEndPointsPermutations, int maxAPMappingCombinations)
Given a pair of seed vertexes that define where a pair of subgraphs stars in the corresponding origin...
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 void checkAndAddXoverSites(FragmentSpace fragSpace, List< Vertex > subGraphA, List< Vertex > subGraphB, CrossoverType xoverType, List< XoverSite > collector, int maxAPMappingCombinations)
Here we check that the given subgraphs have a mapping that allows to swap them, and full fill any oth...
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.
boolean isAvailableThroughout()
Check availability of this attachment point throughout the graph level, i.e., check also across the i...
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:7817
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:7852
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:7636
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:36
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.
public< T > void shuffle(List< T > list)
Fisher-Yates shuffle of the given list.
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...