$darkmode
DENOPTIM
GraphOperations.java
Go to the documentation of this file.
1/*
2 * DENOPTIM
3 * Copyright (C) 2019 Vishwesh Venkatraman <vishwesh.venkatraman@ntnu.no> and
4 * Marco Foscato <marco.foscato@uib.no>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published
8 * by the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20package denoptim.ga;
21
22import java.io.File;
23import java.util.ArrayList;
24import java.util.LinkedHashMap;
25import java.util.List;
26import java.util.Map;
27import java.util.Map.Entry;
28import java.util.TreeMap;
29import java.util.logging.Level;
30import java.util.stream.Collectors;
31
32import org.apache.http.TruncatedChunkException;
33import org.openscience.cdk.interfaces.IAtomContainer;
34import org.paukov.combinatorics3.Generator;
35
36import denoptim.constants.DENOPTIMConstants;
37import denoptim.exception.DENOPTIMException;
38import denoptim.fragspace.APMapFinder;
39import denoptim.fragspace.FragmentSpace;
40import denoptim.fragspace.FragmentSpaceParameters;
41import denoptim.fragspace.GraphLinkFinder;
42import denoptim.fragspace.IdFragmentAndAP;
43import denoptim.graph.APClass;
44import denoptim.graph.APMapping;
45import denoptim.graph.AttachmentPoint;
46import denoptim.graph.DGraph;
47import denoptim.graph.Edge;
48import denoptim.graph.Ring;
49import denoptim.graph.SymmetricAPs;
50import denoptim.graph.SymmetricVertexes;
51import denoptim.graph.Template;
52import denoptim.graph.Template.ContractLevel;
53import denoptim.graph.Vertex;
54import denoptim.graph.Vertex.BBType;
55import denoptim.graph.rings.ChainLink;
56import denoptim.graph.rings.ClosableChain;
57import denoptim.graph.rings.PathSubGraph;
58import denoptim.graph.rings.RandomCombOfRingsIterator;
59import denoptim.graph.rings.RingClosingAttractor;
60import denoptim.graph.rings.RingClosureParameters;
61import denoptim.io.DenoptimIO;
62import denoptim.logging.CounterID;
63import denoptim.logging.Monitor;
64import denoptim.molecularmodeling.ThreeDimTreeBuilder;
65import denoptim.programs.RunTimeParameters.ParametersType;
66import denoptim.programs.denovo.GAParameters;
67import denoptim.utils.CrossoverType;
68import denoptim.utils.GraphUtils;
69import denoptim.utils.MutationType;
70import denoptim.utils.Randomizer;
71
76public class GraphOperations
77{
78
79//------------------------------------------------------------------------------
80
94 public static List<XoverSite> locateCompatibleXOverPoints(
95 DGraph graphA, DGraph graphB, FragmentSpace fragSpace,
96 int maxSizeXoverSubGraph)
98 {
99 // First, we identify all the edges that allow crossover, and collect
100 // their target vertexes (i.e., all the potential seed vertexes of
101 // subgraphs that crossover could swap.
102 List<Vertex[]> compatibleVrtxPairs = new ArrayList<Vertex[]>();
103 for (Edge eA : graphA.getEdgeList())
104 {
105 Vertex vA = eA.getTrgAP().getOwner();
106 // We don't do genetic operations on capping vertexes
107 if (vA.getBuildingBlockType() == BBType.CAP)
108 continue;
109
110 for (Edge eB : graphB.getEdgeList())
111 {
112 Vertex vB = eB.getTrgAP().getOwner();
113 // We don't do genetic operations on capping vertexes
114 if (vB.getBuildingBlockType() == BBType.CAP)
115 continue;
116
117 //Check condition for considering this combination
118 if (isCrossoverPossible(eA, eB, fragSpace))
119 {
120 Vertex[] pair = new Vertex[]{vA,vB};
121 compatibleVrtxPairs.add(pair);
122 }
123 }
124 }
125
126 // The crossover sites are the combination of the above compatible
127 // vertexes that define subgraphs respecting the requirements for
128 // being swapped between the two graphs.
129 ArrayList<XoverSite> sites = new ArrayList<XoverSite>();
130 for (Vertex[] pair : compatibleVrtxPairs)
131 {
132 Vertex vA = pair[0];
133 Vertex vB = pair[1];
134 DGraph gA = vA.getGraphOwner();
135 DGraph gB = vB.getGraphOwner();
136
137 // Here we also identify the branch identity of each descendant
138 List<Vertex> descendantsA = new ArrayList<Vertex>();
139 gA.getChildrenTree(vA, descendantsA, true);
140 List<Vertex> descendantsB = new ArrayList<Vertex>();
141 gB.getChildrenTree(vB, descendantsB, true);
142
143 // Branches that are isomorphic are not considered for crossover
144 DGraph test1 = gA.clone();
145 DGraph test2 = gB.clone();
146 try
147 {
148 DGraph subGraph1 = test1.extractSubgraph(gA.indexOf(vA));
149 DGraph subGraph2 = test2.extractSubgraph(gB.indexOf(vB));
150 if (maxSizeXoverSubGraph >= Math.max(subGraph1.getVertexCount(),
151 subGraph2.getVertexCount()))
152 {
153 if (!subGraph1.isIsomorphicTo(subGraph2))
154 {
155 List<Vertex> branchOnVA = new ArrayList<Vertex>();
156 branchOnVA.add(vA);
157 branchOnVA.addAll(descendantsA);
158 List<Vertex> branchOnVB = new ArrayList<Vertex>();
159 branchOnVB.add(vB);
160 branchOnVB.addAll(descendantsB);
161
162 checkAndAddXoverSites(fragSpace, branchOnVA, branchOnVB,
163 CrossoverType.BRANCH, sites);
164 }
165 }
166 } catch (DENOPTIMException e)
167 {
168 //We should never end up here.
169 e.printStackTrace();
170 }
171
172 // To limit the number of combination, we first get rid of end-point
173 // candidates that cannot be used
174 List<Vertex[]> usablePairs = new ArrayList<Vertex[]>();
175
176 // To identify subgraphs smaller than the full branch we need to find
177 // where such subgraphs end, i.e., the vertexes at the end of
178 // such subgraphs (included in them), a.k.a. the subgraph ends.
179 // Since these subgraph ends will need to allow connection with the
180 // rest of the original graph, they are related to the
181 // already-identified crossover-compatible
182 // sites, i.e., they are the parents of the vertexes collected in
183 // compatibleVrtxPairs. Yet, we can combine them
184 // * in any number from 1 to all of them,
185 // * in any combination of the chosen number of them.
186 // Also, note that the ends need not to cover all the branches. So,
187 // some combinations will have to cut some branches short while
188 // taking some other branches completely till their last leaf.
189 for (Vertex[] otherPair : compatibleVrtxPairs)
190 {
191 // NB: the xover compatible sites are the child vertexes of the
192 // subgraph ends. So we need to get the parent
193 Vertex nextToEndOnA = otherPair[0];
194 Vertex nextToEndOnB = otherPair[1];
195 Vertex endOnA = nextToEndOnA.getParent();
196 Vertex endOnB = nextToEndOnB.getParent();
197 if (endOnA==null || endOnB==null)
198 continue;
199
200 // Exclude vertexes that are not downstream to the seed of the subgraph
201 if (!descendantsA.contains(endOnA) && endOnA!=vA
202 || !descendantsB.contains(endOnB) && endOnB!=vB)
203 continue;
204
205 // If any partner is a fixed-structure templates...
206 if ((gA.getTemplateJacket()!=null
209 || (gB.getTemplateJacket()!=null
212 {
213 //...the two paths must have same length. This would be
214 // checked anyway later when checking for isostructural
215 // subgraphs, but here it helps reducing the size of the
216 // combinatorial problem.
217 PathSubGraph pathA = new PathSubGraph(vA, endOnA, gA);
218 PathSubGraph pathB = new PathSubGraph(vB, endOnB, gB);
219 if (pathA.getPathLength()!=pathB.getPathLength())
220 continue;
221 }
222 Vertex[] pairOfEnds = new Vertex[]{endOnA,endOnB};
223 if (!usablePairs.contains(pairOfEnds))
224 usablePairs.add(pairOfEnds);
225 }
226
227 // We classify the pairs by branch ownership
228 TreeMap<String,List<Vertex[]>> sitesByBranchIdA =
229 new TreeMap<String,List<Vertex[]>>();
230 TreeMap<String,List<Vertex[]>> sitesByBranchIdB =
231 new TreeMap<String,List<Vertex[]>>();
232 for (Vertex[] pp : usablePairs)
233 {
234 String branchIdA = gA.getBranchIdOfVertexAsStr(pp[0]);
235 String branchIdB = gB.getBranchIdOfVertexAsStr(pp[1]);
236 if (sitesByBranchIdA.containsKey(branchIdA))
237 {
238 sitesByBranchIdA.get(branchIdA).add(pp);
239 } else {
240 ArrayList<Vertex[]> lst = new ArrayList<Vertex[]>();
241 lst.add(pp);
242 sitesByBranchIdA.put(branchIdA, lst);
243 }
244 if (sitesByBranchIdB.containsKey(branchIdB))
245 {
246 sitesByBranchIdB.get(branchIdB).add(pp);
247 } else {
248 ArrayList<Vertex[]> lst = new ArrayList<Vertex[]>();
249 lst.add(pp);
250 sitesByBranchIdB.put(branchIdB, lst);
251 }
252 }
253
254 // The side with the smallest set of branches determines the max
255 // number of pairs that can define a subgraph.
256 TreeMap<String,List<Vertex[]>> fewestBranchesSide = null;
257 if (sitesByBranchIdA.size() <= sitesByBranchIdB.size())
258 fewestBranchesSide = sitesByBranchIdA;
259 else
260 fewestBranchesSide = sitesByBranchIdB;
261
262 // Add the empty, i.e., the branch with empty is not cut short.
263 for (List<Vertex[]> val : fewestBranchesSide.values())
264 val.add(new Vertex[]{null,null});
265
266 // Generate the combinations: Cartesian product of multiple lists.
267 // NB: this combinatorial generator retains the
268 // sequence of generated subsets (important for reproducibility)
269 List<List<Vertex[]>> preCombsOfEnds = Generator.cartesianProduct(
270 fewestBranchesSide.values())
271 .stream()
272 .limit(100000) //Prevent explosion!!!
273 .collect(Collectors.<List<Vertex[]>>toList());
274
275 // Remove the 'null,null' place holders that indicate the use of no
276 // end-point on a specific branch.
277 List<List<Vertex[]>> combsOfEnds = new ArrayList<List<Vertex[]>>();
278 for (List<Vertex[]> comb : preCombsOfEnds)
279 {
280 List<Vertex[]> nullPurgedComb = new ArrayList<Vertex[]>();
281 for (Vertex[] inPair : comb)
282 {
283 if (inPair[0]!=null && inPair[1]!=null)
284 nullPurgedComb.add(inPair);
285 }
286 // the case where all entries are null corresponds to use no
287 // end point on any branch, which is already considered above.
288 if (nullPurgedComb.size()>0)
289 combsOfEnds.add(nullPurgedComb);
290 }
291
292 // This would be a strategy to parallelize. However, this type of
293 // parallelization is not compatible with ensuring reproducibility.
294 // Perhaps, we could guarantee reproducibility by acting on the
295 // collector of sites as to ensure the list is sorted
296 // at the end of the generation of all possibilities.
297 /*
298 combsOfEnds
299 .parallelStream()
300 .limit(50) // Prevent explosion!
301 .forEach(c -> processCombinationOfEndPoints(pair, c, sites,
302 fragSpace));
303 */
304
305 combsOfEnds.stream()
306 .limit(50) // Prevent explosion!
307 .forEach(c -> processCombinationOfEndPoints(pair, c, sites,
308 fragSpace));
309 }
310
311 // NB: we consider only templates that are at the same level of embedding
312 for (Vertex vA : graphA.getVertexList())
313 {
314 if (!(vA instanceof Template))
315 continue;
316 Template tA = (Template) vA;
317
319 continue;
320
321 for (Vertex vB : graphB.getVertexList())
322 {
323 if (!(vB instanceof Template))
324 continue;
325 Template tB = (Template) vB;
326
328 continue;
329
331 tA.getInnerGraph(), tB.getInnerGraph(), fragSpace,
332 maxSizeXoverSubGraph))
333 {
334 if (!sites.contains(xos))
335 sites.add(xos);
336 }
337 }
338 }
339 return sites;
340 }
341
342//------------------------------------------------------------------------------
343
356 private static void processCombinationOfEndPoints(Vertex[] pair,
357 List<Vertex[]> cominationOfEnds,
358 List<XoverSite> collector, FragmentSpace fragSpace)
359 {
360 // Empty set corresponds to using the entire branch and subgraph and
361 // has been already dealt with at this point
362 if (cominationOfEnds.size()==0)
363 return;
364
365 // This would be a strategy to parallelize. However, this type of
366 // parallelization is not compatible with ensuring reproducibility.
367 // Perhaps, we could guarantee reproducibility by acting on the
368 // collector as to ensure the list of collected results is sorted
369 // at the end of the generation of all possibilities
370 /*
371 List<List<Vertex[]>> permutsOfEnds = new ArrayList<List<Vertex[]>>();
372 Generator.subset(cominationOfEnds)
373 .simple()
374 .stream()
375 .limit(100) // Prevent explosion!
376 .forEach(c -> permutsOfEnds.add(c));
377 permutsOfEnds
378 .parallelStream()
379 .forEach(c -> processPermutationOfEndPoints(pair, c, collector,
380 fragSpace));
381 */
382
383 Generator.permutation(cominationOfEnds)
384 .simple()
385 .stream()
386 .limit(100) // Prevent explosion!
387 .forEach(c -> processPermutationOfEndPoints(pair, c, collector,
388 fragSpace));
389 }
390
391//------------------------------------------------------------------------------
392
405 private static void processPermutationOfEndPoints(Vertex[] pair,
406 List<Vertex[]> chosenSequenceOfEndpoints,
407 List<XoverSite> collector, FragmentSpace fragSpace)
408 {
409 Vertex vA = pair[0];
410 Vertex vB = pair[1];
411 DGraph gA = vA.getGraphOwner();
412 DGraph gB = vB.getGraphOwner();
413
414 // Exclude overlapping combinations
415 boolean exclude = false;
416 for (Vertex[] pairA : chosenSequenceOfEndpoints)
417 {
418 for (Vertex[] pairB : chosenSequenceOfEndpoints)
419 {
420 if (pairA==pairB)
421 continue;
422
423 if (pairA[0]==pairB[0] || pairA[1]==pairB[1])
424 {
425 exclude = true;
426 break;
427 }
428 }
429 if (exclude)
430 break;
431 }
432 if (exclude)
433 return;
434
435 List<Vertex> subGraphEndInA = new ArrayList<Vertex>();
436 List<Vertex> subGraphEndInB = new ArrayList<Vertex>();
437 List<Vertex> alreadyIncludedFromA = new ArrayList<Vertex>();
438 List<Vertex> alreadyIncludedFromB = new ArrayList<Vertex>();
439 for (Vertex[] otherPair : chosenSequenceOfEndpoints)
440 {
441 Vertex endOnA = otherPair[0];
442 Vertex endOnB = otherPair[1];
443
444 // Ignore vertexes that are already part of the subgraph
445 if (alreadyIncludedFromA.contains(endOnA)
446 || alreadyIncludedFromB.contains(endOnB))
447 continue;
448
449 PathSubGraph pathA = new PathSubGraph(vA, endOnA, gA);
450 PathSubGraph pathB = new PathSubGraph(vB, endOnB, gB);
451 subGraphEndInA.add(endOnA);
452 subGraphEndInB.add(endOnB);
453 alreadyIncludedFromA.addAll(pathA.getVertecesPath());
454 alreadyIncludedFromB.addAll(pathB.getVertecesPath());
455 }
456 ArrayList<Vertex> subGraphA = new ArrayList<Vertex>();
457 subGraphA.add(vA);
458 if (!subGraphEndInA.contains(vA))
459 gA.getChildTreeLimited(vA, subGraphA, subGraphEndInA, true);
460
461 ArrayList<Vertex> subGraphB = new ArrayList<Vertex>();
462 subGraphB.add(vB);
463 if (!subGraphEndInB.contains(vB))
464 gB.getChildTreeLimited(vB, subGraphB, subGraphEndInB, true);
465
466 // The two subgraphs must not be isomorfic to prevent unproductive crossover
467 if (subGraphA.size()>1 && subGraphB.size()>1)
468 {
469 DGraph subGraphCloneA = gA.extractSubgraph(subGraphA);
470 DGraph subGraphCloneB = gB.extractSubgraph(subGraphB);
471 if (subGraphCloneA.isIsomorphicTo(subGraphCloneB))
472 return;
473 } else {
474 if (subGraphA.get(0).sameAs(subGraphB.get(0), new StringBuilder()))
475 return;
476 }
477
478 checkAndAddXoverSites(fragSpace, subGraphA, subGraphB,
479 CrossoverType.SUBGRAPH, collector);
480 }
481
482//------------------------------------------------------------------------------
483
493 private static void checkAndAddXoverSites(FragmentSpace fragSpace,
494 List<Vertex> subGraphA,
495 List<Vertex> subGraphB, CrossoverType xoverType,
496 List<XoverSite> collector)
497 {
498 DGraph gOwnerA = subGraphA.get(0).getGraphOwner();
499 DGraph gOwnerB = subGraphB.get(0).getGraphOwner();
500
501 // What APs need to find a corresponding AP in the other
502 // subgraph in order to allow swapping?
503 List<AttachmentPoint> needyAPsA = gOwnerA.getInterfaceAPs(
504 subGraphA);
505 List<AttachmentPoint> allAPsA = gOwnerA.getSubgraphAPs(
506 subGraphA);
507 List<AttachmentPoint> needyAPsB = gOwnerB.getInterfaceAPs(
508 subGraphB);
509 List<AttachmentPoint> allAPsB = gOwnerB.getSubgraphAPs(
510 subGraphB);
511 if (allAPsA.size() < needyAPsB.size()
512 || allAPsB.size() < needyAPsA.size())
513 {
514 // Impossible to satisfy needy APs. Crossover site is not usable.
515 return;
516 }
517
518 // Shortcut: since the compatibility of one AP that is needed to do
519 // branch swapping is guaranteed by the identification of the seeds of
520 // swappable subgraphs, we can avoid searching for a valid A mapping
521 // when the graphs are not embedded. This because any AP that is not
522 // the one connecting the subgraph to the parent can be left free or
523 // removed without side effects on templates that embed the graph
524 // because there is no such template.
525 Template jacketTmplA = gOwnerA.getTemplateJacket();
526 Template jacketTmplB = gOwnerB.getTemplateJacket();
527 if (xoverType == CrossoverType.BRANCH
528 && jacketTmplA==null
529 && jacketTmplB==null)
530 {
531 XoverSite xos = new XoverSite(subGraphA, needyAPsA, subGraphB,
532 needyAPsB, xoverType);
533 if (!collector.contains(xos))
534 collector.add(xos);
535 return;
536 }
537
538 if ((jacketTmplA!=null && jacketTmplA.getContractLevel()
540 || (jacketTmplB!=null && jacketTmplB.getContractLevel()
542 {
543 // Avoid to alter cyclicity of inner graphs
544 for (Vertex v : subGraphA)
545 if (v.isRCV() && !gOwnerA.getRingsInvolvingVertex(v).isEmpty())
546 return;
547 for (Vertex v : subGraphB)
548 if (v.isRCV() && !gOwnerB.getRingsInvolvingVertex(v).isEmpty())
549 return;
550
551 // Avoid to change the structure of inner graphs
552 DGraph subGraphCloneA = gOwnerA.extractSubgraph(subGraphA);
553 DGraph subGraphCloneB = gOwnerB.extractSubgraph(subGraphB);
554 if (!subGraphCloneA.isIsostructuralTo(subGraphCloneB))
555 return;
556 }
557
558 // Retain connection to parent to keep directionality of spanning tree!
559 // To this end, identify the seed of the subgraphs...
560 Vertex seedOnA = gOwnerA.getDeepestAmongThese(subGraphA);
561 Vertex seedOnB = gOwnerB.getDeepestAmongThese(subGraphB);
562 //...and ensure we use the same APs to link to the parent graph.
563 APMapping fixedRootAPs = new APMapping();
564 fixedRootAPs.put(seedOnA.getEdgeToParent().getTrgAP(),
565 seedOnB.getEdgeToParent().getTrgAP());
566
567 APMapFinder apmf = new APMapFinder(fragSpace,
568 allAPsA, needyAPsA, allAPsB, needyAPsB,
569 fixedRootAPs,
570 false, // false: we stop at the first good mapping
571 true, // true: only complete mapping
572 false); // false: free APs are not compatible by default
573 if (apmf.foundMapping())
574 {
575 XoverSite xos = new XoverSite(subGraphA, needyAPsA,
576 subGraphB, needyAPsB, xoverType);
577 if (!collector.contains(xos))
578 collector.add(xos);
579 }
580 }
581
582//------------------------------------------------------------------------------
583
595 private static boolean isCrossoverPossible(Edge eA, Edge eB,
596 FragmentSpace fragSpace)
597 {
598 APClass apClassSrcA = eA.getSrcAPClass();
599 APClass apClassTrgA = eA.getTrgAPClass();
600 APClass apClassSrcB = eB.getSrcAPClass();
601 APClass apClassTrgB = eB.getTrgAPClass();
602
603 if (apClassSrcA.isCPMapCompatibleWith(apClassTrgB, fragSpace))
604 {
605 if (apClassSrcB.isCPMapCompatibleWith(apClassTrgA, fragSpace))
606 {
607 return true;
608 }
609 }
610 return false;
611 }
612
613//------------------------------------------------------------------------------
614
626 protected static boolean deleteLink(Vertex vertex,
627 int chosenVrtxIdx, Monitor mnt, FragmentSpace fragSpace)
628 throws DENOPTIMException
629 {
630 DGraph graph = vertex.getGraphOwner();
631 boolean done = graph.removeVertexAndWeld(vertex, fragSpace);
632 if (!done)
633 {
635 }
636 return done;
637 }
638
639//------------------------------------------------------------------------------
640
657 protected static boolean substituteLink(Vertex vertex,
658 int chosenVrtxIdx, Monitor mnt, FragmentSpace fragSpace)
659 throws DENOPTIMException
660 {
661 //TODO: for reproducibility, the AP mapping should become an optional
662 // parameter: if given we try to use it, if not given, GraphLinkFinder
663 // will try to find a suitable mapping.
664
665 GraphLinkFinder glf = null;
666 if (chosenVrtxIdx<0)
667 {
668 glf = new GraphLinkFinder(fragSpace, vertex);
669 } else {
670 glf = new GraphLinkFinder(fragSpace, vertex, chosenVrtxIdx);
671 }
672 if (!glf.foundAlternativeLink())
673 {
675 return false;
676 }
677
678 DGraph graph = vertex.getGraphOwner();
679 boolean done = graph.replaceVertex(vertex,
683 fragSpace);
684 if (!done)
685 {
686 mnt.increase(
688 }
689 return done;
690 }
691
692//------------------------------------------------------------------------------
693
709 public static boolean extendLink(Vertex vertex,
710 int chosenAPId, Monitor mnt, FragmentSpace fragSpace)
711 throws DENOPTIMException
712 {
713 return extendLink(vertex, chosenAPId, -1 , mnt, fragSpace);
714 }
715
716//------------------------------------------------------------------------------
717
735 public static boolean extendLink(Vertex vertex, int chosenAPId,
736 int chosenNewVrtxId, Monitor mnt, FragmentSpace fragSpace)
737 throws DENOPTIMException
738 {
739 AttachmentPoint ap = vertex.getAP(chosenAPId);
740 if (ap == null)
741 {
742 throw new DENOPTIMException("No AP "+chosenAPId+" in vertex "
743 +vertex+".");
744 }
746
747 if (e == null)
748 {
749 throw new DENOPTIMException("AP "+chosenAPId+" in vertex "
750 +vertex+" has no edge user.");
751 }
752 if (e.getSrcAP().getOwner() != vertex)
753 {
754 throw new DENOPTIMException("Request to extend a link from a child "
755 + "vertex (AP "+chosenAPId+" of vertex "+vertex+").");
756 }
757 return extendLink(e, chosenNewVrtxId, mnt, fragSpace);
758 }
759
760//------------------------------------------------------------------------------
761
774 public static boolean extendLink(Edge edge, int chosenBBIdx,
775 Monitor mnt, FragmentSpace fragSpace) throws DENOPTIMException
776 {
777 //TODO: for reproducibility, the AP mapping should become an optional
778 // parameter: if given we try to use it, if not given we GraphLinkFinder
779 // will try to find a suitable mapping.
780
781 GraphLinkFinder glf = null;
782 if (chosenBBIdx < 0)
783 {
784 glf = new GraphLinkFinder(fragSpace, edge);
785 } else {
786 glf = new GraphLinkFinder(fragSpace, edge,chosenBBIdx);
787 }
788 if (!glf.foundAlternativeLink())
789 {
791 return false;
792 }
793
794 // Need to convert the mapping to make it independent from the instance
795 // or the new link.
796 LinkedHashMap<AttachmentPoint,Integer> apMap =
797 new LinkedHashMap<AttachmentPoint,Integer>();
798 for (Entry<AttachmentPoint, AttachmentPoint> e :
799 glf.getChosenAPMapping().entrySet())
800 {
801 apMap.put(e.getKey(), e.getValue().getIndexInOwner());
802 }
803
804 DGraph graph = edge.getSrcAP().getOwner().getGraphOwner();
805 boolean done = graph.insertVertex(edge,
808 apMap, fragSpace);
809 if (!done)
810 {
811 mnt.increase(
813 }
814 return done;
815 }
816
817//------------------------------------------------------------------------------
818
840 protected static boolean rebuildBranch(Vertex vertex,
841 boolean force, int chosenVrtxIdx, int chosenApId,
842 GAParameters settings) throws DENOPTIMException
843 {
844 DGraph g = vertex.getGraphOwner();
845
846 // first get the edge with the parent
847 Edge e = vertex.getEdgeToParent();
848 if (e == null)
849 {
850 String msg = "Program Bug in substituteFragment: Unable to locate "
851 + "parent edge for vertex "+vertex+" in graph "+g;
852 settings.getLogger().log(Level.SEVERE, msg);
853 throw new DENOPTIMException(msg);
854 }
855
856 // vertex id of the parent
857 long pvid = e.getSrcVertex();
858 Vertex parentVrt = g.getVertexWithId(pvid);
859
860 // Need to remember symmetry because we are deleting the symm. vertices
861 boolean symmetry = g.hasSymmetryInvolvingVertex(vertex);
862
863 // delete the vertex and its children and all its symmetric partners
864 deleteFragment(vertex);
865
866 // extend the graph at this vertex but without recursion
867 return extendGraph(parentVrt,false,symmetry,force,chosenVrtxIdx,
868 chosenApId, settings);
869 }
870
871//------------------------------------------------------------------------------
872
881 protected static boolean deleteFragment(Vertex vertex)
882 throws DENOPTIMException
883 {
884 long vid = vertex.getVertexId();
885 DGraph molGraph = vertex.getGraphOwner();
886
887 if (molGraph.hasSymmetryInvolvingVertex(vertex))
888 {
889 List<Vertex> toRemove = new ArrayList<Vertex>();
890 toRemove.addAll(molGraph.getSymSetForVertex(vertex));
891 for (Vertex v : toRemove)
892 {
893 molGraph.removeBranchStartingAt(v);
894 }
895 }
896 else
897 {
898 molGraph.removeBranchStartingAt(vertex);
899 }
900
901 if (molGraph.getVertexWithId(vid) == null && molGraph.getVertexCount() > 1)
902 return true;
903
904 return false;
905 }
906
907//------------------------------------------------------------------------------
908
921 protected static boolean deleteChain(Vertex vertex, Monitor mnt,
922 FragmentSpace fragSpace) throws DENOPTIMException
923 {
924 long vid = vertex.getVertexId();
925 DGraph molGraph = vertex.getGraphOwner();
926
927 if (molGraph.hasSymmetryInvolvingVertex(vertex))
928 {
929 List<Vertex> toRemove = new ArrayList<Vertex>();
930 toRemove.addAll(molGraph.getSymSetForVertex(vertex));
931 for (Vertex v : toRemove)
932 {
933 if (!v.getMutationTypes(new ArrayList<MutationType>())
934 .contains(MutationType.DELETECHAIN))
935 continue;
936 molGraph.removeChainUpToBranching(v, fragSpace);
937 }
938 }
939 else
940 {
941 molGraph.removeChainUpToBranching(vertex, fragSpace);
942 }
943
944 if (molGraph.getVertexWithId(vid) == null && molGraph.getVertexCount() > 1)
945 return true;
946 return false;
947 }
948
949//------------------------------------------------------------------------------
950
966 protected static boolean addRing(Vertex vertex, Monitor mnt, boolean force,
967 FragmentSpace fragSpace, GAParameters settings)
968 throws DENOPTIMException
969 {
970 // get settings //TODO: this should happen inside RunTimeParameters
972 if (settings.containsParameters(ParametersType.RC_PARAMS))
973 {
974 rcParams = (RingClosureParameters)settings.getParameters(
976 }
977 Randomizer rng = settings.getRandomizer();
978
979 // First of all we remove capping groups in the graph
980 vertex.getGraphOwner().removeCappingGroups();
981
982 List<AttachmentPoint> freeeAPs = vertex.getFreeAPThroughout();
983 if (freeeAPs.size()==0)
984 {
986 return false;
987 }
988 DGraph originalGraph = vertex.getGraphOwner();
989 DGraph tmpGraph = originalGraph.clone();
990
991 Vertex headVrtx = tmpGraph.getVertexAtPosition(originalGraph.indexOf(
992 vertex));
993
994 // Define the set of rings on the cloned (tmp) graph
995 List<Ring> setOfRingsOnTmpGraph = null;
996 for (AttachmentPoint srcAP : headVrtx.getFreeAPThroughout())
997 {
998 APClass apc = srcAP.getAPClass();
999
1000 // Skip if the APClass is not allowed to form ring closures
1001 if (!fragSpace.getRCCompatibilityMatrix().containsKey(apc))
1002 {
1003 continue;
1004 }
1005 List<APClass> rcTrgAPCs = fragSpace.getRCCompatibilityMatrix().get(
1006 apc);
1007
1008 // NB: the fragment space may or may not have a RCV for this AP
1009 Vertex rcvOnSrcAP = null;
1010 List<Vertex> candidateRCVs = fragSpace.getRCVsForAPClass(apc);
1011 boolean rcvIsChosenArbitrarily = false;
1012 if (candidateRCVs.size()>0)
1013 {
1014 rcvOnSrcAP = rng.randomlyChooseOne(candidateRCVs);
1015 } else {
1016 rcvIsChosenArbitrarily = true;
1017 rcvOnSrcAP = fragSpace.getPolarizedRCV(true);
1018 }
1019
1020 // Add the RCV on this AP
1021 List<Vertex> rcvAddedToGraph = new ArrayList<Vertex>();
1022 tmpGraph.appendVertexOnAP(srcAP, rcvOnSrcAP.getAP(0));
1023 rcvAddedToGraph.add(rcvOnSrcAP);
1024
1025 // Add a few RCVs in the rest of the system
1026 // WARNING: hard-coded max number of attempts. It should not be too
1027 // high to prevent combinatorial explosion.
1028 for (int i=0; i<20; i++)
1029 {
1030 // Do it only on APs that APClass-compatible with chord formation
1031 List<AttachmentPoint> apsToTry =
1032 tmpGraph.getAvailableAPsThroughout();
1033 int numberOfAttempts = apsToTry.size();
1034 AttachmentPoint trgAP = null;
1035 for (int iap=0; iap<numberOfAttempts; iap++)
1036 {
1037 AttachmentPoint candidate = rng.randomlyChooseOne(apsToTry);
1038 if (rcTrgAPCs.contains(candidate.getAPClass()))
1039 {
1040 trgAP = candidate;
1041 break;
1042 }
1043 apsToTry.remove(trgAP);
1044 }
1045 if (trgAP==null)
1046 {
1047 // No more AP can be used to form rings with srcAP
1048 break;
1049 }
1050
1051 // Choose type of RCV
1052 Vertex rcvOnTrgAP = null;
1053 if (rcvIsChosenArbitrarily)
1054 {
1055 rcvOnTrgAP = fragSpace.getPolarizedRCV(false);
1056 } else {
1057 List<Vertex> candRCVs = fragSpace.getRCVsForAPClass(
1058 trgAP.getAPClass());
1059 if (candRCVs.size()>0)
1060 {
1061 APClass requiredAPC = RingClosingAttractor.RCAAPCMAP.get(
1062 rcvOnSrcAP.getAP(0).getAPClass());
1063 List<Vertex> keptRCVs = new ArrayList<Vertex>();
1064 for (Vertex rcv : candRCVs)
1065 {
1066 if (requiredAPC.equals(rcv.getAP(0).getAPClass()))
1067 keptRCVs.add(rcv);
1068 }
1069 rcvOnTrgAP = rng.randomlyChooseOne(keptRCVs);
1070 if (rcvOnTrgAP==null)
1071 {
1072 // no RCV is both usable and compatible with the
1073 // one already selected for srcAP
1074 continue;
1075 }
1076 } else {
1077 // The APClass settings and RCV compatibility rules
1078 // do not allow to identify a suitable RCV
1079 continue;
1080 }
1081 }
1082
1083 // append RCV
1084 tmpGraph.appendVertexOnAP(trgAP, rcvOnTrgAP.getAP(0));
1085 rcvAddedToGraph.add(rcvOnTrgAP);
1086 }
1087 if (rcvAddedToGraph.size() < 2)
1088 {
1089 // TODO: we could consider counting these to see what is the
1090 // most frequent cause of this mutation to fail
1091 continue;
1092 }
1093
1094 // Define rings to close in tmp graph
1096 settings.getLogger(), rng);
1097 t3d.setAlignBBsIn3D(false); //3D not needed
1098 IAtomContainer mol = t3d.convertGraphTo3DAtomContainer(tmpGraph,true);
1100 mol,
1101 tmpGraph,
1102 settings.getMaxRingsAddedByMutation(),
1103 fragSpace, rcParams);
1104
1105 //TODO: possibility to generate multiple combinations, rank them,
1106 // and pick the best one. Though definition of comparator is not
1107 // unambiguous.
1108
1109 setOfRingsOnTmpGraph = rCombIter.next();
1110
1111 // Termination of search over trgAPs
1112 if (setOfRingsOnTmpGraph.size()>0)
1113 break;
1114
1115 // Cleanup before starting new iteration
1116 for (Vertex toRemove : rcvAddedToGraph)
1117 tmpGraph.removeVertex(toRemove);
1118 }
1119 if (setOfRingsOnTmpGraph==null || setOfRingsOnTmpGraph.size()==0)
1120 {
1122 return false;
1123 }
1124
1125 // Project rings into the actual graph
1126 boolean done = false;
1127 for (Ring rOnTmp : setOfRingsOnTmpGraph)
1128 {
1129 // Project head RCV and all info to attach it to original graph
1130 Vertex vToHeadRCV = originalGraph.getVertexAtPosition(
1131 tmpGraph.indexOf(rOnTmp.getHeadVertex().getParent()));
1132 AttachmentPoint apToHeadRCV = vToHeadRCV.getAP(
1133 rOnTmp.getHeadVertex().getEdgeToParent().getSrcAP()
1134 .getIndexInOwner());
1135 Vertex headRCV = rOnTmp.getHeadVertex().clone();
1137
1138 // And append head RCV on original graph
1139 originalGraph.appendVertexOnAP(apToHeadRCV, headRCV.getAP(0));
1140
1141 // Project tail RCV and all info to attach it to original graph
1142 Vertex vToTailRCV = originalGraph.getVertexAtPosition(
1143 tmpGraph.indexOf(rOnTmp.getTailVertex().getParent()));
1144 AttachmentPoint apToTailRCV = vToTailRCV.getAP(
1145 rOnTmp.getTailVertex().getEdgeToParent().getSrcAP()
1146 .getIndexInOwner());
1147 Vertex tailRCV = rOnTmp.getHeadVertex().clone();
1149
1150 // And append tail RCV on original graph
1151 originalGraph.appendVertexOnAP(apToTailRCV, tailRCV.getAP(0));
1152
1153 // Add ring
1154 originalGraph.addRing(headRCV, tailRCV);
1155 done = true;
1156 }
1157
1158 // Restore capping groups
1159 vertex.getGraphOwner().addCappingGroups(fragSpace);
1160
1161 return done;
1162 }
1163
1164//------------------------------------------------------------------------------
1165
1180 protected static boolean extendGraph(Vertex curVertex,
1181 boolean extend,
1182 boolean symmetryOnAps,
1183 GAParameters settings)
1184 throws DENOPTIMException
1185 {
1186 return extendGraph(curVertex, extend, symmetryOnAps, false, -1, -1,
1187 settings);
1188 }
1189
1190//------------------------------------------------------------------------------
1191
1215 protected static boolean extendGraph(Vertex curVrtx,
1216 boolean extend,
1217 boolean symmetryOnAps,
1218 boolean force,
1219 int chosenVrtxIdx,
1220 int chosenApId,
1221 GAParameters settings)
1222 throws DENOPTIMException
1223 {
1224 // get settings //TODO: this should happen inside RunTimeParameters
1226 if (settings.containsParameters(ParametersType.RC_PARAMS))
1227 {
1228 rcParams = (RingClosureParameters)settings.getParameters(
1230 }
1232 if (settings.containsParameters(ParametersType.FS_PARAMS))
1233 {
1234 fsParams = (FragmentSpaceParameters)settings.getParameters(
1236 }
1237 int maxHeavyAtoms = fsParams.getMaxHeavyAtom();
1238
1239 // return true if the append has been successful
1240 boolean status = false;
1241
1242 // check if the fragment has available APs
1243 if (!curVrtx.hasFreeAP())
1244 {
1245 return status;
1246 }
1247
1248 DGraph molGraph = curVrtx.getGraphOwner();
1249 int lvl = molGraph.getLevel(curVrtx);
1250
1251 ArrayList<Long> addedVertices = new ArrayList<>();
1252
1253 List<AttachmentPoint> lstDaps = curVrtx.getAttachmentPoints();
1254 List<AttachmentPoint> toDoAPs = new ArrayList<AttachmentPoint>();
1255 toDoAPs.addAll(lstDaps);
1256 for (int i=0; i<lstDaps.size(); i++)
1257 {
1258 // WARNING: randomization decouples 'i' from the index of the AP
1259 // in the vertex's list of APs! So 'i' is just the i-th attempt on
1260 // the curVertex.
1261
1262 AttachmentPoint ap = settings.getRandomizer().randomlyChooseOne(
1263 toDoAPs);
1264 toDoAPs.remove(ap);
1265 int apId = ap.getIndexInOwner();
1266
1267 // is it possible to extend on this AP?
1268 if (!ap.isAvailable())
1269 {
1270 continue;
1271 }
1272
1273 // NB: this is done also in addRing()
1274 // Ring closure does not change the size of the molecule, so we
1275 // give it an extra chance to occur irrespectively on molecular size
1276 // limit, while still subject of crowdedness probability.
1277 boolean allowOnlyRingClosure = false;
1278 if (!force)
1279 {
1280 // Decide whether we want to extend the graph at this AP?
1281 // Note that depending on the criterion (level/molSize) one
1282 // of these two first factors is 1.0.
1283 double molSizeProb = EAUtils.getMolSizeProbability(molGraph,
1284 settings);
1285 double byLevelProb = EAUtils.getGrowthByLevelProbability(lvl,
1286 settings);
1287 double crowdingProb = EAUtils.getCrowdingProbability(ap,
1288 settings);
1289 double extendGraphProb = molSizeProb * byLevelProb * crowdingProb;
1290 boolean fgrow = settings.getRandomizer().nextBoolean(
1291 extendGraphProb);
1292 if (!fgrow)
1293 {
1294 if (rcParams.allowRingClosures()
1295 && settings.getRandomizer().nextBoolean(byLevelProb
1296 * crowdingProb))
1297 {
1298 allowOnlyRingClosure = true;
1299 } else {
1300 continue;
1301 }
1302 }
1303 }
1304
1305 // Apply closability bias in selection of next fragment
1306 if (!allowOnlyRingClosure
1307 && rcParams.allowRingClosures()
1309 {
1310 boolean successful = attachFragmentInClosableChain(curVrtx,
1311 apId, molGraph, addedVertices, settings);
1312 if (successful)
1313 {
1314 continue;
1315 }
1316 }
1317
1318 // find a compatible combination of fragment and AP
1319 IdFragmentAndAP chosenFrgAndAp = null;
1320 if (allowOnlyRingClosure)
1321 {
1322 // NB: this works only for RCVs that are in the BBSpace, does
1323 // not generate a default RCV on-the-fly. So if no RCV is found
1324 // we'll get a pointer to nothing, which is what we check in the
1325 // next IF-block.
1326 chosenFrgAndAp = getRCVForSrcAp(curVrtx, apId,
1327 fsParams.getFragmentSpace());
1328 } else {
1329 chosenFrgAndAp = getFrgApForSrcAp(curVrtx,
1330 apId, chosenVrtxIdx, chosenApId, fsParams.getFragmentSpace());
1331 }
1332 int fid = chosenFrgAndAp.getVertexMolId();
1333 if (fid == -1)
1334 {
1335 continue;
1336 }
1337
1338 // Get the vertex that we'll add to the graph
1339 Vertex incomingVertex = Vertex.newVertexFromLibrary(-1,
1340 chosenFrgAndAp.getVertexMolId(),
1342 fsParams.getFragmentSpace());
1343
1344 // Stop if graph is already too big
1345 if ((curVrtx.getGraphOwner().getHeavyAtomsCount() +
1346 incomingVertex.getHeavyAtomsCount()) > maxHeavyAtoms)
1347 {
1348 continue;
1349 }
1350
1351 // Decide on symmetric substitution within this vertex...
1352 boolean cpOnSymAPs = applySymmetry(
1354 ap.getAPClass()),
1355 settings.getSymmetryProbability(),
1356 fsParams.getRandomizer());
1357 SymmetricAPs symAPs = new SymmetricAPs();
1358 if (curVrtx.getSymmetricAPs(ap).size()!=0
1359 && (cpOnSymAPs || symmetryOnAps)
1360 && !allowOnlyRingClosure)
1361 {
1362 symAPs.addAll(curVrtx.getSymmetricAPs(ap));
1363
1364 // Are symmetric APs rooted on same atom?
1365 boolean allOnSameSrc = true;
1366 for (AttachmentPoint symAP : symAPs)
1367 {
1368 if (!symAP.hasSameSrcAtom(ap))
1369 {
1370 allOnSameSrc = false;
1371 break;
1372 }
1373 }
1374
1375 if (allOnSameSrc)
1376 {
1377 // If the APs are rooted on the same src atom, we want to
1378 // apply the crowdedness probability to avoid over crowded
1379 // atoms
1380
1381 int crowdedness = EAUtils.getCrowdedness(ap);
1382
1383 SymmetricAPs toKeep = new SymmetricAPs();
1384
1385 // Start by keeping "ap"
1386 toKeep.add(ap);
1387 crowdedness = crowdedness + 1;
1388
1389 // Pick the accepted value once (used to decide how much
1390 // crowdedness we accept)
1391 double shot = settings.getRandomizer().nextDouble();
1392
1393 // Keep as many as allowed by the crowdedness decision
1394 for (AttachmentPoint symAP : symAPs)
1395 {
1396 if (symAP == ap)
1397 continue;
1398
1399 double crowdProb = EAUtils.getCrowdingProbability(
1400 crowdedness, settings);
1401
1402 if (shot > crowdProb)
1403 break;
1404
1405 toKeep.add(symAP);
1406 crowdedness = crowdedness + 1;
1407 }
1408
1409 // Adjust the list of symmetric APs to work with
1410 symAPs = toKeep;
1411 }
1412 } else {
1413 symAPs = new SymmetricAPs();
1414 symAPs.add(ap);
1415 }
1416
1417 // ...and inherit symmetry from previous levels
1418 boolean cpOnSymVrts = molGraph.hasSymmetryInvolvingVertex(curVrtx);
1419 SymmetricVertexes symVerts = new SymmetricVertexes();
1420 if (cpOnSymVrts)
1421 {
1422 symVerts = molGraph.getSymSetForVertex(curVrtx);
1423 }
1424 else
1425 {
1426 symVerts.add(curVrtx);
1427 }
1428
1429 // Consider size after application of symmetry
1430 if ((curVrtx.getGraphOwner().getHeavyAtomsCount() +
1431 incomingVertex.getHeavyAtomsCount() * symVerts.size()
1432 * symAPs.size()) > maxHeavyAtoms)
1433 {
1434 continue;
1435 }
1436
1437 // Collects all sym APs: within the vertex and outside it
1438 List<AttachmentPoint> allAPsFromSymVerts = new ArrayList<>();
1439 for (Vertex symVrt : symVerts)
1440 {
1441 for (AttachmentPoint apOnVrt : symAPs)
1442 {
1443 AttachmentPoint apOnSymVrt = symVrt.getAP(
1444 apOnVrt.getIndexInOwner());
1445 // This check is most often not needed, but it prevents that
1446 // misleading symmetry relations are used to break APClass
1447 // compatibility constraints
1448 if (apOnVrt.sameAs(apOnSymVrt)
1449 // Also ignore previously found APs
1450 && !symAPs.contains(apOnSymVrt))
1451 {
1452 allAPsFromSymVerts.add(apOnSymVrt);
1453 }
1454 }
1455 }
1456 symAPs.addAll(allAPsFromSymVerts);
1457
1459
1460 // loop on all symmetric vertices, but can be only one.
1461 SymmetricVertexes newSymSetOfVertices = new SymmetricVertexes();
1462 for (AttachmentPoint symAP : symAPs)
1463 {
1464 if (!symAP.isAvailable())
1465 {
1466 continue;
1467 }
1468
1469 // Finally add the fragment on a symmetric AP
1470 long newVrtId = GraphUtils.getUniqueVertexIndex();
1471 Vertex fragVertex = Vertex.newVertexFromLibrary(newVrtId,
1472 chosenFrgAndAp.getVertexMolId(),
1474 fsParams.getFragmentSpace());
1475 AttachmentPoint trgAP = fragVertex.getAP(
1476 chosenFrgAndAp.getApId());
1477
1478 molGraph.appendVertexOnAP(symAP, trgAP);
1479
1480 addedVertices.add(newVrtId);
1481 newSymSetOfVertices.add(fragVertex);
1482 }
1483
1484 // If any, store symmetry of new vertices in the graph
1485 if (newSymSetOfVertices.size() > 1)
1486 {
1487 molGraph.addSymmetricSetOfVertices(newSymSetOfVertices);
1488 }
1489 } // end loop over APs
1490
1491 if (extend)
1492 {
1493 // attempt to further extend each of the newly added vertices
1494 for (int i=0; i<addedVertices.size(); i++)
1495 {
1496 long vid = addedVertices.get(i);
1497 Vertex v = molGraph.getVertexWithId(vid);
1498 extendGraph(v, extend, symmetryOnAps, settings);
1499 }
1500 }
1501
1502 if (addedVertices.size() > 0)
1503 status = true;
1504
1505 return status;
1506 }
1507
1508//------------------------------------------------------------------------------
1509
1521 protected static IdFragmentAndAP getFrgApForSrcAp(Vertex curVertex,
1522 int dapidx, FragmentSpace fragSpace) throws DENOPTIMException
1523 {
1524 return getFrgApForSrcAp(curVertex, dapidx, -1, -1, fragSpace);
1525 }
1526
1527//------------------------------------------------------------------------------
1528
1546 protected static IdFragmentAndAP getFrgApForSrcAp(Vertex curVertex,
1547 int dapidx, int chosenVrtxIdx, int chosenApId,
1548 FragmentSpace fragSpace) throws DENOPTIMException
1549 {
1550 List<AttachmentPoint> lstDaps = curVertex.getAttachmentPoints();
1551 AttachmentPoint curDap = lstDaps.get(dapidx);
1552
1553 // Initialize with an empty pointer
1554 IdFragmentAndAP res = new IdFragmentAndAP(-1, -1, BBType.FRAGMENT, -1,
1555 -1, -1);
1556 if (!fragSpace.useAPclassBasedApproach())
1557 {
1558 int fid = fragSpace.getRandomizer().nextInt(
1559 fragSpace.getFragmentLibrary().size());
1560 res = new IdFragmentAndAP(-1,fid,BBType.FRAGMENT,-1,-1,-1);
1561 }
1562 else
1563 {
1564 List<IdFragmentAndAP> candidates =
1565 fragSpace.getFragAPsCompatibleWithClass(
1566 curDap.getAPClass());
1567 if (candidates.size() > 0)
1568 {
1569 if (chosenVrtxIdx>-1 && chosenApId>-1)
1570 {
1571 // We have asked to force the selection
1572 res = new IdFragmentAndAP(-1,chosenVrtxIdx,BBType.FRAGMENT,
1573 chosenApId,-1,-1);
1574 } else {
1575 res = fragSpace.getRandomizer().randomlyChooseOne(candidates);
1576 }
1577 }
1578 }
1579 return res;
1580 }
1581
1582//------------------------------------------------------------------------------
1583
1595 protected static IdFragmentAndAP getRCVForSrcAp(Vertex curVertex,
1596 int dapidx, FragmentSpace fragSpace) throws DENOPTIMException
1597 {
1598 AttachmentPoint ap = curVertex.getAP(dapidx);
1599
1600 Randomizer rng = fragSpace.getRandomizer();
1601 List<Vertex> rcvs = fragSpace.getRCVs();
1602 Vertex chosen = null;
1603 if (!fragSpace.useAPclassBasedApproach())
1604 {
1605 chosen = rng.randomlyChooseOne(rcvs);
1606 } else {
1607 List<Vertex> candidates = fragSpace.getRCVsForAPClass(
1608 ap.getAPClass());
1609 if (candidates.size() > 0)
1610 {
1611 chosen = rng.randomlyChooseOne(candidates);
1612 }
1613 }
1614
1615 IdFragmentAndAP pointer = new IdFragmentAndAP();
1616 if (chosen!=null)
1617 pointer = new IdFragmentAndAP(-1, chosen.getBuildingBlockId(),
1618 chosen.getBuildingBlockType(), 0, -1, -1);
1619 return pointer;
1620 }
1621
1622//------------------------------------------------------------------------------
1623
1624 protected static boolean attachFragmentInClosableChain(
1625 Vertex curVertex, int dapidx, DGraph molGraph,
1626 ArrayList<Long> addedVertices, GAParameters settings)
1627 throws DENOPTIMException
1628 {
1629 boolean res = false;
1631 if (settings.containsParameters(ParametersType.FS_PARAMS))
1632 {
1633 fsParams = (FragmentSpaceParameters)settings.getParameters(
1635 }
1636
1637 // Get candidate fragments
1638 ArrayList<FragForClosabChains> lscFfCc = getFragmentForClosableChain(
1639 curVertex, dapidx, molGraph);
1640
1641 // Here we can get:
1642 // 1) a selection of fragments that allow to close rings
1643 // 2) an empty list because no fragments allow to close rings
1644 // 3) "-1" as molID that means there are closable chains that
1645 // terminate at the current level, so we let the standard
1646 // routine proceeds selecting an extension of the chain
1647 // or cap this end.
1648
1649 // Choose a candidate and attach it to the graph
1650 int numCands = lscFfCc.size();
1651 if (numCands > 0)
1652 {
1653 int chosenId = settings.getRandomizer().nextInt(numCands);
1654 FragForClosabChains chosenFfCc = lscFfCc.get(chosenId);
1655 ArrayList<Integer> newFragIds = chosenFfCc.getFragIDs();
1656 int molIdNewFrag = newFragIds.get(0);
1657 BBType typeNewFrag = BBType.parseInt(newFragIds.get(1));
1658 int dapNewFrag = newFragIds.get(2);
1659 if (molIdNewFrag != -1)
1660 {
1661 long newvid = GraphUtils.getUniqueVertexIndex();
1663 newvid, molIdNewFrag, typeNewFrag,
1664 fsParams.getFragmentSpace());
1665
1666 molGraph.appendVertexOnAP(curVertex.getAP(dapidx),
1667 newVrtx.getAP(dapNewFrag));
1668
1669 if (newvid != -1)
1670 {
1671 addedVertices.add(newvid);
1672 // update list of candidate closable chains
1673 molGraph.getClosableChains().removeAll(
1674 chosenFfCc.getIncompatibleCC());
1675 APClass apc = curVertex.getAttachmentPoints().get(
1676 dapidx).getAPClass();
1677 if (applySymmetry(
1679 settings.getSymmetryProbability(),
1680 fsParams.getRandomizer()))
1681 {
1682//TODO: implement symmetric substitution with closability bias
1683 }
1684 res = true;
1685 }
1686 else
1687 {
1688 String msg = "BUG: Incorrect vertex num. Contact author.";
1689 settings.getLogger().log(Level.SEVERE, msg);
1690 throw new DENOPTIMException(msg);
1691 }
1692 }
1693 }
1694 return res;
1695 }
1696
1697//------------------------------------------------------------------------------
1698
1703 private static class FragForClosabChains
1704 {
1705 private ArrayList<ClosableChain> compatChains;
1706 private ArrayList<ClosableChain> incompatChains;
1707 private ArrayList<Integer> fragIds;
1708
1709 //----------------------------------------------------------------------
1710
1711 public FragForClosabChains(ArrayList<ClosableChain> compatChains,
1712 ArrayList<ClosableChain> incompatChains,
1713 ArrayList<Integer> fragIds)
1714 {
1715 this.compatChains = compatChains;
1716 this.incompatChains = incompatChains;
1717 this.fragIds = fragIds;
1718 }
1719
1720 //----------------------------------------------------------------------
1721
1723 {
1724 compatChains.add(icc);
1725 }
1726
1727 //----------------------------------------------------------------------
1728
1729 public ArrayList<ClosableChain> getCompatibleCC()
1730 {
1731 return compatChains;
1732 }
1733
1734 //----------------------------------------------------------------------
1735
1736 public ArrayList<ClosableChain> getIncompatibleCC()
1737 {
1738 return incompatChains;
1739 }
1740
1741 //----------------------------------------------------------------------
1742
1743 public ArrayList<Integer> getFragIDs()
1744 {
1745 return fragIds;
1746 }
1747
1748 //----------------------------------------------------------------------
1749 }
1750
1751//------------------------------------------------------------------------------
1752
1758 protected static ArrayList<FragForClosabChains> getFragmentForClosableChain(
1759 Vertex curVertex,
1760 int dapidx,
1761 DGraph molGraph)
1762 throws DENOPTIMException
1763 {
1764 // Select candidate fragments respecting the closability conditions
1765 ArrayList<FragForClosabChains> lstChosenFfCc =
1766 new ArrayList<FragForClosabChains>();
1767
1768 if (molGraph.getClosableChains().size() == 0)
1769 {
1770 return lstChosenFfCc;
1771 }
1772
1773 if (curVertex.getBuildingBlockType() == BBType.SCAFFOLD)
1774 {
1775 for (ClosableChain cc : molGraph.getClosableChains())
1776 {
1777 int posInCc = cc.involvesVertex(curVertex);
1778 ChainLink cLink = cc.getLink(posInCc);
1779 int nfid = -1;
1780 BBType nfty = BBType.UNDEFINED;
1781 int nfap = -1;
1782
1783 if (cLink.getApIdToLeft() != dapidx &&
1784 cLink.getApIdToRight() != dapidx)
1785 {
1786 // Chain does not involve AP dapidx
1787 continue;
1788 }
1789
1790 if (cLink.getApIdToRight() == dapidx)
1791 {
1792 if (cc.getSize() > (posInCc+1))
1793 {
1794 // cLink is NOT the rightmost chain link
1795 ChainLink nextChainLink = cc.getLink(posInCc+1);
1796 nfid = nextChainLink.getIdx();
1797 nfty = nextChainLink.getFragType();
1798 nfap = nextChainLink.getApIdToLeft();
1799 }
1800 else
1801 {
1802 // cLink is the rightmost chain link
1803 // closability bias suggest NO fragment
1804 }
1805 }
1806 else if (cLink.getApIdToLeft() == dapidx)
1807 {
1808 if ((posInCc-1) >= 0)
1809 {
1810 // cLink is NOT the leftmost chain link
1811 ChainLink nextChainLink = cc.getLink(posInCc-1);
1812 nfid = nextChainLink.getIdx();
1813 nfty = nextChainLink.getFragType();
1814 nfap = nextChainLink.getApIdToRight();
1815 }
1816 else
1817 {
1818 // cLink is the leftmost chain link
1819 // closability bias suggest NO fragment
1820 }
1821 }
1822
1823 ArrayList<Integer> eligibleFrgId = new ArrayList<Integer>();
1824 eligibleFrgId.add(nfid);
1825 eligibleFrgId.add(nfty.toOldInt());
1826 eligibleFrgId.add(nfap);
1827 boolean found = false;
1828 for (FragForClosabChains ffcc : lstChosenFfCc)
1829 {
1830 int fidA = ffcc.getFragIDs().get(0);
1831 BBType ftyA = BBType.parseInt(ffcc.getFragIDs().get(1));
1832 int fapA = ffcc.getFragIDs().get(2);
1833 if (nfid==fidA && nfty==ftyA && nfap==fapA)
1834 {
1835 found = true;
1836 ffcc.getCompatibleCC().add(cc);
1837 }
1838 else
1839 {
1840 ffcc.getIncompatibleCC().add(cc);
1841 }
1842 }
1843 if (!found)
1844 {
1845 ArrayList<ClosableChain> compatChains =
1846 new ArrayList<ClosableChain>();
1847 ArrayList<ClosableChain> incompatChains =
1848 new ArrayList<ClosableChain>();
1849 for (FragForClosabChains otherFfCc : lstChosenFfCc)
1850 {
1851 incompatChains.addAll(otherFfCc.getCompatibleCC());
1852 }
1853 FragForClosabChains newChosenCc = new FragForClosabChains(
1854 compatChains,
1855 incompatChains,
1856 eligibleFrgId);
1857
1858 newChosenCc.addCompatibleCC(cc);
1859 lstChosenFfCc.add(newChosenCc);
1860 }
1861 }
1862 }
1863 else
1864 {
1865 Vertex parent = molGraph.getParent(curVertex);
1866 Edge edge = molGraph.getEdgeWithParent(
1867 curVertex.getVertexId());
1868 int prntId = parent.getBuildingBlockId();
1869 BBType prntTyp = parent.getBuildingBlockType();
1870 int prntAp = edge.getSrcAPID();
1871 int chidAp = edge.getTrgAPID();
1872 for (ClosableChain cc : molGraph.getClosableChains())
1873 {
1874 int posInCc = cc.involvesVertexAndAP(curVertex, dapidx, chidAp);
1875
1876 if (posInCc == -1)
1877 {
1878 // closable chain does not span this combination
1879 // of vertex and APs
1880 continue;
1881 }
1882
1883 ChainLink cLink = cc.getLink(posInCc);
1884 int nfid = -1;
1885 BBType nfty = BBType.UNDEFINED;
1886 int nfap = -1;
1887
1888 List<Integer> altertnativeDirections = new ArrayList<>();
1889 altertnativeDirections.add(-1);
1890 altertnativeDirections.add(+1);
1891 for (int altDir : altertnativeDirections)
1892 {
1893 ChainLink parentLink = cc.getLink(posInCc + altDir);
1894 int pLnkId = parentLink.getIdx();
1895 BBType pLnkTyp = parentLink.getFragType();
1896
1897 int pLnkAp = -1;
1898 int cApId = -1;
1899 if (altDir>0)
1900 {
1901 pLnkAp = parentLink.getApIdToRight();
1902 cApId = cLink.getApIdToLeft();
1903 } else {
1904 pLnkAp = parentLink.getApIdToLeft();
1905 cApId = cLink.getApIdToRight();
1906 }
1907 if (pLnkId==prntId && pLnkTyp==prntTyp && pLnkAp == prntAp &&
1908 cApId == chidAp)
1909 {
1910 if (cc.getSize() > (posInCc+altDir)
1911 && (posInCc+altDir) >= 0)
1912 {
1913 ChainLink nextChainLink = cc.getLink(posInCc + altDir);
1914 nfid = nextChainLink.getIdx();
1915 nfty = nextChainLink.getFragType();
1916 nfap = nextChainLink.getApIdToLeft();
1917 }
1918 else
1919 {
1920 // cLink is the rightmost chain link
1921 // closability bias suggests NO fragment
1922 }
1923 }
1924 else
1925 {
1926 // different parent link
1927 continue;
1928 }
1929 }
1930
1931 ArrayList<Integer> eligibleFrgId = new ArrayList<Integer>();
1932 eligibleFrgId.add(nfid);
1933 eligibleFrgId.add(nfty.toOldInt());
1934 eligibleFrgId.add(nfap);
1935 boolean found = false;
1936 for (FragForClosabChains ffcc : lstChosenFfCc)
1937 {
1938 int fidA = ffcc.getFragIDs().get(0);
1939 BBType ftyA = BBType.parseInt(ffcc.getFragIDs().get(1));
1940 int fapA = ffcc.getFragIDs().get(2);
1941 if (nfid==fidA && nfty==ftyA && nfap==fapA)
1942 {
1943 found = true;
1944 ffcc.getCompatibleCC().add(cc);
1945 }
1946 else
1947 {
1948 ffcc.getIncompatibleCC().add(cc);
1949 }
1950 }
1951 if (!found)
1952 {
1953 ArrayList<ClosableChain> compatChains =
1954 new ArrayList<ClosableChain>();
1955 ArrayList<ClosableChain> incompatChains =
1956 new ArrayList<ClosableChain>();
1957 for (FragForClosabChains otherFfCc : lstChosenFfCc)
1958 {
1959 incompatChains.addAll(otherFfCc.getCompatibleCC());
1960 }
1961 FragForClosabChains newChosenCc = new FragForClosabChains(
1962 compatChains,
1963 incompatChains,
1964 eligibleFrgId);
1965 newChosenCc.addCompatibleCC(cc);
1966 lstChosenFfCc.add(newChosenCc);
1967 }
1968 }
1969 }
1970 return lstChosenFfCc;
1971 }
1972
1973//------------------------------------------------------------------------------
1974
1985 public static boolean performCrossover(XoverSite site,
1986 FragmentSpace fragSpace) throws DENOPTIMException
1987 {
1988 DGraph gA = site.getA().get(0).getGraphOwner();
1989 DGraph gB = site.getB().get(0).getGraphOwner();
1990
1991 // All the APs that point away from the subgraph
1992 List<AttachmentPoint> allAPsOnA = gA.getSubgraphAPs(site.getA());
1993 List<AttachmentPoint> allAPsOnB = gB.getSubgraphAPs(site.getB());
1994
1995 // The APs that are required to have a mapping for proper crossover,
1996 // eg. because the change of subgraph needs to retain a super structure.
1997 List<AttachmentPoint> needyAPsOnA = site.getAPsNeedingMappingA();
1998 List<AttachmentPoint> needyAPsOnB = site.getAPsNeedingMappingB();
1999
2000 // APs that connects the subgraphs' root to the parent vertex
2001 AttachmentPoint apToParentA = null;
2002 AttachmentPoint apToParentB = null;
2003 for (AttachmentPoint ap : needyAPsOnA)
2004 {
2005 if (!ap.isSrcInUserThroughout())
2006 {
2007 apToParentA = ap;
2008 //WARNING: we assume there is one AND only one AP to parent!!!
2009 break;
2010 }
2011 }
2012 for (AttachmentPoint ap : needyAPsOnB)
2013 {
2014 if (!ap.isSrcInUserThroughout())
2015 {
2016 apToParentB = ap;
2017 //WARNING: we assume there is one AND only one AP to parent!!!
2018 break;
2019 }
2020 }
2021 if (apToParentA==null || apToParentB==null)
2022 {
2023 throw new DENOPTIMException("Could not identify any attachment "
2024 + "point connecting a subgraph to the rest of the graph. "
2025 + "This violates assumption that crossover does not "
2026 + "involve scaffold or vertexes without parent.");
2027 }
2028 // Check if the subgraphs can be used with reversed edge direction, or
2029 // bias the AP mapping to use the original source vertexes.
2030 APMapping fixedRootAPs = null;
2031 //TODO: REACTIVATE ONCE REVERSION of the subgrsph's spanning tree is in place.
2032 //if (!subG_M.isReversible() || !subG_F.isReversible())
2033 if (true)
2034 {
2035 // Constrain the AP mapping so that the AP originally used to
2036 // connect to the parent vertex, will also be used the same way.
2037 // Thus, forces retention of edge direction within the subgraph.
2038 fixedRootAPs = new APMapping();
2039 fixedRootAPs.put(apToParentA, apToParentB);
2040 }
2041
2042 // Find an AP mapping that satisfies both root-vertex constrain and
2043 // need to ensure the mapping of needy APs
2044 APMapFinder apmf = new APMapFinder(fragSpace,
2045 allAPsOnA, needyAPsOnA,
2046 allAPsOnB, needyAPsOnB, fixedRootAPs,
2047 false, // false means stop at the first compatible mapping.
2048 false, // false means we do not require complete mapping.
2049 false); // false means free AP are not considered compatible.
2050 if (!apmf.foundMapping())
2051 {
2052 // Since the xover site has been detected by searching for compatible
2053 // sites that do have a mapping there should always be at least one
2054 // mapping and this exception should never occur.
2055 throw new DENOPTIMException("Missing AP mapping for known XoverSite.");
2056 }
2057
2058 // To replace each subgraph in the original graphs, we need to
2059 // map the APs on the original A/B graph with those in the
2060 // corresponding incoming subgraph, which are clones of the original:
2061 DGraph subGraphA = gA.extractSubgraph(site.getA());
2062 DGraph subGraphB = gB.extractSubgraph(site.getB());
2063
2064 // Here we create the two AP mappings we need: one for A other for B.
2065 LinkedHashMap<AttachmentPoint,AttachmentPoint>
2066 apMapA = new LinkedHashMap<AttachmentPoint,AttachmentPoint>();
2067 LinkedHashMap<AttachmentPoint,AttachmentPoint>
2068 apMapB = new LinkedHashMap<AttachmentPoint,AttachmentPoint>();
2069 for (Map.Entry<AttachmentPoint, AttachmentPoint> e :
2070 apmf.getChosenAPMapping().entrySet())
2071 {
2072 AttachmentPoint apOnA = e.getKey();
2073 AttachmentPoint apOnB = e.getValue();
2074
2075 // NB: assumption that vertex IDs are healthy, AND that order of APs
2076 // is retained upon cloning of the subgraph!
2077 AttachmentPoint apOnSubGraphA = subGraphA.getVertexWithId(
2078 apOnA.getOwner().getVertexId()).getAP(
2079 apOnA.getIndexInOwner());
2080 AttachmentPoint apOnSubGraphB = subGraphB.getVertexWithId(
2081 apOnB.getOwner().getVertexId()).getAP(
2082 apOnB.getIndexInOwner());
2083 apMapA.put(apOnA, apOnSubGraphB);
2084 apMapB.put(apOnB, apOnSubGraphA);
2085 }
2086
2087 // Now we do the actual replacement of subgraphs
2088 if (!gA.replaceSubGraph(site.getA(), subGraphB, apMapA, fragSpace))
2089 return false;
2090 if (!gB.replaceSubGraph(site.getB(), subGraphA, apMapB, fragSpace))
2091 return false;
2092
2093 return true;
2094 }
2095
2096//------------------------------------------------------------------------------
2097
2110 protected static boolean applySymmetry(boolean apclassImposed,
2111 double symmetryProbability, Randomizer randomizer)
2112 {
2113 boolean r = false;
2114 if (apclassImposed)
2115 {
2116 r = true;
2117 }
2118 else
2119 {
2120 r = randomizer.nextBoolean(symmetryProbability);
2121 }
2122 return r;
2123 }
2124
2125//------------------------------------------------------------------------------
2126
2139 public static boolean performMutation(DGraph graph, Monitor mnt,
2140 GAParameters settings) throws DENOPTIMException
2141 {
2142 // Get vertices that can be mutated: they can be part of subgraphs
2143 // embedded in templates
2144 List<Vertex> mutable = graph.getMutableSites(
2145 settings.getExcludedMutationTypes());
2146 if (mutable.size() == 0)
2147 {
2149 String msg = "Graph has no mutable site. Mutation aborted.";
2150 settings.getLogger().info(msg);
2151 return false;
2152 }
2153 boolean doneMutation = true;
2154 int numberOfMutations = EAUtils.chooseNumberOfSitesToMutate(
2155 settings.getMultiSiteMutationWeights(),
2156 settings.getRandomizer().nextDouble());
2157 for (int i=0; i<numberOfMutations; i++)
2158 {
2159 if (i>0)
2160 {
2161 mutable = graph.getMutableSites(
2162 settings.getExcludedMutationTypes());
2163 break;
2164 }
2165 Vertex v = settings.getRandomizer().randomlyChooseOne(mutable);
2166 doneMutation = performMutation(v, mnt, settings);
2167 if(!doneMutation)
2168 break;
2169 }
2170 return doneMutation;
2171 }
2172
2173//------------------------------------------------------------------------------
2174
2188 public static boolean performMutation(Vertex vertex, Monitor mnt,
2189 GAParameters settings) throws DENOPTIMException
2190 {
2191 List<MutationType> mTypes = vertex.getMutationTypes(
2192 settings.getExcludedMutationTypes());
2193 if (mTypes.size() == 0)
2194 {
2195 return false;
2196 }
2197 MutationType mType = settings.getRandomizer().randomlyChooseOne(mTypes);
2198 return performMutation(vertex, mType, mnt, settings);
2199 }
2200
2201//------------------------------------------------------------------------------
2202
2214 public static boolean performMutation(Vertex vertex,
2215 MutationType mType, Monitor mnt, GAParameters settings)
2216 throws DENOPTIMException
2217 {
2218 DGraph c = vertex.getGraphOwner().clone();
2219 int pos = vertex.getGraphOwner().indexOf(vertex);
2220 try
2221 {
2222 return performMutation(vertex, mType, false, -1 ,-1, mnt, settings);
2223 } catch (IllegalArgumentException|NullPointerException e)
2224 {
2225 String debugFile = "failedMutation_" + mType
2226 + "_" + vertex.getVertexId() + "(" + pos + ")_"
2227 + settings.timeStamp + ".sdf";
2228 DenoptimIO.writeGraphToSDF(new File(debugFile), c, false,
2229 settings.getLogger(), settings.getRandomizer());
2230 settings.getLogger().warning("Fatal exception while performing "
2231 + "mutation. See file '" + debugFile + "' to reproduce the "
2232 + "problem.");
2233 throw e;
2234 }
2235 }
2236
2237//------------------------------------------------------------------------------
2238
2264 public static boolean performMutation(Vertex vertex,
2265 MutationType mType, boolean force, int chosenVrtxIdx,
2266 int chosenApId, Monitor mnt, GAParameters settings)
2267 throws DENOPTIMException
2268 {
2270 if (settings.containsParameters(ParametersType.FS_PARAMS))
2271 {
2272 fsParams = (FragmentSpaceParameters)settings.getParameters(
2274 }
2275
2276 DGraph graph = vertex.getGraphOwner();
2277 if (graph == null)
2278 {
2280 settings.getLogger().info("Vertex has no owner - "
2281 + "Mutation aborted");
2282 return false;
2283 }
2284 if (!vertex.getMutationTypes(settings.getExcludedMutationTypes())
2285 .contains(mType))
2286 {
2288 settings.getLogger().info("Vertex does not allow mutation type "
2289 + "'" + mType + "' - Mutation aborted");
2290 return false;
2291 }
2292
2293 int graphId = graph.getGraphId();
2294 int positionOfVertex = graph.indexOf(vertex);
2295 //NB: since we have renumbered the vertexes, we use the old vertex ID
2296 // when reporting what vertex is being mutated. Also, note that the
2297 // identity of the candidate is already in the graph's local msg.
2298 String mutantOrigin = graph.getLocalMsg() + "|"
2299 + vertex.getProperty(DENOPTIMConstants.STOREDVID)
2300 + " (" + positionOfVertex + ")";
2301 graph.setLocalMsg(mutantOrigin);
2302
2303 boolean done = false;
2304 switch (mType)
2305 {
2306 case CHANGEBRANCH:
2307 done = rebuildBranch(vertex, force, chosenVrtxIdx, chosenApId,
2308 settings);
2309 if (!done)
2310 mnt.increase(
2312 break;
2313
2314 case CHANGELINK:
2315 done = substituteLink(vertex, chosenVrtxIdx, mnt,
2316 fsParams.getFragmentSpace());
2317 if (!done)
2318 mnt.increase(
2320 break;
2321
2322 case DELETELINK:
2323 done = deleteLink(vertex, chosenApId, mnt,
2324 fsParams.getFragmentSpace());
2325 if (!done)
2326 mnt.increase(
2328 break;
2329
2330 case DELETECHAIN:
2331 done = deleteChain(vertex, mnt, fsParams.getFragmentSpace());
2332 if (!done)
2333 mnt.increase(
2335 break;
2336
2337 case ADDLINK:
2338 if (chosenApId < 0)
2339 {
2340 List<Integer> candidates = new ArrayList<Integer>();
2341 for (Vertex c : vertex.getChilddren())
2342 {
2343 candidates.add(c.getEdgeToParent().getSrcAP()
2344 .getIndexInOwner());
2345 }
2346 if (candidates.size() == 0)
2347 {
2348 mnt.increase(
2350 break;
2351 }
2352 chosenApId = settings.getRandomizer().randomlyChooseOne(
2353 candidates);
2354 }
2355 done = extendLink(vertex, chosenApId, chosenVrtxIdx, mnt,
2356 fsParams.getFragmentSpace());
2357 if (!done)
2358 mnt.increase(
2360 break;
2361
2362 case ADDRING:
2363 done = addRing(vertex, mnt, false, fsParams.getFragmentSpace(),
2364 settings);
2365 if (!done)
2367 break;
2368
2369 case EXTEND:
2370 vertex.getGraphOwner().removeCappingGroupsOn(vertex);
2371 done = extendGraph(vertex, false, false, force, chosenVrtxIdx,
2372 chosenApId, settings);
2373 if (!done)
2375 break;
2376
2377 case DELETE:
2378 done = deleteFragment(vertex);
2379 if (!done)
2381 break;
2382 }
2383
2384 String msg = "Mutation '" + mType.toString() + "' on vertex "
2385 + vertex.toString() + " (position " + positionOfVertex
2386 + " in graph " + graphId+"): ";
2387 if (done)
2388 {
2389 msg = msg + "done";
2390
2391 // Triggers reconstruction of the molecular representation of
2392 // templates upon changes of the embedded graph
2393 if (graph.getTemplateJacket() != null)
2394 {
2396 }
2397 } else {
2398 msg = msg + "unsuccessful";
2399 }
2400 settings.getLogger().info(msg);
2401
2402 return done;
2403 }
2404
2405//------------------------------------------------------------------------------
2406
2407
2408
2409}
General set of constants used in DENOPTIM.
static final Object STOREDVID
Key of the property remembering vertex IDs.
An utility class to encapsulate the search for an AttachmentPoint-AttachmentPoint mapping.
APMapping getChosenAPMapping()
Returns the AttachmentPoint-AttachmentPoint mapping chosen among the possible mappings.
boolean foundMapping()
Returns true if any mapping has been found.
Class defining a space of building blocks.
boolean imposeSymmetryOnAPsOfClass(APClass apClass)
Checks if the symmetry settings impose use of symmetry on attachment points of the given AP class.
Parameters defining the fragment space.
Data structure containing information that identifies a single AP of a vertex/fragment.
Helper methods for the genetic algorithm.
Definition: EAUtils.java:93
static double getGrowthByLevelProbability(int level, GAParameters settings)
Calculates the probability of adding a fragment to the given level.
Definition: EAUtils.java:2106
static int chooseNumberOfSitesToMutate(double[] multiSiteMutationProb, double hit)
Takes a decision on how many sites to mutate on a candidate.
Definition: EAUtils.java:210
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:2129
static int getCrowdedness(AttachmentPoint ap)
Calculate the current crowdedness of the given attachment point.
Definition: EAUtils.java:2174
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:2029
Private class representing a selected closable chain of fragments.
FragForClosabChains(ArrayList< ClosableChain > compatChains, ArrayList< ClosableChain > incompatChains, ArrayList< Integer > fragIds)
Collection of operators meant to alter graphs and associated utilities.
static IdFragmentAndAP getFrgApForSrcAp(Vertex curVertex, int dapidx, FragmentSpace fragSpace)
Select a compatible fragment for the given attachment point.
static boolean performMutation(Vertex vertex, MutationType mType, boolean force, int chosenVrtxIdx, int chosenApId, Monitor mnt, GAParameters settings)
Mutates the given vertex according to the given mutation type, if possible.
static boolean extendGraph(Vertex curVrtx, boolean extend, boolean symmetryOnAps, boolean force, int chosenVrtxIdx, int chosenApId, GAParameters settings)
function that will keep extending the graph.
static boolean extendLink(Vertex vertex, int chosenAPId, Monitor mnt, FragmentSpace fragSpace)
Inserts a vertex in between two connected vertexes that are identified by the one vertex holding the ...
static List< XoverSite > locateCompatibleXOverPoints(DGraph graphA, DGraph graphB, FragmentSpace fragSpace, int maxSizeXoverSubGraph)
Identify crossover sites, i.e., subgraphs that can be swapped between two graphs (i....
static boolean applySymmetry(boolean apclassImposed, double symmetryProbability, Randomizer randomizer)
Decides whether to apply constitutional symmetry or not.
static void checkAndAddXoverSites(FragmentSpace fragSpace, List< Vertex > subGraphA, List< Vertex > subGraphB, CrossoverType xoverType, List< XoverSite > collector)
Here we check that the given subgraphs have a mapping that allows to swap them, and full fill any oth...
static boolean performMutation(Vertex vertex, MutationType mType, Monitor mnt, GAParameters settings)
Mutates the given vertex according to the given mutation type, if possible.
static boolean substituteLink(Vertex vertex, int chosenVrtxIdx, Monitor mnt, FragmentSpace fragSpace)
Substitutes a vertex while keeping its surrounding.
static boolean isCrossoverPossible(Edge eA, Edge eB, FragmentSpace fragSpace)
Evaluate AP class-compatibility of a pair of edges with respect to crossover.
static void processCombinationOfEndPoints(Vertex[] pair, List< Vertex[]> cominationOfEnds, List< XoverSite > collector, FragmentSpace fragSpace)
Given a pair of seed vertexes that define where a pair of subgraphs stars in the corresponding origin...
static boolean attachFragmentInClosableChain(Vertex curVertex, int dapidx, DGraph molGraph, ArrayList< Long > addedVertices, GAParameters settings)
static void processPermutationOfEndPoints(Vertex[] pair, List< Vertex[]> chosenSequenceOfEndpoints, List< XoverSite > collector, FragmentSpace fragSpace)
Given a pair of seed vertexes that define where a pair of subgraphs stars in the corresponding origin...
static boolean extendGraph(Vertex curVertex, boolean extend, boolean symmetryOnAps, GAParameters settings)
function that will keep extending the graph according to the growth/substitution probability.
static ArrayList< FragForClosabChains > getFragmentForClosableChain(Vertex curVertex, int dapidx, DGraph molGraph)
Method to select fragments that increase the likeliness of generating closable chains.
static boolean performMutation(Vertex vertex, Monitor mnt, GAParameters settings)
Tries to do mutate the given vertex.
static IdFragmentAndAP getFrgApForSrcAp(Vertex curVertex, int dapidx, int chosenVrtxIdx, int chosenApId, FragmentSpace fragSpace)
Select a compatible fragment for the given attachment point.
static IdFragmentAndAP getRCVForSrcAp(Vertex curVertex, int dapidx, FragmentSpace fragSpace)
Select a compatible ring-closing vertex for the given attachment point.
static boolean deleteFragment(Vertex vertex)
Deletion mutation removes the vertex and also the symmetric partners on its parent.
static boolean rebuildBranch(Vertex vertex, boolean force, int chosenVrtxIdx, int chosenApId, GAParameters settings)
Substitutes a vertex and any child branch.
static boolean deleteLink(Vertex vertex, int chosenVrtxIdx, Monitor mnt, FragmentSpace fragSpace)
Removes a vertex while merging as many of the child branches into the parent vertex.
static boolean extendLink(Vertex vertex, int chosenAPId, int chosenNewVrtxId, Monitor mnt, FragmentSpace fragSpace)
Inserts a vertex in between two connected vertexes that are identified by the one vertex holding the ...
static boolean performMutation(DGraph graph, Monitor mnt, GAParameters settings)
Tries to do mutate the given graph.
static boolean addRing(Vertex vertex, Monitor mnt, boolean force, FragmentSpace fragSpace, GAParameters settings)
Tries to use any free AP of the given vertex to close ring in the graph by adding a chord.
static boolean extendLink(Edge edge, int chosenBBIdx, Monitor mnt, FragmentSpace fragSpace)
Replace an edge with two edges with a new vertex in between, thus inserting a vertex in between two d...
static boolean deleteChain(Vertex vertex, Monitor mnt, FragmentSpace fragSpace)
Deletes the given vertex and all other vertexes that are not connected to more than 2 non-capping gro...
static boolean performCrossover(XoverSite site, FragmentSpace fragSpace)
Performs the crossover that swaps the two subgraphs defining the given XoverSite.
This class collects the data identifying the subgraphs that would be swapped by a crossover event.
Definition: XoverSite.java:36
boolean isCPMapCompatibleWith(APClass other, FragmentSpace fragSpace)
Check compatibility as defined in the compatibility matrix considering this AP as source and the othe...
Definition: APClass.java:455
boolean equals(Object o)
Definition: APClass.java:488
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....
APClass getAPClass()
Returns the Attachment Point class.
boolean isAvailable()
Check availability of this attachment point.
Edge getEdgeUserThroughout()
Gets the edge that is using this AP, or null if no edge is using this AP.
Container for the list of vertices and the edges that connect them.
Definition: DGraph.java:102
boolean removeVertexAndWeld(Vertex vertex, FragmentSpace fragSpace)
Remove a given vertex belonging to this graph and re-connects the resulting graph branches as much as...
Definition: DGraph.java:1195
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:2258
Vertex getVertexWithId(long vid)
Searches for a vertex with the given identifier.
Definition: DGraph.java:2582
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:4258
boolean isIsomorphicTo(DGraph other)
Checks if this graph is "DENOPTIM-isomorphic" to the other one given.
Definition: DGraph.java:3453
ArrayList< Ring > getRingsInvolvingVertex(Vertex v)
Returns the list of rings that include the given vertex in their fundamental cycle.
Definition: DGraph.java:826
void getChildrenTree(Vertex vertex, List< Vertex > children)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:2771
String getLocalMsg()
Definition: DGraph.java:279
void removeVertex(Vertex vertex)
Remove a vertex from this graph.
Definition: DGraph.java:1119
int indexOf(Vertex v)
Returns the index of a vertex in the list of vertices of this graph.
Definition: DGraph.java:2569
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:2514
Vertex getDeepestAmongThese(List< Vertex > list)
Identify the oldest ancestor (i.e., most great grandparent) in the given collection.
Definition: DGraph.java:3123
String getBranchIdOfVertexAsStr(Vertex v)
Returns the branch identifier as a literal string.
Definition: DGraph.java:2978
List< AttachmentPoint > getAvailableAPsThroughout()
Returns the list of attachment points contained in this graph that are available throughout the templ...
Definition: DGraph.java:4011
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:5776
List< AttachmentPoint > getInterfaceAPs(List< Vertex > subGraphB)
Searches for all AttachmentPoints that represent the interface between a subgraph,...
Definition: DGraph.java:7113
DGraph clone()
Returns almost "deep-copy" of this graph.
Definition: DGraph.java:3186
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:1680
int getLevel(Vertex v)
Calculates the level of a vertex in this graph.
Definition: DGraph.java:5326
void addSymmetricSetOfVertices(SymmetricVertexes symSet)
Adds a symmetric set of vertices to this graph.
Definition: DGraph.java:661
SymmetricVertexes getSymSetForVertex(Vertex v)
Returns the set of vertexes symmetric to the given one.
Definition: DGraph.java:633
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:7148
void addRing(Ring ring)
Definition: DGraph.java:1030
boolean hasSymmetryInvolvingVertex(Vertex v)
Definition: DGraph.java:293
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:2360
void getChildTreeLimited(Vertex vertex, List< Vertex > children, boolean stopBeforeRCVs)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:3028
boolean removeBranchStartingAt(Vertex v, boolean symmetry)
Deletes the branch, i.e., the specified vertex and its children.
Definition: DGraph.java:4788
Template getTemplateJacket()
Definition: DGraph.java:6932
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:4878
void setLocalMsg(String msg)
Definition: DGraph.java:272
boolean isIsostructuralTo(DGraph other)
Checks if this graph is "DENOPTIM-isostructural" to the other one given.
Definition: DGraph.java:3580
This class represents the edge between two vertices.
Definition: Edge.java:38
AttachmentPoint getTrgAP()
Definition: Edge.java:115
long getSrcVertex()
Definition: Edge.java:122
AttachmentPoint getSrcAP()
Definition: Edge.java:94
APClass getTrgAPClass()
Definition: Edge.java:157
APClass getSrcAPClass()
Definition: Edge.java:150
This class represents the closure of a ring in a spanning tree.
Definition: Ring.java:40
A collection of AttachmentPoints that are related by a relation that we call "symmetry",...
boolean add(T item)
Adds an item to this list, if not already present.
A collection of Vertexs that are related by a relation that we call "symmetry", even though this clas...
ContractLevel getContractLevel()
Returns the contract level of this template, i.e., to what extent the content of this template can be...
Definition: Template.java:203
void clearIAtomContainer()
Removes the molecular representation.
Definition: Template.java:600
A vertex is a data structure that has an identity and holds a list of AttachmentPoints.
Definition: Vertex.java:61
abstract Vertex clone()
Returns a deep-copy of this vertex.
int getBuildingBlockId()
Returns the index of the building block that should correspond to the position of the building block ...
Definition: Vertex.java:284
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:972
void setVertexId(long vertexId2)
Definition: Vertex.java:261
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:996
Vertex.BBType getBuildingBlockType()
Definition: Vertex.java:298
DGraph getGraphOwner()
Returns the graph this vertex belongs to or null.
Definition: Vertex.java:779
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:1085
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:382
AttachmentPoint getAP(int i)
Get attachment point i on this vertex.
Definition: Vertex.java:920
static Vertex newVertexFromLibrary(int bbId, Vertex.BBType bbt, FragmentSpace fragSpace)
Builds a new molecular fragment kind of vertex.
Definition: Vertex.java:214
ClosableChain represents a chain of fragments (chain links) that is closable (or candidate closable).
This object represents a path in a DGraph.
int getPathLength()
Returns the length of the list of edges involved in this path.
List< Vertex > getVertecesPath()
Returns the list of verteces involved.
A class for iterating over sets of ring combinations generated by considering any constrain and setti...
The RingClosingAttractor represent the available valence/connection that allows to close a ring.
static final Map< APClass, APClass > RCAAPCMAP
Recognized APClasses on RingClosingAttractor and compatible types.
Parameters and setting related to handling ring closures.
Utility methods for input/output.
static void writeGraphToSDF(File file, DGraph graph, boolean append, boolean make3D, Logger logger, Randomizer randomizer)
Writes the graph to SDF file.
A collection of counters user to count actions taken by the evolutionary algorithm.
Definition: Monitor.java:37
Tool to build build three-dimensional (3D) tree-like molecular structures from DGraph.
void setAlignBBsIn3D(boolean align)
Sets the flag that controls whether building blocks have to be aligned according to the AP vectors or...
IAtomContainer convertGraphTo3DAtomContainer(DGraph graph)
Created a three-dimensional molecular representation from a given DGraph.
RunTimeParameters getParameters(ParametersType type)
Randomizer getRandomizer()
Returns the current program-specific randomizer.
Parameters for genetic algorithm.
Utilities for graphs.
Definition: GraphUtils.java:40
static synchronized void ensureVertexIDConsistency(long l)
Method used to ensure consistency between internal atomic integer and vertex id from imported graphs.
Definition: GraphUtils.java:55
static synchronized long getUniqueVertexIndex()
Unique counter for the number of graph vertices generated.
Definition: GraphUtils.java:97
Tool to generate random numbers and random decisions.
Definition: Randomizer.java:35
boolean nextBoolean()
Returns the next pseudo-random, uniformly distributed boolean value from this random number generator...
public< T > T randomlyChooseOne(Collection< T > c)
Chooses one member among the given collection.
Enum specifying to what extent the template's inner graph can be changed.
Definition: Template.java:104
FIXED
Inner graphs are effectively equivalent to the Fragment class, as no change in the inner structure is...
Definition: Template.java:116
FIXED_STRUCT
Inner graph keep the same structure, but the identify of vertices can change.
Definition: Template.java:124
The type of building block.
Definition: Vertex.java:86
static BBType parseInt(int i)
Translates the integer into the enum.
Definition: Vertex.java:103
Identifier of a counter.
Definition: CounterID.java:29
FS_PARAMS
Parameters pertaining the definition of the fragment space.
RC_PARAMS
Parameters pertaining to ring closures in graphs.
Types of crossover defined.
SUBGRAPH
Swaps a portion of a branch trying to retain cyclicity.
BRANCH
Swaps the entire branch starting from a given vertex.
Types of mutation defined in relation to what happens to the target vertex (i.e., the actual mutation...
DELETECHAIN
Removes a vertex and all its neighbors recursively until a branching point, i.e., until a vertex that...