$darkmode
DENOPTIM
EAUtils.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.io.IOException;
24import java.nio.file.Path;
25import java.text.DecimalFormat;
26import java.text.NumberFormat;
27import java.util.ArrayList;
28import java.util.Arrays;
29import java.util.Comparator;
30import java.util.HashMap;
31import java.util.HashSet;
32import java.util.Iterator;
33import java.util.List;
34import java.util.Locale;
35import java.util.Map;
36import java.util.Set;
37import java.util.concurrent.atomic.AtomicInteger;
38import java.util.logging.Level;
39import java.util.logging.Logger;
40import java.util.stream.Collectors;
41import java.util.stream.IntStream;
42
43import org.apache.commons.io.FileUtils;
44import org.apache.commons.io.FilenameUtils;
45import org.openscience.cdk.graph.ShortestPaths;
46import org.openscience.cdk.interfaces.IAtom;
47import org.openscience.cdk.interfaces.IAtomContainer;
48import org.openscience.cdk.isomorphism.Mappings;
49import org.paukov.combinatorics3.Generator;
50
51import com.google.gson.Gson;
52
53import denoptim.constants.DENOPTIMConstants;
54import denoptim.exception.DENOPTIMException;
55import denoptim.fitness.FitnessParameters;
56import denoptim.fragmenter.BridgeHeadFindingRule;
57import denoptim.fragmenter.FragmenterTools;
58import denoptim.fragmenter.ScaffoldingPolicy;
59import denoptim.fragspace.FragmentSpace;
60import denoptim.fragspace.FragmentSpaceParameters;
61import denoptim.graph.APClass;
62import denoptim.graph.AttachmentPoint;
63import denoptim.graph.Candidate;
64import denoptim.graph.DGraph;
65import denoptim.graph.Edge.BondType;
66import denoptim.graph.EmptyVertex;
67import denoptim.graph.Fragment;
68import denoptim.graph.GraphPattern;
69import denoptim.graph.RelatedAPPair;
70import denoptim.graph.Ring;
71import denoptim.graph.SymmetricAPs;
72import denoptim.graph.SymmetricSet;
73import denoptim.graph.SymmetricSetWithMode;
74import denoptim.graph.Template;
75import denoptim.graph.Template.ContractLevel;
76import denoptim.graph.Vertex;
77import denoptim.graph.Vertex.BBType;
78import denoptim.graph.rings.CyclicGraphHandler;
79import denoptim.graph.rings.RingClosureParameters;
80import denoptim.graph.rings.RingClosuresArchive;
81import denoptim.io.DenoptimIO;
82import denoptim.json.DENOPTIMgson;
83import denoptim.logging.CounterID;
84import denoptim.logging.Monitor;
85import denoptim.molecularmodeling.ThreeDimTreeBuilder;
86import denoptim.programs.RunTimeParameters.ParametersType;
87import denoptim.programs.denovo.GAParameters;
88import denoptim.programs.fragmenter.CuttingRule;
89import denoptim.programs.fragmenter.FragmenterParameters;
90import denoptim.utils.DummyAtomHandler;
91import denoptim.utils.GeneralUtils;
92import denoptim.utils.GraphUtils;
93import denoptim.utils.ManySMARTSQuery;
94import denoptim.utils.MoleculeUtils;
95import denoptim.utils.Randomizer;
96import denoptim.utils.RotationalSpaceUtils;
97import denoptim.utils.SizeControlledSet;
98import denoptim.utils.StatUtils;
99
100
106public class EAUtils
107{
108 // cluster the fragments based on their #APs
109 protected static HashMap<Integer, ArrayList<Integer>> fragmentPool;
110
114 private static Locale enUsLocale = new Locale("en", "US");
115
119 private static DecimalFormat df = initialiseFormatter();
120 private static DecimalFormat initialiseFormatter() {
121 DecimalFormat df = (DecimalFormat) NumberFormat.getNumberInstance(
122 enUsLocale);
123 df.setGroupingUsed(false);
124 return df;
125 }
126
127 // for each fragment store the reactions associated with it
128 protected static HashMap<Integer, ArrayList<String>> lstFragmentClass;
129
133 public enum CandidateSource {
134 CROSSOVER, MUTATION, CONSTRUCTION, MANUAL;
135 }
136
137 private static final String NL =System.getProperty("line.separator");
138 private static final String FSEP = System.getProperty("file.separator");
139
140//------------------------------------------------------------------------------
141
148 protected static void createFolderForGeneration(int genId,
149 GAParameters settings)
150 {
151 denoptim.files.FileUtils.createDirectory(
152 EAUtils.getPathNameToGenerationFolder(genId, settings));
153 }
154
155//------------------------------------------------------------------------------
156
163 SizeControlledSet uniqueIDsSet, GAParameters settings)
164 throws DENOPTIMException, IOException
165 {
166 Population population = new Population(settings);
167
168 // Read existing or previously visited UIDs
169 HashSet<String> lstUID = new HashSet<>(1024);
170 if (!settings.getUIDFileIn().equals(""))
171 {
172 EAUtils.readUID(settings.getUIDFileIn(),lstUID);
173 for (String uid : lstUID)
174 {
175 uniqueIDsSet.addNewUniqueEntry(uid);
176 }
177 settings.getLogger().log(Level.INFO, "Read " + lstUID.size()
178 + " known UIDs from " + settings.getUIDFileIn());
179 }
180
181 // Read existing graphs
182 int numFromInitGraphs = 0;
183 String initPopFile = settings.getInitialPopulationFile();
184 if (initPopFile.length() > 0)
185 {
186 EAUtils.getPopulationFromFile(initPopFile, population, uniqueIDsSet,
188 settings);
189 numFromInitGraphs = population.size();
190 settings.getLogger().log(Level.INFO, "Imported " + numFromInitGraphs
191 + " candidates (as graphs) from " + initPopFile);
192 }
193
194 return population;
195 }
196
197//------------------------------------------------------------------------------
198
208 {
210 settings.getCrossoverWeight(),
211 settings.getMutationWeight(),
212 settings.getConstructionWeight(),
213 settings.getRandomizer());
214 }
215
216//------------------------------------------------------------------------------
217
224 public static int chooseNumberOfSitesToMutate(double[] multiSiteMutationProb,
225 double hit)
226 {
227 double tot = 0;
228 for (int i=0; i<multiSiteMutationProb.length; i++)
229 tot = tot + multiSiteMutationProb[i];
230
231 double scaledHit = hit * tot;
232
233 double min = 0;
234 double max = 0;
235 int choice = 0;
236 for (int i=0; i<multiSiteMutationProb.length; i++)
237 {
238 max = max + multiSiteMutationProb[i];
239 if (min < scaledHit && scaledHit <= max)
240 {
241 choice = i;
242 break;
243 }
244 min = Math.max(min,min+multiSiteMutationProb[i]);
245 }
246 return choice;
247 }
248
249//------------------------------------------------------------------------------
250
264 double xoverWeight, double mutWeight, double newWeight,
265 Randomizer randomizer)
266 {
267 double hit = randomizer.nextDouble()
268 * (xoverWeight + mutWeight + newWeight);
269 if (hit <= xoverWeight)
270 {
272 } else if (xoverWeight < hit && hit <= (mutWeight+xoverWeight))
273 {
275 } else {
277 }
278 }
279
280//------------------------------------------------------------------------------
281
293 protected static List<Candidate> buildCandidatesByXOver(
294 List<Candidate> eligibleParents, Population population,
295 Monitor mnt, GAParameters settings) throws DENOPTIMException
296 {
297 return buildCandidatesByXOver(eligibleParents, population, mnt,
298 null, -1, -1, settings, settings.maxOffsprintFromXover());
299 }
300
301//------------------------------------------------------------------------------
302
314 List<Candidate> eligibleParents, Population population,
315 Monitor mnt, GAParameters settings) throws DENOPTIMException
316 {
317 return buildCandidateByXOver(eligibleParents, population, mnt,
318 null, -1, -1, settings);
319 }
320
321//------------------------------------------------------------------------------
322
348 List<Candidate> eligibleParents, Population population,
349 Monitor mnt, int[] choiceOfParents, int choiceOfXOverSites,
350 int choiceOfOffstring, GAParameters settings)
351 throws DENOPTIMException
352 {
353 List<Candidate> cands = buildCandidatesByXOver(eligibleParents,
354 population, mnt,
355 choiceOfParents, choiceOfXOverSites, choiceOfOffstring,
356 settings, 1);
357 if (cands.size()>0)
358 return cands.get(0);
359 else
360 return null;
361 }
362
363//------------------------------------------------------------------------------
364
392 protected static List<Candidate> buildCandidatesByXOver(
393 List<Candidate> eligibleParents, Population population,
394 Monitor mnt, int[] choiceOfParents, int choiceOfXOverSites,
395 int choiceOfOffstring, GAParameters settings,
396 int maxCandidatesToReturn) throws DENOPTIMException
397 {
399 if (settings.containsParameters(ParametersType.FS_PARAMS))
400 {
401 fsParams = (FragmentSpaceParameters)settings.getParameters(
403 }
404 FragmentSpace fragSpace = fsParams.getFragmentSpace();
405
406 mnt.increase(CounterID.XOVERATTEMPTS);
407 mnt.increase(CounterID.NEWCANDIDATEATTEMPTS);
408
409 int numatt = 1;
410
411 // Identify a pair of parents that can do crossover, and a pair of
412 // vertexes from which we can define a subgraph (or a branch) to swap
413 XoverSite xos = null;
414 boolean foundPars = false;
415 while (numatt < settings.getMaxGeneticOpAttempts())
416 {
417 if (fragSpace.useAPclassBasedApproach())
418 {
419 xos = EAUtils.performFBCC(eligibleParents,
420 population, choiceOfParents, choiceOfXOverSites,
421 settings);
422 if (xos == null)
423 {
424 numatt++;
425 continue;
426 }
427 } else {
428 //TODO: make it reproducible using choiceOfParents and choiceOfXOverSites
430 eligibleParents, 2, settings);
431 if (parents[0] == null || parents[1] == null)
432 {
433 numatt++;
434 continue;
435 }
436 //NB: this does not go into templates!
437 DGraph gpA = parents[0].getGraph();
438 List<Vertex> subGraphA = new ArrayList<Vertex>();
440 gpA, settings.getRandomizer()),subGraphA);
441
442 DGraph gpB = parents[1].getGraph();
443 List<Vertex> subGraphB = new ArrayList<Vertex>();
445 gpB, settings.getRandomizer()),subGraphB);
446 }
447 foundPars = true;
448 break;
449 }
450 mnt.increaseBy(CounterID.XOVERPARENTSEARCH, numatt);
451
452 if (!foundPars)
453 {
455 mnt.increase(CounterID.FAILEDXOVERATTEMPTS);
456 return new ArrayList<Candidate>();
457 }
458
459 Candidate cA = null, cB = null;
460 Vertex vA = null, vB = null;
461 vA = xos.getA().get(0);
462 vB = xos.getB().get(0);
463 DGraph gA = vA.getGraphOwner();
465 DGraph gB = vB.getGraphOwner();
467
468 String candIdA = cA.getName();
469 String candIdB = cB.getName();
470 int gid1 = gA.getGraphId();
471 int gid2 = gB.getGraphId();
472
473 // Start building the offspring
474 XoverSite xosOnClones = xos.projectToClonedGraphs();
475 DGraph gAClone = xosOnClones.getA().get(0).getGraphOwner();
476 DGraph gBClone = xosOnClones.getB().get(0).getGraphOwner();
477
478 try
479 {
480 if (!GraphOperations.performCrossover(xosOnClones,fragSpace))
481 {
483 mnt.increase(CounterID.FAILEDXOVERATTEMPTS);
484 return new ArrayList<Candidate>();
485 }
486 } catch (Throwable t) {
487 if (!settings.xoverFailureTolerant)
488 {
489 t.printStackTrace();
490 ArrayList<DGraph> parents = new ArrayList<DGraph>();
491 parents.add(gA);
492 parents.add(gB);
493 DenoptimIO.writeGraphsToSDF(new File(settings.getDataDirectory()
494 + "_failed_xover.sdf"), parents, true,
495 settings.getLogger(), settings.getRandomizer());
496 throw new DENOPTIMException("Error while performing crossover! "+NL
497 + "XOverSite: " + xos.toString() + NL
498 + "XOverSite(C): " + xosOnClones.toString() + NL
499 + " Please, report this to the authors ",t);
500 }
502 mnt.increase(CounterID.FAILEDXOVERATTEMPTS);
503 return new ArrayList<Candidate>();
504 }
507 String lstIdVA = "";
508 for (Vertex v : xos.getA())
509 lstIdVA = lstIdVA + "_" + v.getVertexId();
510 String lstIdVB = "";
511 for (Vertex v : xos.getB())
512 lstIdVB = lstIdVB + "_" + v.getVertexId();
513 String[] msgs = new String[2];
514 msgs[0] = "Xover: "
515 + "Gen:" + cA.getGeneration() + " Cand:" + candIdA
516 + "|" + gid1 + "|" + lstIdVA
517 + " X "
518 + "Gen:" + cB.getGeneration() + " Cand:" + candIdB
519 + "|" + gid2 + "|" + lstIdVB;
520 msgs[1] = "Xover: "
521 + "Gen:" + cB.getGeneration() + " Cand:" + candIdB
522 + "|" + gid2 + "|" + lstIdVB
523 + " X "
524 + "Gen:" + cA.getGeneration() + " Cand:" + candIdA
525 + "|" + gid1 + "|" + lstIdVA;
526
527 DGraph[] graphsAffectedByXover = new DGraph[2];
528 graphsAffectedByXover[0] = gAClone;
529 graphsAffectedByXover[1] = gBClone;
530
531 List<Candidate> validOffspring = new Population(settings);
532 for (int ig=0; ig<graphsAffectedByXover.length; ig++)
533 {
534 DGraph g = graphsAffectedByXover[ig];
535
536 // It makes sense to do this on the possibly embedded graph and not
537 // on their embedding owners because there cannot be any new cycle
538 // affecting the latter, but there can be ones affecting the first.
539 if (!EAUtils.setupRings(null, g, settings))
540 {
542 continue;
543 }
544
545 // Finalize the graph that is at the outermost level
546 DGraph gOutermost = g.getOutermostGraphOwner();
547 gOutermost.addCappingGroups(fragSpace);
548 gOutermost.renumberGraphVertices();
549 gOutermost.setLocalMsg(msgs[ig]);
550
551 // Consider if the result can be used to define a new candidate
552 Object[] res = null;
553 try
554 {
555 res = gOutermost.checkConsistency(settings);
556 } catch (NullPointerException|IllegalArgumentException e)
557 {
558 if (!settings.xoverGraphFailedEvalTolerant)
559 {
560 ArrayList<DGraph> parents = new ArrayList<DGraph>();
561 parents.add(gA);
562 parents.add(gB);
563 parents.add(gAClone);
564 parents.add(gBClone);
565 DenoptimIO.writeGraphsToSDF(new File(settings.getDataDirectory()
566 + "_failed_xover-ed_check.sdf"), parents, true,
567 settings.getLogger(), settings.getRandomizer());
568 throw e;
569 } else {
570 res = null;
571 }
572 }
573 if (res != null)
574 {
575 if (!EAUtils.setupRings(res, gOutermost, settings))
576 {
578 res = null;
579 }
580 } else {
582 }
583
584 // Check if the chosen combination gives rise to forbidden ends
585 for (Vertex rcv : gOutermost.getFreeRCVertices())
586 {
587 APClass apc = rcv.getEdgeToParent().getSrcAP().getAPClass();
588 if (fragSpace.getCappingMap().get(apc)==null
589 && fragSpace.getForbiddenEndList().contains(apc))
590 {
592 res = null;
593 }
594 }
595 if (res == null)
596 {
597 mnt.increase(CounterID.FAILEDXOVERATTEMPTS);
598 gOutermost.cleanup();
599 gOutermost = null;
600 continue;
601 }
602
603 // OK: we can now use it to make a new candidate
604 Candidate offspring = new Candidate(gOutermost);
605 offspring.setUID(res[0].toString().trim());
606 offspring.setSmiles(res[1].toString().trim());
607 offspring.setChemicalRepresentation((IAtomContainer) res[2]);
608
609 validOffspring.add(offspring);
610 }
611
612 if (validOffspring.size() == 0)
613 {
614 mnt.increase(CounterID.FAILEDXOVERATTEMPTS);
615 return new ArrayList<Candidate>();
616 }
617
618 if (maxCandidatesToReturn==1)
619 {
620 Candidate chosenOffspring = null;
621 if (choiceOfOffstring<0)
622 {
623 chosenOffspring = settings.getRandomizer().randomlyChooseOne(
624 validOffspring);
625 chosenOffspring.setName("M" + GeneralUtils.getPaddedString(
628 } else {
629 chosenOffspring = validOffspring.get(choiceOfOffstring);
630 }
631 validOffspring.retainAll(Arrays.asList(chosenOffspring));
632 } else {
633 for (Candidate cand : validOffspring)
634 {
638 }
639 }
640 return validOffspring;
641 }
642
643//------------------------------------------------------------------------------
644
646 List<Candidate> eligibleParents, Monitor mnt,
647 GAParameters settings) throws DENOPTIMException
648 {
650 if (settings.containsParameters(ParametersType.FS_PARAMS))
651 {
652 fsParams = (FragmentSpaceParameters)settings.getParameters(
654 }
655 FragmentSpace fragSpace = fsParams.getFragmentSpace();
656
657 mnt.increase(CounterID.MUTATTEMPTS);
658 mnt.increase(CounterID.NEWCANDIDATEATTEMPTS);
659
660 int numatt = 0;
661 Candidate parent = null;
662 while (numatt < settings.getMaxGeneticOpAttempts())
663 {
664 parent = EAUtils.selectBasedOnFitness(eligibleParents,1, settings)[0];
665 if (parent == null)
666 {
667 numatt++;
668 continue;
669 }
670 break;
671 }
672 mnt.increaseBy(CounterID.MUTPARENTSEARCH,numatt);
673 if (parent == null)
674 {
675 mnt.increase(CounterID.FAILEDMUTATTEMTS);
676 return null;
677 }
678
679 DGraph graph = parent.getGraph().clone();
680 graph.renumberGraphVertices();
681
682 String parentMolName = FilenameUtils.getBaseName(parent.getSDFFile());
683 int parentGraphId = parent.getGraph().getGraphId();
684 graph.setLocalMsg("Mutation:"
685 + " Gen:" + parent.getGeneration() + " Cand:" + parentMolName
686 + "|" + parentGraphId);
687
688 if (!GraphOperations.performMutation(graph, mnt, settings))
689 {
691 mnt.increase(CounterID.FAILEDMUTATTEMTS);
692 return null;
693 }
694
696
697 graph.addCappingGroups(fragSpace);
698
699 Object[] res = null;
700 try
701 {
702 res = graph.checkConsistency(settings);
703 } catch (NullPointerException|IllegalArgumentException e)
704 {
705 if (!settings.mutatedGraphFailedEvalTolerant)
706 {
707 settings.getLogger().log(Level.INFO, "WRITING DEBUG FILE for "
708 + graph.getLocalMsg());
709 DenoptimIO.writeGraphToSDF(new File("debug_evalGrp_parent.sdf"),
710 parent.getGraph(),false, settings.getLogger(),
711 settings.getRandomizer());
712 DenoptimIO.writeGraphToSDF(new File("debug_evalGrp_curr.sdf"),
713 graph,false, settings.getLogger(),
714 settings.getRandomizer());
715 throw e;
716 } else {
717 res = null;
718 mnt.increase(CounterID.FAILEDMUTATTEMTS_EVAL);
719 }
720 }
721
722 if (res != null)
723 {
724 if (!EAUtils.setupRings(res,graph,settings))
725 {
726 res = null;
728 }
729 } else {
730 mnt.increase(CounterID.FAILEDMUTATTEMTS_EVAL);
731 }
732
733 // Check if the chosen combination gives rise to forbidden ends
734 //TODO this should be considered already when making the list of
735 // possible combination of rings
736 for (Vertex rcv : graph.getFreeRCVertices())
737 {
738 APClass apc = rcv.getEdgeToParent().getSrcAP().getAPClass();
739 if (fragSpace.getCappingMap().get(apc)==null
740 && fragSpace.getForbiddenEndList().contains(apc))
741 {
742 res = null;
744 }
745 }
746
747 if (res == null)
748 {
749 graph.cleanup();
750 graph = null;
751 mnt.increase(CounterID.FAILEDMUTATTEMTS);
752 return null;
753 }
754
755 Candidate offspring = new Candidate(graph);
756 offspring.setUID(res[0].toString().trim());
757 offspring.setSmiles(res[1].toString().trim());
758 offspring.setChemicalRepresentation((IAtomContainer) res[2]);
759 offspring.setName("M" + GeneralUtils.getPaddedString(
762
763 return offspring;
764 }
765
766//------------------------------------------------------------------------------
767
768 //TODO: move to IO class
769 protected static Candidate readCandidateFromFile(File srcFile, Monitor mnt,
770 GAParameters settings) throws DENOPTIMException
771 {
772 mnt.increase(CounterID.MANUALADDATTEMPTS);
773 mnt.increase(CounterID.NEWCANDIDATEATTEMPTS);
774
775 ArrayList<DGraph> graphs;
776 try
777 {
778 graphs = DenoptimIO.readDENOPTIMGraphsFromFile(srcFile);
779 } catch (Exception e)
780 {
781 e.printStackTrace();
783 String msg = "Could not read graphs from file " + srcFile
784 + ". No candidate generated!";
785 settings.getLogger().log(Level.SEVERE, msg);
786 return null;
787 }
788 if (graphs.size() == 0 || graphs.size() > 1)
789 {
791 String msg = "Found " + graphs.size() + " graphs in file " + srcFile
792 + ". I expect one and only one graph. "
793 + "No candidate generated!";
794 settings.getLogger().log(Level.SEVERE, msg);
795 return null;
796 }
797
798 DGraph graph = graphs.get(0);
799 if (graph == null)
800 {
802 String msg = "Null graph from file " + srcFile
803 + ". Expected one and only one graph. "
804 + "No candidate generated!";
805 settings.getLogger().log(Level.SEVERE, msg);
806 return null;
807 }
808 graph.setLocalMsg("MANUAL_ADD");
809
810 // We expect users to know what they ask for. Therefore, we do
811 // evaluate the graph, but in a permissive manner, meaning that
812 // several filters are disabled to permit the introduction of graphs
813 // that cannot be generated automatically.
814 Object[] res = graph.checkConsistency(settings, true);
815
816 if (res == null)
817 {
818 graph.cleanup();
821 return null;
822 }
823
824 Candidate candidate = new Candidate(graph);
825 candidate.setUID(res[0].toString().trim());
826 candidate.setSmiles(res[1].toString().trim());
827 candidate.setChemicalRepresentation((IAtomContainer) res[2]);
828
829 candidate.setName("M" + GeneralUtils.getPaddedString(
832
833 String msg = "Candidate " + candidate.getName() + " is imported from "
834 + srcFile;
835 settings.getLogger().log(Level.INFO, msg);
836
837 return candidate;
838 }
839
840//------------------------------------------------------------------------------
841
843 GAParameters settings)
844 throws DENOPTIMException
845 {
847 if (settings.containsParameters(ParametersType.FS_PARAMS))
848 {
849 fsParams = (FragmentSpaceParameters)settings.getParameters(
851 }
852 FragmentSpace fragSpace = fsParams.getFragmentSpace();
853
854 mnt.increase(CounterID.BUILDANEWATTEMPTS);
855 mnt.increase(CounterID.NEWCANDIDATEATTEMPTS);
856
857 DGraph graph = EAUtils.buildGraph(settings);
858 if (graph == null)
859 {
861 mnt.increase(CounterID.FAILEDBUILDATTEMPTS);
862 return null;
863 }
864 graph.setLocalMsg("NEW");
865
866 Object[] res = graph.checkConsistency(settings);
867
868 if (res != null)
869 {
870 if (!EAUtils.setupRings(res,graph, settings))
871 {
872 graph.cleanup();
874 mnt.increase(CounterID.FAILEDBUILDATTEMPTS);
875 return null;
876 }
877 } else {
878 graph.cleanup();
880 mnt.increase(CounterID.FAILEDBUILDATTEMPTS);
881 return null;
882 }
883
884 // Check if the chosen combination gives rise to forbidden ends
885 //TODO: this should be considered already when making the list of
886 // possible combination of rings
887 for (Vertex rcv : graph.getFreeRCVertices())
888 {
889 // Also exclude any RCV that is not bound to anything?
890 if (rcv.getEdgeToParent() == null)
891 {
892 res = null;
894 }
895 if (rcv.getEdgeToParent() == null)
896 {
897 // RCV as scaffold! Ignore special case
898 continue;
899 }
900 APClass apc = rcv.getEdgeToParent().getSrcAP().getAPClass();
901 if (fragSpace.getCappingMap().get(apc)==null
902 && fragSpace.getForbiddenEndList().contains(apc))
903 {
904 res = null;
906 }
907 }
908
909 if (res == null)
910 {
911 graph.cleanup();
912 mnt.increase(CounterID.FAILEDBUILDATTEMPTS);
913 return null;
914 }
915
916 Candidate candidate = new Candidate(graph);
917 candidate.setUID(res[0].toString().trim());
918 candidate.setSmiles(res[1].toString().trim());
919 candidate.setChemicalRepresentation((IAtomContainer) res[2]);
920
921 candidate.setName("M" + GeneralUtils.getPaddedString(
924
925 return candidate;
926 }
927
928//------------------------------------------------------------------------------
929
943 public static Candidate buildCandidateByFragmentingMolecule(IAtomContainer mol,
944 Monitor mnt, GAParameters settings, int index) throws DENOPTIMException
945 {
947 if (settings.containsParameters(ParametersType.FS_PARAMS))
948 {
949 fsParams = (FragmentSpaceParameters) settings.getParameters(
951 }
952 FragmentSpace fragSpace = fsParams.getFragmentSpace();
953
955 if (settings.containsParameters(ParametersType.FRG_PARAMS))
956 {
957 frgParams = (FragmenterParameters) settings.getParameters(
959 }
960
961 if (frgParams.getCuttingRules()==null
962 || frgParams.getCuttingRules().isEmpty())
963 {
964 throw new DENOPTIMException("Request to generate candidates by "
965 + "fragmentation but no cutting rules provided. Please,"
966 + "add FRG-CUTTINGRULESFILE=path/to/your/file to the "
967 + "input.");
968 }
969 mnt.increase(CounterID.CONVERTBYFRAGATTEMPTS);
970 mnt.increase(CounterID.NEWCANDIDATEATTEMPTS);
971
972 // Adjust molecular representation to our settings
973 if (!FragmenterTools.prepareMolToFragmentation(mol, frgParams, index))
974 return null;
975
976 // Do actual fragmentation
977 DGraph graph = null;
978 try {
980 frgParams.getCuttingRules(), settings.getLogger(),
981 frgParams.getScaffoldingPolicy(),
982 frgParams.getLinearAngleLimit(),
983 fragSpace);
984 } catch (DENOPTIMException de)
985 {
986 String msg = "Unable to convert molecule (" + mol.getAtomCount()
987 + " atoms) to DENPTIM graph. " + de.getMessage();
988 settings.getLogger().log(Level.WARNING, msg);
989 }
990 if (graph == null)
991 {
994 return null;
995 }
996
997 if (frgParams.embedRingsInTemplate())
998 {
999 try {
1001 fragSpace, frgParams.getEmbeddedRingsContract());
1002 } catch (DENOPTIMException e) {
1003 graph.cleanup();
1005 return null;
1006 }
1007 }
1008
1009 graph.setLocalMsg("INITIAL_MOL_FRAGMENTED");
1010
1011 Object[] res = graph.checkConsistency(settings);
1012 if (res == null)
1013 {
1014 graph.cleanup();
1016 return null;
1017 }
1018
1019 Candidate candidate = new Candidate(graph);
1020 candidate.setUID(res[0].toString().trim());
1021 candidate.setSmiles(res[1].toString().trim());
1022 candidate.setChemicalRepresentation((IAtomContainer) res[2]);
1023
1024 candidate.setName("M" + GeneralUtils.getPaddedString(
1027
1028 return candidate;
1029 }
1030
1031//------------------------------------------------------------------------------
1032
1044 public static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol,
1045 List<CuttingRule> cuttingRules, Logger logger,
1046 ScaffoldingPolicy scaffoldingPolicy)
1047 throws DENOPTIMException
1048 {
1049 return makeGraphFromFragmentationOfMol(mol, cuttingRules, logger,
1050 scaffoldingPolicy, 190, new FragmentSpace());
1051 // NB: and angle of 190 means we are not adding Du on linearities
1052 // because the max possible bond angle is 180.
1053 }
1054
1055//------------------------------------------------------------------------------
1056
1070 public static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol,
1071 List<CuttingRule> cuttingRules, Logger logger,
1072 ScaffoldingPolicy scaffoldingPolicy, double linearAngleLimit)
1073 throws DENOPTIMException
1074 {
1075 return makeGraphFromFragmentationOfMol(mol, cuttingRules, logger,
1076 scaffoldingPolicy, linearAngleLimit, new FragmentSpace());
1077 }
1078
1079//------------------------------------------------------------------------------
1080
1094 public static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol,
1095 List<CuttingRule> cuttingRules, Logger logger,
1096 ScaffoldingPolicy scaffoldingPolicy, FragmentSpace fragSpace)
1097 throws DENOPTIMException
1098 {
1099 return makeGraphFromFragmentationOfMol(mol, cuttingRules, logger,
1100 scaffoldingPolicy, 190, fragSpace);
1101 // NB: and angle of 190 means we are not adding Du on linearities
1102 // because the max possible bond angle is 180.
1103 }
1104
1105//------------------------------------------------------------------------------
1106
1122 public static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol,
1123 List<CuttingRule> cuttingRules, Logger logger,
1124 ScaffoldingPolicy scaffoldingPolicy, double linearAngleLimit,
1125 FragmentSpace fragSpace)
1126 throws DENOPTIMException
1127 {
1128 // We expect only Fragments here.
1129 List<Vertex> fragments = FragmenterTools.fragmentation(mol,
1130 cuttingRules, logger);
1131 for (Vertex v : fragments)
1132 {
1133 Fragment frag = (Fragment) v;
1134
1135 // This is done to set the symmetry relations in each vertex
1136 frag.updateAPs();
1137
1138 // Add linearity-breaking dummy atoms
1139 DummyAtomHandler.addDummiesOnLinearities(frag, linearAngleLimit);
1140 }
1141 if (fragments.size()==0)
1142 {
1143 throw new DENOPTIMException("Fragmentation of molecule with "
1144 + mol.getAtomCount() + " atoms produced 0 fragments.");
1145 }
1146
1147 // Define which fragment is the scaffold
1148 Vertex scaffold = null;
1149 switch (scaffoldingPolicy)
1150 {
1151 case ELEMENT:
1152 {
1153 for (Vertex v : fragments)
1154 {
1155 if (v instanceof Fragment)
1156 {
1157 boolean setAsScaffold = false;
1158 IAtomContainer iac = v.getIAtomContainer();
1159 for (IAtom atm : iac.atoms())
1160 {
1161 if (scaffoldingPolicy.label.equals(
1163 {
1164 setAsScaffold = true;
1165 break;
1166 }
1167 }
1168 if (setAsScaffold)
1169 {
1170 scaffold = v;
1171 break;
1172 }
1173 }
1174 }
1175 break;
1176 }
1177
1178 default:
1179 case LARGEST_FRAGMENT:
1180 {
1181 try {
1182 scaffold = fragments.stream()
1183 .max(Comparator.comparing(
1185 .get();
1186 } catch (Exception e)
1187 {
1188 throw new DENOPTIMException("Cannot get largest fragment "
1189 + "among " + fragments.size() + " fragments.", e);
1190 }
1191 break;
1192 }
1193 }
1194 if (scaffold==null)
1195 {
1196 throw new DENOPTIMException("No fragment matches criteria to be "
1197 + "identified as the "
1198 + BBType.SCAFFOLD.toString().toLowerCase() + ".");
1199 }
1200 scaffold.setVertexId(0);
1202
1203 // Build the graph
1204 DGraph graph = new DGraph();
1205 graph.addVertex(scaffold);
1206 AtomicInteger vId = new AtomicInteger(1);
1207 for (int i=1; i<fragments.size(); i++)
1208 {
1209 appendVertexesToGraphFollowingEdges(graph, vId, fragments);
1210 }
1211
1212 // Set symmetry relations: these depend on which scaffold we have chosen
1213 graph.detectSymVertexSets();
1214
1215 // Identify capping groups, i.e., fragments that reflect the capping
1216 // groups found in the fragment space, if any.
1217 if (fragSpace!=null && fragSpace.getCappingMap()!=null)
1218 {
1219 for (Vertex v : graph.getVertexList())
1220 {
1221 if (v.getAttachmentPoints().size()!=1 || v.isRCV())
1222 continue;
1223
1224 APClass srcAPC = v.getAP(0).getLinkedAPThroughout().getAPClass();
1225 APClass capAPC = fragSpace.getAPClassOfCappingVertex(srcAPC);
1226 Vertex cap = fragSpace.getCappingVertexWithAPClass(capAPC);
1227 if (cap==null)
1228 continue;
1229
1230 if (!(v instanceof Fragment && cap instanceof Fragment))
1231 continue;
1232
1233 Fragment f = (Fragment) v;
1234 // NB: here we ignore APClasses and Du atoms
1235 if (f.isIsomorphicTo(cap, true))
1236 {
1238 v.getAP(0).setAPClass(capAPC);
1239 }
1240 }
1241 }
1242
1243 return graph;
1244 }
1245
1246//------------------------------------------------------------------------------
1247
1249 AtomicInteger vId, List<Vertex> vertexes) throws DENOPTIMException
1250 {
1251 // We seek for the last and non-RCV vertex added to the graph
1252 Vertex lastlyAdded = null;
1253 for (int i=-1; i>-4; i--)
1254 {
1255 lastlyAdded = graph.getVertexList().get(
1256 graph.getVertexList().size()+i);
1257 if (!lastlyAdded.isRCV())
1258 break;
1259 }
1260 for (AttachmentPoint apI : lastlyAdded.getAttachmentPoints())
1261 {
1262 if (!apI.isAvailable())
1263 continue;
1264
1265 for (int j=0; j<vertexes.size(); j++)
1266 {
1267 Vertex fragJ = vertexes.get(j);
1268
1269 boolean ringClosure = false;
1270 if (graph.containsVertex(fragJ))
1271 {
1272 ringClosure = true;
1273 }
1274 for (AttachmentPoint apJ : fragJ.getAttachmentPoints())
1275 {
1276 if (apI==apJ)
1277 continue;
1278
1279 if (apI.getCutId()==apJ.getCutId())
1280 {
1281 if (ringClosure)
1282 {
1285 BondType.ANY));
1287 rcvI.setVertexId(vId.getAndIncrement());
1288 graph.appendVertexOnAP(apI, rcvI.getAP(0));
1289
1293 rcvJ.setVertexId(vId.getAndIncrement());
1294 graph.appendVertexOnAP(apJ, rcvJ.getAP(0));
1295 graph.addRing(rcvI, rcvJ);
1296 } else {
1298 fragJ.setVertexId(vId.getAndIncrement());
1299 graph.appendVertexOnAP(apI, apJ);
1300
1301 // Recursion into the branch of the graph that is
1302 // rooted onto the lastly added vertex
1304 vertexes);
1305 }
1306 }
1307 }
1308 }
1309 }
1310 }
1311
1312//------------------------------------------------------------------------------
1313
1324 public static void outputPopulationDetails(Population population,
1325 String filename, GAParameters settings, boolean printpathNames)
1326 throws DENOPTIMException
1327 {
1328 StringBuilder sb = new StringBuilder(512);
1330 sb.append(NL);
1331
1332 df.setMaximumFractionDigits(settings.getPrecisionLevel());
1333 df.setMinimumFractionDigits(settings.getPrecisionLevel());
1334
1335 // NB: we consider the configured size of the population, not the actual
1336 // size of list representing the population.
1337 String stats = "";
1338 synchronized (population)
1339 {
1340 List<Candidate> popMembers = new ArrayList<Candidate>();
1341 for (int i=0; i<settings.getPopulationSize(); i++)
1342 {
1343 Candidate mol = population.get(i);
1344 popMembers.add(mol);
1345 if (mol != null)
1346 {
1347 String mname = new File(mol.getSDFFile()).getName();
1348 if (mname != null)
1349 sb.append(String.format("%-20s", mname));
1350
1351 sb.append(String.format("%-20s",
1352 mol.getGraph().getGraphId()));
1353 sb.append(String.format("%-30s", mol.getUID()));
1354 sb.append(df.format(mol.getFitness()));
1355
1356 if (printpathNames)
1357 {
1358 sb.append(" ").append(mol.getSDFFile());
1359 }
1360
1361 sb.append(System.getProperty("line.separator"));
1362 }
1363 }
1364
1365 // calculate descriptive statistics for the population
1366 stats = getSummaryStatistics(population, settings);
1367
1368 if (settings.savePopFile())
1369 {
1370 File dest = new File(filename.replaceAll("\\.txt$", ".sdf"));
1371 DenoptimIO.writeCandidatesToFile(dest, popMembers, false);
1372 }
1373 }
1374 if (stats.trim().length() > 0)
1375 sb.append(stats);
1376 DenoptimIO.writeData(filename, sb.toString(), false);
1377
1378 sb.setLength(0);
1379 }
1380
1381//------------------------------------------------------------------------------
1382
1383 private static String getSummaryStatistics(Population popln,
1384 GAParameters settings)
1385 {
1386 double[] fitness = getFitnesses(popln);
1387 double sdev = StatUtils.stddev(fitness, true);
1388 String res = "";
1389 df.setMaximumFractionDigits(settings.getPrecisionLevel());
1390
1391 StringBuilder sb = new StringBuilder(128);
1392 sb.append(NL+NL+"#####POPULATION SUMMARY#####"+NL);
1393 int n = popln.size();
1394 sb.append(String.format("%-30s", "SIZE:"));
1395 sb.append(String.format("%12s", n));
1396 sb.append(NL);
1397 double f;
1398 f = StatUtils.max(fitness);
1399 sb.append(String.format("%-30s", "MAX:")).append(df.format(f));
1400 sb.append(NL);
1401 f = StatUtils.min(fitness);
1402 sb.append(String.format("%-30s", "MIN:")).append(df.format(f));
1403 sb.append(NL);
1404 f = StatUtils.mean(fitness);
1405 sb.append(String.format("%-30s", "MEAN:")).append(df.format(f));
1406 sb.append(NL);
1407 f = StatUtils.median(fitness);
1408 sb.append(String.format("%-30s", "MEDIAN:")).append(df.format(f));
1409 sb.append(NL);
1410 f = StatUtils.stddev(fitness, true);
1411 sb.append(String.format("%-30s", "STDDEV:")).append(df.format(f));
1412 sb.append(NL);
1413 if (sdev > 0.0001)
1414 {
1415 f = StatUtils.skewness(fitness, true);
1416 sb.append(String.format("%-30s", "SKEW:")).append(df.format(f));
1417 sb.append(NL);
1418 } else {
1419 sb.append(String.format("%-30s", "SKEW:")).append(" NaN (sdev too small)");
1420 sb.append(NL);
1421 }
1422
1423 res = sb.toString();
1424 sb.setLength(0);
1425
1426 return res;
1427 }
1428
1429//------------------------------------------------------------------------------
1430
1441 List<Candidate> eligibleParents, int number, GAParameters settings)
1442 {
1443 Candidate[] mates = new Candidate[number];
1444 switch (settings.getSelectionStrategyType())
1445 {
1446 case 1:
1447 mates = SelectionHelper.performTournamentSelection(eligibleParents,
1448 number, settings);
1449 break;
1450 case 2:
1451 mates = SelectionHelper.performRWS(eligibleParents, number, settings);
1452 break;
1453 case 3:
1454 mates = SelectionHelper.performSUS(eligibleParents, number, settings);
1455 break;
1456 case 4:
1457 mates = SelectionHelper.performRandomSelection(eligibleParents, number,
1458 settings);
1459 break;
1460 }
1461
1462 if (settings.recordMateSelection())
1463 {
1464 String matesStr="";
1465 for (int i=0; i < mates.length; i++)
1466 {
1467 if (i>0)
1468 matesStr = matesStr + settings.NL;
1469 matesStr = matesStr + mates[i].getUID();
1470 }
1471 try
1472 {
1473 DenoptimIO.writeData(settings.getMonitorFile()+".mates",
1474 matesStr, true);
1475 } catch (DENOPTIMException e)
1476 {
1477 // TODO Auto-generated catch block
1478 e.printStackTrace();
1479 }
1480 }
1481
1482 return mates;
1483 }
1484
1485//------------------------------------------------------------------------------
1486
1491 Randomizer randomizer)
1492 {
1493 List<Vertex> candidates = new ArrayList<Vertex>(
1494 g.getVertexList());
1495 candidates.removeIf(v ->
1496 v.getBuildingBlockType() == BBType.SCAFFOLD
1497 || v.getBuildingBlockType() == BBType.CAP);
1498 return randomizer.randomlyChooseOne(candidates);
1499 }
1500
1501//------------------------------------------------------------------------------
1502
1518 protected static XoverSite performFBCC(
1519 List<Candidate> eligibleParents, Population population,
1520 int[] choiceOfParents, int choiceOfXOverSites, GAParameters settings)
1521 {
1522 Candidate parentA = null;
1523 if (choiceOfParents==null)
1524 parentA = selectBasedOnFitness(eligibleParents, 1, settings)[0];
1525 else
1526 parentA = eligibleParents.get(choiceOfParents[0]);
1527
1528 if (parentA == null)
1529 return null;
1530
1533 {
1534 fsParams = (FragmentSpaceParameters)settings.getParameters(
1536 }
1537 FragmentSpace fragSpace = fsParams.getFragmentSpace();
1538 List<Candidate> matesCompatibleWithFirst = population.getXoverPartners(
1539 parentA, eligibleParents, fragSpace);
1540 if (matesCompatibleWithFirst.size() == 0)
1541 return null;
1542
1543 Candidate parentB = null;
1544 if (choiceOfParents==null)
1545 {
1546 parentB = selectBasedOnFitness(matesCompatibleWithFirst, 1,
1547 settings)[0];
1548 } else {
1549 parentB = eligibleParents.get(choiceOfParents[1]);
1550 }
1551 if (parentB == null)
1552 return null;
1553
1554 XoverSite result = null;
1555 if (choiceOfXOverSites<0)
1556 {
1557 result = settings.getRandomizer().randomlyChooseOne(
1558 population.getXoverSites(parentA, parentB));
1559 } else {
1560 result = population.getXoverSites(parentA, parentB).get(
1561 choiceOfXOverSites);
1562 }
1563 return result;
1564 }
1565
1566//------------------------------------------------------------------------------
1567
1568 public static String getPathNameToGenerationFolder(int genID,
1569 GAParameters settings)
1570 {
1571 StringBuilder sb = new StringBuilder(32);
1572
1573 int ndigits = String.valueOf(settings.getNumberOfGenerations()).length();
1574
1575 sb.append(settings.getDataDirectory()).append(FSEP).append(
1577 .append(GeneralUtils.getPaddedString(ndigits, genID));
1578
1579 return sb.toString();
1580 }
1581
1582//------------------------------------------------------------------------------
1583
1584 public static String getPathNameToGenerationDetailsFile(int genID,
1585 GAParameters settings)
1586 {
1587 StringBuilder sb = new StringBuilder(32);
1588
1589 int ndigits = String.valueOf(settings.getNumberOfGenerations()).length();
1590
1591 sb.append(settings.getDataDirectory()).append(FSEP)
1593 .append(GeneralUtils.getPaddedString(ndigits, genID))
1594 .append(FSEP)
1596 .append(GeneralUtils.getPaddedString(ndigits, genID))
1597 .append(".txt");
1598
1599 return sb.toString();
1600 }
1601
1602//------------------------------------------------------------------------------
1603
1605 {
1606 StringBuilder sb = new StringBuilder(32);
1607 sb.append(settings.getDataDirectory()).append(FSEP).append("Final");
1608 return sb.toString();
1609 }
1610
1611//------------------------------------------------------------------------------
1612
1614 GAParameters settings)
1615 {
1616 StringBuilder sb = new StringBuilder(32);
1617 sb.append(settings.getDataDirectory()).append(FSEP).append("Final")
1618 .append(FSEP).append("Final.txt");
1619 return sb.toString();
1620 }
1621
1622//------------------------------------------------------------------------------
1623
1634 protected static void outputFinalResults(Population popln,
1635 GAParameters settings) throws DENOPTIMException
1636 {
1637 String dirName = EAUtils.getPathNameToFinalPopulationFolder(settings);
1638 denoptim.files.FileUtils.createDirectory(dirName);
1639 File fileDir = new File(dirName);
1640
1641 boolean intermediateCandidatesAreOnDisk =
1642 ((FitnessParameters) settings.getParameters(
1643 ParametersType.FIT_PARAMS)).writeCandidatesOnDisk();
1644
1645 for (int i=0; i<popln.size(); i++)
1646 {
1647 Candidate c = popln.get(i);
1648 String sdfile = c.getSDFFile();
1649 String imgfile = c.getImageFile();
1650
1651 try {
1652 if (intermediateCandidatesAreOnDisk && sdfile!=null)
1653 {
1654 FileUtils.copyFileToDirectory(new File(sdfile), fileDir);
1655 } else {
1656 File candFile = new File(fileDir, c.getName()
1658 c.setSDFFile(candFile.getAbsolutePath());
1659 DenoptimIO.writeCandidateToFile(candFile, c, false);
1660 }
1661 } catch (IOException ioe) {
1662 throw new DENOPTIMException("Failed to copy file '"
1663 + sdfile + "' to '" + fileDir + "' for candidate "
1664 + c.getName(), ioe);
1665 }
1666 if (imgfile != null && intermediateCandidatesAreOnDisk)
1667 {
1668 try {
1669 FileUtils.copyFileToDirectory(new File(imgfile), fileDir);
1670 } catch (IOException ioe) {
1671 throw new DENOPTIMException("Failed to copy file '"
1672 + imgfile + "' to '" + fileDir + "' for candidate "
1673 + c.getName(), ioe);
1674 }
1675 }
1676 }
1679 settings, true);
1680 }
1681
1682//------------------------------------------------------------------------------
1683
1692 protected static void getPopulationFromFile(String filename,
1693 Population population, SizeControlledSet uniqueIDsSet,
1694 String genDir, GAParameters settings)
1695 throws DENOPTIMException, IOException
1696 {
1697 List<Candidate> candidates = DenoptimIO.readCandidates(
1698 new File(filename), true);
1699 if (candidates.size() == 0)
1700 {
1701 String msg = "Found 0 candidates in file " + filename;
1702 settings.getLogger().log(Level.SEVERE, msg);
1703 throw new DENOPTIMException(msg);
1704 }
1705
1706 for (Candidate candidate : candidates)
1707 {
1708 if (uniqueIDsSet.addNewUniqueEntry(candidate.getUID()))
1709 {
1711 int gctr = GraphUtils.getUniqueGraphIndex();
1712
1713 String molName = "M" + GeneralUtils.getPaddedString(8, ctr);
1714 candidate.setName(molName);
1715 candidate.getGraph().setGraphId(gctr);
1716 candidate.getGraph().setLocalMsg("INITIAL_POPULATION");
1717 String sdfPathName = genDir + System.getProperty("file.separator")
1719 candidate.setSDFFile(sdfPathName);
1720 candidate.setImageFile(null);
1721
1722 // Write the candidate to file as if it had been processed by fitness provider
1723 DenoptimIO.writeCandidateToFile(new File(sdfPathName),
1724 candidate, false);
1725
1726 population.add(candidate);
1727 } else {
1728 settings.getLogger().log(Level.WARNING, "Candidate from intial "
1729 + "population file '" + filename
1730 + "' is rejected because its identifier is "
1731 + "already listed among the previously visited "
1732 + "identifiers.");
1733 }
1734 }
1735
1736 if (population.isEmpty())
1737 {
1738 String msg = "Population is still empty after having processes "
1739 + candidates.size() + " candidates from file " + filename;
1740 settings.getLogger().log(Level.SEVERE, msg);
1741 throw new DENOPTIMException(msg);
1742 }
1743
1744 setVertexCounterValue(population);
1745 }
1746
1747//------------------------------------------------------------------------------
1748
1749 protected static void writeUID(String outfile, HashSet<String> lstInchi,
1750 boolean append) throws DENOPTIMException
1751 {
1752 StringBuilder sb = new StringBuilder(256);
1753 Iterator<String> iter = lstInchi.iterator();
1754
1755 boolean first = true;
1756 while(iter.hasNext())
1757 {
1758 if (first)
1759 {
1760 sb.append(iter.next());
1761 first = false;
1762 }
1763 else
1764 {
1765 sb.append(NL).append(iter.next());
1766 }
1767 }
1768
1769 DenoptimIO.writeData(outfile, sb.toString(), append);
1770 sb.setLength(0);
1771 }
1772
1773//------------------------------------------------------------------------------
1774
1782 protected static void setVertexCounterValue(Population population)
1783 throws DENOPTIMException
1784 {
1785 long val = Long.MIN_VALUE;
1786 for (Candidate popln1 : population)
1787 {
1788 DGraph g = popln1.getGraph();
1789 val = Math.max(val, g.getMaxVertexId());
1790 }
1792 }
1793
1794//------------------------------------------------------------------------------
1795
1803 protected static DGraph buildGraph(GAParameters settings)
1804 throws DENOPTIMException
1805 {
1807 if (settings.containsParameters(ParametersType.FS_PARAMS))
1808 {
1809 fsParams = (FragmentSpaceParameters)settings.getParameters(
1811 }
1812 FragmentSpace fragSpace = fsParams.getFragmentSpace();
1813
1814 DGraph graph = new DGraph();
1816
1817 // building a molecule starts by selecting a random scaffold
1818 Vertex scafVertex = fragSpace.makeRandomScaffold();
1819
1820 // add the scaffold as a vertex
1821 graph.addVertex(scafVertex);
1822 graph.setLocalMsg("NEW");
1823
1824 if (scafVertex instanceof Template
1825 && !((Template) scafVertex).getContractLevel().equals(
1827 {
1828 Monitor mnt = new Monitor();
1829 mnt.name = "IntraTemplateBuild";
1830 List<Vertex> initialMutableSites = graph.getMutableSites(
1831 settings.getExcludedMutationTypes());
1832 for (Vertex mutableSite : initialMutableSites)
1833 {
1834 // This accounts for the possibility that a mutation changes a
1835 // branch of the initial graph or deletes vertexes.
1836 if (!graph.containsOrEmbedsVertex(mutableSite))
1837 continue;
1838
1839 // TODO: need to discriminate between EmptyVertexes that
1840 // represent placeholders and those that represent property carriers
1841 // The first should always be mutated (as it happens now), but
1842 // the latter should be kept intact.
1843 // Possibly this is a case for subclassing the EmptyVertex.
1844
1845 if (!GraphOperations.performMutation(mutableSite, mnt,
1846 settings))
1847 {
1850 return null;
1851 }
1852 }
1853 }
1854
1855 // get settings //TODO: this should happen inside RunTimeParameters
1857 if (settings.containsParameters(ParametersType.RC_PARAMS))
1858 {
1859 rcParams = (RingClosureParameters)settings.getParameters(
1861 }
1862//TODO this works only for scaffolds at the moment. make the preference for
1863// fragments that lead to known closable chains operate also when fragments are
1864// the "turning point".
1867 scafVertex.getBuildingBlockId()));
1868
1869 if (scafVertex.hasFreeAP())
1870 {
1871 GraphOperations.extendGraph(scafVertex, true, false, settings);
1872 }
1873
1874 if (!(scafVertex instanceof Template)
1875 && graph.getVertexCount() == 0)
1876 {
1877 return null;
1878 }
1879
1880 graph.addCappingGroups(fragSpace);
1881 return graph;
1882 }
1883
1884//------------------------------------------------------------------------------
1885
1898 protected static boolean setupRings(Object[] res, DGraph molGraph,
1899 GAParameters settings) throws DENOPTIMException
1900 {
1901 // get settings //TODO: this should happen inside RunTimeParameters
1903 if (settings.containsParameters(ParametersType.RC_PARAMS))
1904 {
1905 rcParams = (RingClosureParameters)settings.getParameters(
1907 }
1909 if (settings.containsParameters(ParametersType.FS_PARAMS))
1910 {
1911 fsParams = (FragmentSpaceParameters)settings.getParameters(
1913 }
1914 FragmentSpace fragSpace = fsParams.getFragmentSpace();
1915
1916 if (!fragSpace.useAPclassBasedApproach())
1917 return true;
1918
1919 if (!rcParams.allowRingClosures())
1920 return true;
1921
1922 // get a atoms/bonds molecular representation (no 3D needed)
1923 ThreeDimTreeBuilder t3d = new ThreeDimTreeBuilder(settings.getLogger(),
1924 settings.getRandomizer());
1925 t3d.setAlignBBsIn3D(false);
1926 IAtomContainer mol = t3d.convertGraphTo3DAtomContainer(molGraph,true);
1927
1928 // Set rotatability property as property of IBond
1929 String rotoSpaceFile = "";
1930 if (settings.containsParameters(ParametersType.FS_PARAMS))
1931 {
1932 rotoSpaceFile = ((FragmentSpaceParameters) settings.getParameters(
1933 ParametersType.FS_PARAMS)).getRotSpaceDefFile();
1934 }
1935 RotationalSpaceUtils.defineRotatableBonds(mol, rotoSpaceFile, true,
1936 true, settings.getLogger());
1937
1938 // get the set of possible RCA combinations = ring closures
1939 CyclicGraphHandler cgh = new CyclicGraphHandler(rcParams,fragSpace);
1940
1941 //TODO: remove hard-coded variable that exclude considering all
1942 // combination of rings
1943 boolean onlyRandomCombOfRings = true;
1944
1945 if (onlyRandomCombOfRings)
1946 {
1947 List<Ring> combsOfRings = cgh.getRandomCombinationOfRings(
1948 mol, molGraph, rcParams.getMaxRingClosures());
1949 if (combsOfRings.size() > 0)
1950 {
1951 for (Ring ring : combsOfRings)
1952 {
1953 // Consider the crowding probability
1954 double shot = settings.getRandomizer().nextDouble();
1955 int crowdOnH = EAUtils.getCrowdedness(
1956 ring.getHeadVertex().getEdgeToParent().getSrcAP(),
1957 true);
1958 int crowdOnT = EAUtils.getCrowdedness(
1959 ring.getTailVertex().getEdgeToParent().getSrcAP(),
1960 true);
1961 double crowdProbH = EAUtils.getCrowdingProbability(crowdOnH,
1962 settings);
1963 double crowdProbT = EAUtils.getCrowdingProbability(crowdOnT,
1964 settings);
1965
1966 if (shot < crowdProbH && shot < crowdProbT)
1967 {
1968 molGraph.addRing(ring);
1969 }
1970 }
1971 }
1972 }
1973 else
1974 {
1975 ArrayList<List<Ring>> allCombsOfRings =
1976 cgh.getPossibleCombinationOfRings(mol, molGraph);
1977
1978 // Keep closable chains that are relevant for chelate formation
1979 if (rcParams.buildChelatesMode())
1980 {
1981 ArrayList<List<Ring>> toRemove = new ArrayList<>();
1982 for (List<Ring> setRings : allCombsOfRings)
1983 {
1984 if (!cgh.checkChelatesGraph(molGraph,setRings))
1985 {
1986 toRemove.add(setRings);
1987 }
1988 }
1989
1990 allCombsOfRings.removeAll(toRemove);
1991 if (allCombsOfRings.isEmpty())
1992 {
1993 String msg = "Setup Rings: no combination of rings.";
1994 settings.getLogger().log(Level.INFO, msg);
1995 return false;
1996 }
1997 }
1998
1999 // Select a combination, if any still available
2000 int sz = allCombsOfRings.size();
2001 if (sz > 0)
2002 {
2003 List<Ring> selected = new ArrayList<>();
2004 if (sz == 1)
2005 {
2006 selected = allCombsOfRings.get(0);
2007 }
2008 else
2009 {
2010 int selId = settings.getRandomizer().nextInt(sz);
2011 selected = allCombsOfRings.get(selId);
2012 }
2013
2014 // append new rings to existing list of rings in graph
2015 for (Ring ring : selected)
2016 {
2017 molGraph.addRing(ring);
2018 }
2019 }
2020 }
2021
2022 // Update the IAtomContainer representation
2023 //DENOPTIMMoleculeUtils.removeUsedRCA(mol,molGraph);
2024 // Done already at t3d.convertGraphTo3DAtomContainer
2025 if (res!=null)
2026 {
2027 res[2] = mol;
2028 }
2029 // Update the SMILES representation
2030 if (res!=null)
2031 {
2032 String molsmiles = MoleculeUtils.getSMILESForMolecule(mol,
2033 settings.getLogger());
2034 if (molsmiles == null)
2035 {
2036 String msg = "Evaluation of graph: SMILES is null! "
2037 + molGraph.toString();
2038 settings.getLogger().log(Level.INFO, msg);
2039 molsmiles = "FAIL: NO SMILES GENERATED";
2040 }
2041 res[1] = molsmiles;
2042 }
2043
2044 // Update the INCHI key representation
2045 if (res!=null)
2046 {
2047 String inchikey = MoleculeUtils.getInChIKeyForMolecule(mol,
2048 settings.getLogger());
2049 if (inchikey == null)
2050 {
2051 String msg = "Evaluation of graph: INCHI is null!";
2052 settings.getLogger().log(Level.INFO, msg);
2053 inchikey = "UNDEFINED";
2054 }
2055 res[0] = inchikey;
2056 }
2057
2058 return true;
2059 }
2060
2061//------------------------------------------------------------------------------
2062
2070 protected static boolean containsMolecule(Population mols, String molcode)
2071 {
2072 if(mols.isEmpty())
2073 return false;
2074
2075 for (Candidate mol : mols)
2076 {
2077 if (mol.getUID().compareToIgnoreCase(molcode) == 0)
2078 {
2079 return true;
2080 }
2081 }
2082 return false;
2083 }
2084
2085//------------------------------------------------------------------------------
2086
2093 protected static double[] getFitnesses(Population mols)
2094 {
2095 int k = mols.size();
2096 double[] arr = new double[k];
2097
2098 for (int i=0; i<k; i++)
2099 {
2100 arr[i] = mols.get(i).getFitness();
2101 }
2102 return arr;
2103 }
2104
2105//------------------------------------------------------------------------------
2106
2114 protected static double getPopulationSD(Population molPopulation)
2115 {
2116 double[] fitvals = getFitnesses(molPopulation);
2117 return StatUtils.stddev(fitvals, true);
2118 }
2119
2120//------------------------------------------------------------------------------
2121
2134 public static double getGrowthProbabilityAtLevel(int level, int scheme,
2135 double lambda, double sigmaOne, double sigmaTwo)
2136 {
2137 return getProbability(level, scheme, lambda, sigmaOne, sigmaTwo);
2138 }
2139
2140//------------------------------------------------------------------------------
2141
2154 public static double getMolSizeProbability(DGraph graph,
2155 GAParameters settings)
2156 {
2157 if (!settings.useMolSizeBasedProb())
2158 return 1.0;
2159 int scheme = settings.getMolGrowthProbabilityScheme();
2160 double lambda =settings.getMolGrowthMultiplier();
2161 double sigmaOne = settings.getMolGrowthFactorSteepSigma();
2162 double sigmaTwo = settings.getMolGrowthFactorMiddleSigma();
2163 return getMolSizeProbability(graph, scheme, lambda, sigmaOne, sigmaTwo);
2164 }
2165
2166//------------------------------------------------------------------------------
2167
2180 public static double getMolSizeProbability(DGraph graph,
2181 int scheme, double lambda, double sigmaOne, double sigmaTwo)
2182 {
2183 return getProbability(graph.getHeavyAtomsCount(), scheme, lambda,
2184 sigmaOne, sigmaTwo);
2185 }
2186
2187//------------------------------------------------------------------------------
2188
2199 public static double getProbability(double value,
2200 int scheme, double lambda, double sigmaOne, double sigmaTwo)
2201 {
2202 double prob = 1.0;
2203 if (scheme == 0)
2204 {
2205 double f = Math.exp(-1.0 * value * lambda);
2206 prob = 1 - ((1-f)/(1+f));
2207 }
2208 else if (scheme == 1)
2209 {
2210 prob = 1.0 - Math.tanh(lambda * value);
2211 }
2212 else if (scheme == 2)
2213 {
2214 prob = 1.0-1.0/(1.0 + Math.exp(-sigmaOne * (value - sigmaTwo)));
2215 }
2216 else if (scheme == 3)
2217 {
2218 prob = 1.0;
2219 }
2220 return prob;
2221 }
2222
2223//------------------------------------------------------------------------------
2224
2231 public static double getGrowthByLevelProbability(int level,
2232 GAParameters settings)
2233 {
2234 if (!settings.useLevelBasedProb())
2235 return 1.0;
2236 int scheme = settings.getGrowthProbabilityScheme();
2237 double lambda =settings.getGrowthMultiplier();
2238 double sigmaOne = settings.getGrowthFactorSteepSigma();
2239 double sigmaTwo = settings.getGrowthFactorMiddleSigma();
2240 return getGrowthProbabilityAtLevel(level, scheme, lambda, sigmaOne,
2241 sigmaTwo);
2242 }
2243
2244//------------------------------------------------------------------------------
2245
2255 GAParameters settings)
2256 {
2257 int scheme = settings.getCrowdingProbabilityScheme();
2258 double lambda =settings.getCrowdingMultiplier();
2259 double sigmaOne = settings.getCrowdingFactorSteepSigma();
2260 double sigmaTwo = settings.getCrowdingFactorMiddleSigma();
2261 return getCrowdingProbability(ap, scheme, lambda, sigmaOne, sigmaTwo);
2262 }
2263
2264//------------------------------------------------------------------------------
2265
2279 public static double getCrowdingProbability(int crowdedness,
2280 GAParameters settings)
2281 {
2282 int scheme = settings.getCrowdingProbabilityScheme();
2283 double lambda =settings.getCrowdingMultiplier();
2284 double sigmaOne = settings.getCrowdingFactorSteepSigma();
2285 double sigmaTwo = settings.getCrowdingFactorMiddleSigma();
2286 return getCrowdingProbabilityForCrowdedness(crowdedness, scheme, lambda,
2287 sigmaOne, sigmaTwo);
2288 }
2289
2290//------------------------------------------------------------------------------
2291
2299 public static int getCrowdedness(AttachmentPoint ap)
2300 {
2301 return getCrowdedness(ap,false);
2302 }
2303
2304//------------------------------------------------------------------------------
2305
2315 public static int getCrowdedness(AttachmentPoint ap,
2316 boolean ignoreFreeRCVs)
2317 {
2318 if (ap.getOwner() instanceof EmptyVertex)
2319 {
2320 return 0;
2321 }
2322 int crowdness = 0;
2323 DGraph g = ap.getOwner().getGraphOwner();
2325 {
2326 if (oap.getAtomPositionNumber() == ap.getAtomPositionNumber()
2327 && !oap.isAvailableThroughout()
2328 && oap.getLinkedAP().getOwner()
2329 .getBuildingBlockType() != BBType.CAP)
2330 {
2331 if (ignoreFreeRCVs && oap.getLinkedAP().getOwner().isRCV())
2332 {
2333 if (g.getUsedRCVertices().contains(oap.getLinkedAP().getOwner()))
2334 crowdness = crowdness + 1;
2335 } else {
2336 crowdness = crowdness + 1;
2337 }
2338 }
2339 }
2340 return crowdness;
2341 }
2342
2343//------------------------------------------------------------------------------
2344
2357 public static double getCrowdingProbability(AttachmentPoint ap,
2358 int scheme,
2359 double lambda, double sigmaOne, double sigmaTwo)
2360 {
2361 //Applies only to molecular fragments
2362 if (ap.getOwner() instanceof Fragment == false)
2363 {
2364 return 1.0;
2365 }
2366 int crowdness = getCrowdedness(ap);
2367 return getCrowdingProbabilityForCrowdedness(crowdness, scheme, lambda,
2368 sigmaOne, sigmaTwo);
2369 }
2370
2371//------------------------------------------------------------------------------
2372
2382 public static double getCrowdingProbabilityForCrowdedness(int crowdedness,
2383 int scheme,
2384 double lambda, double sigmaOne, double sigmaTwo)
2385 {
2386 return getProbability(crowdedness, scheme, lambda, sigmaOne, sigmaTwo);
2387 }
2388
2389//------------------------------------------------------------------------------
2390
2399 protected static boolean foundForbiddenEnd(DGraph molGraph,
2400 FragmentSpaceParameters fsParams)
2401 {
2402 List<Vertex> vertices = molGraph.getVertexList();
2403 Set<APClass> classOfForbEnds = fsParams.getFragmentSpace()
2405 for (Vertex vtx : vertices)
2406 {
2407 List<AttachmentPoint> daps = vtx.getAttachmentPoints();
2408 for (AttachmentPoint dp : daps)
2409 {
2410 if (dp.isAvailable())
2411 {
2412 APClass apClass = dp.getAPClass();
2413 if (classOfForbEnds.contains(apClass))
2414 {
2415 String msg = "Forbidden free AP for Vertex: "
2416 + vtx.getVertexId()
2417 + " MolId: " + (vtx.getBuildingBlockId() + 1)
2418 + " Ftype: " + vtx.getBuildingBlockType()
2419 + "\n"+ molGraph+" \n "
2420 + " AP class: " + apClass;
2421 fsParams.getLogger().log(Level.WARNING, msg);
2422 return true;
2423 }
2424 }
2425 }
2426 }
2427 return false;
2428 }
2429
2430//------------------------------------------------------------------------------
2431
2432 protected static void readUID(String infile, HashSet<String> lstInchi)
2433 throws DENOPTIMException
2434 {
2435 ArrayList<String> lst = DenoptimIO.readList(infile);
2436 for (String str:lst)
2437 lstInchi.add(str);
2438 lst.clear();
2439 }
2440
2441//------------------------------------------------------------------------------
2442
2468 //NB: we return a List to retain ordering of the items, but the list must
2469 // not contain redundancies, i.e., lists of AP pairs that are made of the
2470 // same set of AP pairs.
2471 public static List<List<RelatedAPPair>> searchRingFusionSites(
2472 DGraph graph, GAParameters gaParams) throws DENOPTIMException
2473 {
2475 if (gaParams.containsParameters(ParametersType.RC_PARAMS))
2476 {
2477 rcParams = (RingClosureParameters)gaParams.getParameters(
2479 }
2481 if (gaParams.containsParameters(ParametersType.FS_PARAMS))
2482 {
2483 fsParams = (FragmentSpaceParameters)gaParams.getParameters(
2485 }
2486 FragmentSpace fragSpace = fsParams.getFragmentSpace();
2487 Randomizer rng = gaParams.getRandomizer();
2488 boolean projectOnSymmetricAPs = rng.nextBoolean(
2489 gaParams.getSymmetryProbability());
2490 // NB: imposeSymmetryOnAPsOfClass is evaluated inside the
2491 // method searchRingFusionSites
2492 Logger logger = gaParams.getLogger();
2493 return searchRingFusionSites(graph, fragSpace, rcParams,
2494 projectOnSymmetricAPs, logger, rng);
2495 }
2496
2497//------------------------------------------------------------------------------
2498
2524 //NB: we return a List to retain ordering of the items, but the list must
2525 // not contain redundancies, i.e., lists of AP pairs that are made of the
2526 // same set of AP pairs.
2527 public static List<List<RelatedAPPair>> searchRingFusionSites(
2528 DGraph graph, FragmentSpace fragSpace,
2529 RingClosureParameters rcParams, boolean projectOnSymmetricAPs,
2530 Logger logger, Randomizer rng) throws DENOPTIMException
2531 {
2532 // Prepare the empty collector of combinations
2533 List<List<RelatedAPPair>> result = new ArrayList<List<RelatedAPPair>>();
2534
2535 // Most of the work is done on a clone to prevent any modification of the
2536 // 3D molecular representation of the graph, which is here rebuilt in
2537 // a crude way because we only need the connectivity.
2538 DGraph tmpGraph = graph.clone();
2539
2540 // Keep track of which vertexes come from the original graph. We need
2541 // to distinguish them from the capping groups we add here.
2542 Set<Long> originalVertexIDs = new HashSet<Long>();
2543 tmpGraph.getVertexList().stream()
2544 .forEach(v -> originalVertexIDs.add(v.getVertexId()));
2545
2546 // We add capping groups to facilitate the search for substructures
2547 // otherwise we have to write SMARTS that match systems with potentially
2548 // unsaturated valences, and that is a mess.
2549 // Here we change both graph and molecular representation, but it all
2550 // happens on the tmp copy, so the original graph and mol representation
2551 // remain intact. Also, note that the order of atoms does not have a
2552 // role because we only use the position of the atom in the list of atoms
2553 // within the tmp system, and then we use the reference to the
2554 // AP to project the information back into the original system.
2555 tmpGraph.addCappingGroups(fragSpace);
2556
2557 // Get a molecular representation
2558 ThreeDimTreeBuilder t3d = new ThreeDimTreeBuilder(logger, rng);
2559 t3d.setAlignBBsIn3D(false); //3D not needed
2560 IAtomContainer mol = t3d.convertGraphTo3DAtomContainer(tmpGraph, true);
2561
2562 // Search for potential half-ring environments, i.e., sets of atoms
2563 // that belongs to a cyclic system and could hold a chord that would
2564 // define the fused ring.
2565 Map<String, String> smarts = new HashMap<String, String>();
2566 for (BridgeHeadFindingRule rule : rcParams.getBridgeHeadFindingRules())
2567 {
2568 smarts.put(rule.getName(), rule.getSMARTS());
2569 }
2570
2571 ManySMARTSQuery msq = new ManySMARTSQuery(mol, smarts);
2572 if (msq.hasProblems())
2573 {
2574 throw new DENOPTIMException(msq.getMessage());
2575 }
2576 Map<SymmetricSetWithMode,List<RelatedAPPair>> symmRelatedBridgeHeadAPs =
2577 new HashMap<SymmetricSetWithMode,List<RelatedAPPair>>();
2578 List<RelatedAPPair> symBridgeHeadAPs = new ArrayList<RelatedAPPair>();
2579 List<RelatedAPPair> asymBridgeHeadAPs = new ArrayList<RelatedAPPair>();
2580 for (BridgeHeadFindingRule rule : rcParams.getBridgeHeadFindingRules())
2581 {
2582 if (msq.getNumMatchesOfQuery(rule.getName()) == 0)
2583 {
2584 continue;
2585 }
2586
2587 // Get bridge-head atoms
2588 Mappings halfRingAtms = msq.getMatchesOfSMARTS(rule.getName());
2589 // We use a string to facilitate detection of pairs of ids
2590 // irrespectively on the order of ids, i.e., 1-2 vs. 2-1.
2591 Set<String> doneIdPairs = new HashSet<String>();
2592 for (int[] idSubstructure : halfRingAtms)
2593 {
2594 if (idSubstructure.length<2)
2595 {
2596 throw new Error("SMARTS for matching half-ring pattern '"
2597 + rule.getName()
2598 + "' has identified " + idSubstructure.length
2599 + " atoms "
2600 + "instead of at least 2. Modify rule to make it "
2601 + "find 2 or more atoms.");
2602 }
2603
2604 // Potential bridge-head atoms
2605 int[] ids = new int[] {
2606 idSubstructure[rule.getBridgeHeadPositions()[0]],
2607 idSubstructure[rule.getBridgeHeadPositions()[1]]};
2608
2609 IAtom bhA = mol.getAtom(ids[0]);
2610 IAtom bhB = mol.getAtom(ids[1]);
2611
2612 // Avoid duplicate pairs with inverted AP identity
2613 String idPairIdentifier = "";
2614 if (ids[0]<ids[1])
2615 idPairIdentifier = ids[0]+"_"+ids[1];
2616 else
2617 idPairIdentifier = ids[1]+"_"+ids[0];
2618 if (doneIdPairs.contains(idPairIdentifier))
2619 continue;
2620 doneIdPairs.add(idPairIdentifier);
2621
2622 // Bridge-head atoms must have attachment points
2623 if (bhA.getProperty(DENOPTIMConstants.ATMPROPAPS)==null
2624 || bhB.getProperty(DENOPTIMConstants.ATMPROPAPS)==null)
2625 continue;
2626 if (bhA.getProperty(DENOPTIMConstants.ATMPROPVERTEXID)==null
2627 || bhB.getProperty(DENOPTIMConstants.ATMPROPVERTEXID)==null)
2628 throw new IllegalStateException("Atoms in 3d molecular "
2629 + "models of graph objects must have the "
2630 + DENOPTIMConstants.ATMPROPVERTEXID + " property.");
2631
2632 long vrtxIdA = (Long)
2633 bhA.getProperty(DENOPTIMConstants.ATMPROPVERTEXID);
2634 long vrtxIdB = (Long)
2635 bhB.getProperty(DENOPTIMConstants.ATMPROPVERTEXID);
2636
2637 // Each AP on each side can be used
2638 @SuppressWarnings("unchecked")
2639 List<AttachmentPoint> apsOnA = (List<AttachmentPoint>)
2640 bhA.getProperty(DENOPTIMConstants.ATMPROPAPS);
2641 @SuppressWarnings("unchecked")
2642 List<AttachmentPoint> apsOnB = (List<AttachmentPoint>)
2643 bhB.getProperty(DENOPTIMConstants.ATMPROPAPS);
2644 for (int iAPA=0; iAPA<apsOnA.size(); iAPA++)
2645 {
2646 AttachmentPoint copyOfApA = apsOnA.get(iAPA);
2647
2648 // for extreme debug only
2649 /*
2650 System.out.println(rule.getName()+" "+idPairIdentifier+" "
2651 +MoleculeUtils.getAtomRef(bhA, mol)+"-"
2652 +MoleculeUtils.getAtomRef(bhB, mol)+" "
2653 +copyOfApA.getIndexInOwner()
2654 +" in "+copyOfApA.getOwner());
2655 */
2656
2657 if (!canBeUsedForRingFusion(copyOfApA, originalVertexIDs,
2658 fragSpace))
2659 continue;
2660 for (int iAPB=0; iAPB<apsOnB.size(); iAPB++)
2661 {
2662 AttachmentPoint copyOfApB = apsOnB.get(iAPB);
2663
2664 // for extreme debug only
2665 /*
2666 System.out.println(" "+idPairIdentifier+" "
2667 +MoleculeUtils.getAtomRef(bhA, mol)+"-"
2668 +MoleculeUtils.getAtomRef(bhB, mol)+" "
2669 +copyOfApA.getIndexInOwner()
2670 +" in "+copyOfApA.getOwner()
2671 + "--- "
2672 +copyOfApB.getIndexInOwner()
2673 +" in "+copyOfApB.getOwner());
2674 */
2675
2676 if (!canBeUsedForRingFusion(copyOfApB, originalVertexIDs,
2677 fragSpace))
2678 continue;
2679
2680 // Now take the references to the actual APs
2681 AttachmentPoint apA = tmpGraph.getVertexWithId(vrtxIdA)
2682 .getAPWithId(copyOfApA.getID());
2683 AttachmentPoint apB = tmpGraph.getVertexWithId(vrtxIdB)
2684 .getAPWithId(copyOfApB.getID());
2685 if (apA==null || apB==null)
2686 continue;
2687
2688 // Now we have identified a pair of APs suitable to ring fusion
2689 RelatedAPPair pair = new RelatedAPPair(apA, apB, rule,
2690 rule.getName());
2691
2692 //Record symmetric relations
2693 SymmetricAPs symInA = apA.getOwner().getSymmetricAPs(apA);
2694 SymmetricAPs symInB = apB.getOwner().getSymmetricAPs(apB);
2695 if (symInA.size()!=0 && symInB.size()!=0)
2696 {
2697 if (symInA==symInB)
2698 {
2699 storePairsSymmetricRelations(pair, symInA,
2700 symmRelatedBridgeHeadAPs);
2701 } else {
2702 storePairsSymmetricRelations(pair, symInA,
2703 symmRelatedBridgeHeadAPs);
2704 storePairsSymmetricRelations(pair, symInB,
2705 symmRelatedBridgeHeadAPs);
2706 }
2707 symBridgeHeadAPs.add(pair);
2708 } else {
2709 asymBridgeHeadAPs.add(pair);
2710 }
2711 }
2712 }
2713 }
2714 }
2715 if (asymBridgeHeadAPs.size()==0 && symBridgeHeadAPs.size()==0)
2716 {
2717 return result;
2718 }
2719
2720 // Collect potential set of pairs of APs that can be used to create
2721 // fused ring systems accounting for symmetric AP relations.
2722 List<List<RelatedAPPair>> candidateBridgeHeadAPPairs =
2723 new ArrayList<List<RelatedAPPair>>();
2724 if (symmRelatedBridgeHeadAPs.size()>0)
2725 {
2726 for (SymmetricSetWithMode key : symmRelatedBridgeHeadAPs.keySet())
2727 {
2728 List<RelatedAPPair> chosenSymSet =
2729 symmRelatedBridgeHeadAPs.get(key);
2730
2731 @SuppressWarnings("unchecked")
2732 SymmetricSet<AttachmentPoint> symmRelatedAPs =
2733 (SymmetricSet<AttachmentPoint>) key.getItems();
2734 boolean apcImposedSymm = fragSpace.imposeSymmetryOnAPsOfClass(
2735 symmRelatedAPs.get(0).getAPClass());
2736
2737 if (projectOnSymmetricAPs || apcImposedSymm)
2738 {
2739 // We try to get the biggest combination (k is the size)
2740 // but we do limit to avoid combinatorial explosion.
2741 for (int k=Math.min(chosenSymSet.size(), 6); k>0; k--)
2742 {
2743 // Generate combinations that use non-overlapping pairs of APs
2744 List<List<RelatedAPPair>> combs = combineRelatedAPPair(
2745 chosenSymSet, k, 50);
2746 //TODO: make limit of combinations tuneable?
2747
2748 if (combs.size()>0)
2749 {
2750 // We keep only combinations that are not already
2751 // among previously known ones
2752 for (List<RelatedAPPair> comb : combs)
2753 {
2754 boolean isNew = true;
2755 for (List<RelatedAPPair> knownComb :
2756 candidateBridgeHeadAPPairs)
2757 {
2758 if (knownComb.containsAll(comb)
2759 && comb.containsAll(knownComb))
2760 {
2761 isNew = false;
2762 break;
2763 }
2764 }
2765 if (isNew)
2766 {
2767 candidateBridgeHeadAPPairs.add(comb);
2768 for (RelatedAPPair pair : comb)
2769 symBridgeHeadAPs.remove(pair);
2770 }
2771 }
2772 break;
2773 }
2774 }
2775 }
2776 }
2777 // Add left over pairs, if any.
2778 for (RelatedAPPair pair : symBridgeHeadAPs)
2779 {
2780 List<RelatedAPPair> single = new ArrayList<RelatedAPPair>();
2781 single.add(pair);
2782 candidateBridgeHeadAPPairs.add(single);
2783 }
2784 }
2785 for (RelatedAPPair pair : asymBridgeHeadAPs)
2786 {
2787 List<RelatedAPPair> single = new ArrayList<RelatedAPPair>();
2788 single.add(pair);
2789 candidateBridgeHeadAPPairs.add(single);
2790 }
2791
2792 // Project ring fusions into the actual graph (considering symmetry)
2793 for (List<RelatedAPPair> combOnTmpGraph : candidateBridgeHeadAPPairs)
2794 {
2795 List<RelatedAPPair> combOnOriginalGraph =
2796 new ArrayList<RelatedAPPair>();
2797 for (RelatedAPPair pairOnTmpGraph : combOnTmpGraph)
2798 {
2799 Vertex headVertexOnGraph = graph.getVertexAtPosition(
2800 tmpGraph.indexOf(pairOnTmpGraph.apA.getOwner()));
2801 int apHeadID = pairOnTmpGraph.apA.getIndexInOwner();
2802 List<Vertex> symHeadVrts = graph.getSymVerticesForVertex(
2803 headVertexOnGraph);
2804 if (symHeadVrts.size()==0)
2805 symHeadVrts.add(headVertexOnGraph);
2806
2807 Vertex tailVertexOnGraph = graph.getVertexAtPosition(
2808 tmpGraph.indexOf(pairOnTmpGraph.apB.getOwner()));
2809 int apTailID = pairOnTmpGraph.apB.getIndexInOwner();
2810 List<Vertex> symTailVrts = graph.getSymVerticesForVertex(
2811 tailVertexOnGraph);
2812 if (symTailVrts.size()==0)
2813 symTailVrts.add(tailVertexOnGraph);
2814
2815 int numPairs = Math.min(symHeadVrts.size(), symTailVrts.size());
2816 for (int iPair=0; iPair<numPairs; iPair++)
2817 {
2818 RelatedAPPair pairOnOriginalGraph = new RelatedAPPair(
2819 symHeadVrts.get(iPair).getAP(apHeadID),
2820 symTailVrts.get(iPair).getAP(apTailID),
2821 pairOnTmpGraph.property,
2822 pairOnTmpGraph.propID);
2823 combOnOriginalGraph.add(pairOnOriginalGraph);
2824 }
2825 }
2826 result.add(combOnOriginalGraph);
2827 }
2828 return result;
2829 }
2830
2831//------------------------------------------------------------------------------
2832
2833 private static List<List<RelatedAPPair>> combineRelatedAPPair(
2834 List<RelatedAPPair> pool, int k, int limit)
2835 {
2836 List<RelatedAPPair> tmp = new ArrayList<RelatedAPPair>();
2837 List<List<RelatedAPPair>> allCombs = new ArrayList<List<RelatedAPPair>>();
2838 combineRelatedAPPairUtil(pool, 0, k, tmp, allCombs, limit);
2839 return allCombs;
2840 }
2841
2842//------------------------------------------------------------------------------
2843
2844 private static void combineRelatedAPPairUtil(List<RelatedAPPair> pool,
2845 int left, int k,
2846 List<RelatedAPPair> tmp,
2847 List<List<RelatedAPPair>> allCombs, int limit)
2848 {
2849 // PRevent combinatorial explosion: stop if the number of combinations
2850 // grown above the limit
2851 if (allCombs.size()>=limit)
2852 return;
2853
2854 // For last iteration: save answer
2855 if (k == 0)
2856 {
2857 if (!apPairsAreOverlapping(tmp))
2858 {
2859 List<RelatedAPPair> oneComb = new ArrayList<RelatedAPPair>(tmp);
2860 allCombs.add(oneComb);
2861 }
2862 return;
2863 }
2864 // In normal iteration, do recursion
2865 for (int i=left; i<pool.size(); ++i)
2866 {
2867 RelatedAPPair next = pool.get(i);
2868 if (shareAPs(next, tmp))
2869 {
2870 continue;
2871 }
2872 tmp.add(next);
2873 combineRelatedAPPairUtil(pool, i + 1, k-1, tmp, allCombs, limit);
2874 tmp.remove(tmp.size() - 1);
2875 }
2876 }
2877
2878//------------------------------------------------------------------------------
2879
2881 SymmetricAPs symAPs,
2882 Map<SymmetricSetWithMode,List<RelatedAPPair>> storage)
2883 {
2884 SymmetricSetWithMode key = new SymmetricSetWithMode(symAPs, pair.propID);
2885 if (storage.containsKey(key))
2886 {
2887 storage.get(key).add(pair);
2888 } else {
2889 List<RelatedAPPair> lst = new ArrayList<RelatedAPPair>();
2890 lst.add(pair);
2891 storage.put(key, lst);
2892 }
2893 }
2894
2895//------------------------------------------------------------------------------
2896
2905 public static Boolean apPairsAreOverlapping(Iterable<RelatedAPPair> pairs)
2906 {
2907 Set<AttachmentPoint> aps = new HashSet<AttachmentPoint>();
2908
2909 for (RelatedAPPair pair : pairs)
2910 {
2911 if (aps.contains(pair.apA) || aps.contains(pair.apB))
2912 {
2913 return true;
2914 }
2915 aps.add(pair.apA);
2916 aps.add(pair.apB);
2917 }
2918 return false;
2919 }
2920
2921//------------------------------------------------------------------------------
2922
2931 public static Boolean shareAPs(RelatedAPPair pairA,
2932 Iterable<RelatedAPPair> lstB)
2933 {
2934 Set<AttachmentPoint> aps = new HashSet<AttachmentPoint>();
2935 for (RelatedAPPair pairB : lstB)
2936 {
2937 aps.add(pairB.apA);
2938 aps.add(pairB.apB);
2939 }
2940 return aps.contains(pairA.apA) || aps.contains(pairA.apB);
2941 }
2942
2943//------------------------------------------------------------------------------
2944
2967 private static boolean canBeUsedForRingFusion(AttachmentPoint ap,
2968 Set<Long> originalVertexIDs, FragmentSpace fs)
2969 {
2970 if (ap.isAvailableThroughout()
2971 || !originalVertexIDs.contains(
2973 {
2974 if (fs.getRCCompatibilityMatrix().containsKey(ap.getAPClass()))
2975 return true;
2976 }
2977 return false;
2978 }
2979
2980//------------------------------------------------------------------------------
2981
2994 public static List<Vertex> getUsableAromaticBridges(
2995 String elInIncomingFrag, int[] allowedLengths,
2996 FragmentSpace fragSpace)
2997 {
2998 List<Vertex> usableBridgesOriginals =
2999 fragSpace.getVerticesWithAPClassStartingWith(elInIncomingFrag);
3000 List<Vertex> usableBridges = new ArrayList<Vertex>();
3001 final String rootAPC = elInIncomingFrag;
3002 for (Vertex bridge : usableBridgesOriginals)
3003 {
3004 IAtomContainer iacFrag = bridge.getIAtomContainer();
3005 List<Integer> atomIDs = new ArrayList<Integer>();
3006 bridge.getAttachmentPoints()
3007 .stream()
3008 .filter(ap -> ap.getAPClass().getRule().startsWith(
3009 rootAPC))
3010 .forEach(ap -> atomIDs.add(ap.getAtomPositionNumber()));
3011 ShortestPaths sp = new ShortestPaths(iacFrag, iacFrag.getAtom
3012 (atomIDs.get(0)));
3013 List<IAtom> path = new ArrayList<IAtom>(Arrays.asList(
3014 sp.atomsTo(atomIDs.get(1))));
3015 if (IntStream.of(allowedLengths).anyMatch(x -> x == path.size()))
3016 {
3017 Vertex clone = bridge.clone();
3019 path.size());
3020 usableBridges.add(clone);
3021 }
3022 }
3023 return usableBridges;
3024 }
3025
3026//------------------------------------------------------------------------------
3027
3038 public static List<Vertex> getUsableAliphaticBridges(APClass apcA,
3039 APClass apcB, int[] allowedLengths, FragmentSpace fragSpace)
3040 {
3041 List<Vertex> usableBridges = new ArrayList<Vertex>();
3042
3043 List<APClass> compatApClassesA = fragSpace.getCompatibleAPClasses(apcA);
3044 List<APClass> compatApClassesB = fragSpace.getCompatibleAPClasses(apcB);
3045 for (APClass compatA : compatApClassesA)
3046 {
3047 for (APClass compatB : compatApClassesB)
3048 {
3049 boolean sameAPC = compatA.equals(compatB);
3050 Map<APClass,Integer> apFingerprint =
3051 new HashMap<APClass,Integer>();
3052 if (sameAPC)
3053 {
3054 apFingerprint.put(compatA,2);
3055 } else {
3056 apFingerprint.put(compatA,1);
3057 apFingerprint.put(compatB,1);
3058 }
3059 for (Vertex bridge : fragSpace.getVerticesWithAPFingerprint(
3060 apFingerprint))
3061 {
3062 IAtomContainer iacFrag = bridge.getIAtomContainer();
3063
3064 // Identify APs that can be used for each side
3065 List<AttachmentPoint> apsForA = new ArrayList<AttachmentPoint>();
3066 List<AttachmentPoint> apsForB = new ArrayList<AttachmentPoint>();
3067 for (AttachmentPoint apOnBridge : bridge.getAttachmentPoints())
3068 {
3069 if (compatA.equals(apOnBridge.getAPClass()))
3070 apsForA.add(apOnBridge);
3071 if (compatB.equals(apOnBridge.getAPClass()))
3072 apsForB.add(apOnBridge);
3073 }
3074
3075 // Find combinations of usable APs
3076 for (AttachmentPoint apForA : apsForA)
3077 {
3078 ShortestPaths sp = new ShortestPaths(iacFrag,
3079 iacFrag.getAtom(apForA.getAtomPositionNumber()));
3080 for (AttachmentPoint apForB : apsForB)
3081 {
3082 if (apForA.equals(apForB))
3083 continue;
3084 // Retains only combinations of allowed length
3085 List<IAtom> path = new ArrayList<IAtom>(
3086 Arrays.asList(sp.atomsTo(
3087 apForB.getAtomPositionNumber())));
3088 if (IntStream.of(allowedLengths).anyMatch(
3089 x -> x == path.size()))
3090 {
3091 Vertex clone = bridge.clone();
3092 clone.setProperty(
3094 path.size());
3095 clone.setProperty(
3097 apForA.getIndexInOwner());
3098 clone.setProperty(
3100 apForB.getIndexInOwner());
3101 usableBridges.add(clone);
3102 }
3103 }
3104 }
3105 }
3106 }
3107 }
3108 return usableBridges;
3109 }
3110
3111//------------------------------------------------------------------------------
3112
3113}
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 ATMPROPAPS
String tag of Atom property used to store attachment points.
static final String VRTPROPBRIDGEEND_B
Name of Vertex property used to record which AP is selected for bridge formation on side 'B'.
static final String ATMPROPVERTEXID
String tag of Atom property used to store the unique ID of the Vertex corresponding to the molecular ...
static final String GAGENSUMMARYHEADER
Header of text files collection generation details.
static final String GAGENDIRNAMEROOT
Prefix for generation folders.
static final String FITFILENAMEEXTOUT
Ending and extension of output file of external fitness provider.
static final String VRTPROPBRIDGEEND_A
Name of Vertex property used to record which AP is selected for bridge formation on side 'A'.
Settings defining the calculation of fitness.
SMARTS-based rules to identify potential bridge head atoms for ring fusion operations.
static Vertex getRCPForAP(AttachmentPoint ap, APClass rcvApClass)
static boolean prepareMolToFragmentation(IAtomContainer mol, FragmenterParameters settings, int index)
Do any pre-processing on a IAtomContainer meant to be fragmented.
static boolean fragmentation(File input, FragmenterParameters settings, File output, Logger logger)
Performs fragmentation according to the given cutting rules.
Class defining a space of building blocks.
boolean useAPclassBasedApproach()
Check usage of APClass-based approach, i.e., uses attachment points with annotated data (i....
List< Vertex > getVerticesWithAPClassStartingWith(String root)
Extracts vertexes from the collection of vertexes defined by this FragmentSpace.
HashMap< APClass, ArrayList< APClass > > getRCCompatibilityMatrix()
Returns the compatibility matrix for ring closing fragment-fragment connections or null if not provid...
Vertex makeRandomScaffold()
Randomly select a scaffold and return a fully configured clone of it.
HashMap< APClass, APClass > getCappingMap()
ArrayList< APClass > getCompatibleAPClasses(APClass apc)
Returns a list of APClasses compatible with the given APClass.
List< Vertex > getVerticesWithAPFingerprint(Map< APClass, Integer > apcCounts)
Returns the list of vertexes that have the specified number of AttachmentPoints with the given APClas...
Parameters defining the fragment space.
Helper methods for the genetic algorithm.
Definition: EAUtils.java:107
static Boolean shareAPs(RelatedAPPair pairA, Iterable< RelatedAPPair > lstB)
Evaluates if a RelatedAPPair involves the same AttachmentPoint present in a collection.
Definition: EAUtils.java:2931
static void outputFinalResults(Population popln, GAParameters settings)
Saves the final results to disk.
Definition: EAUtils.java:1634
static List< Candidate > buildCandidatesByXOver(List< Candidate > eligibleParents, Population population, Monitor mnt, int[] choiceOfParents, int choiceOfXOverSites, int choiceOfOffstring, GAParameters settings, int maxCandidatesToReturn)
Generates up to a pair of new offspring by performing a crossover operation.
Definition: EAUtils.java:392
static CandidateSource pickNewCandidateGenerationMode(double xoverWeight, double mutWeight, double newWeight, Randomizer randomizer)
Takes a decision on which CandidateSource method to use for generating a new Candidate.
Definition: EAUtils.java:263
static double getGrowthByLevelProbability(int level, GAParameters settings)
Calculates the probability of adding a fragment to the given level.
Definition: EAUtils.java:2231
static double getCrowdingProbability(int crowdedness, GAParameters settings)
Calculated the probability of using and attachment point rooted on an atom that is holding other atta...
Definition: EAUtils.java:2279
static int chooseNumberOfSitesToMutate(double[] multiSiteMutationProb, double hit)
Takes a decision on how many sites to mutate on a candidate.
Definition: EAUtils.java:224
static void appendVertexesToGraphFollowingEdges(DGraph graph, AtomicInteger vId, List< Vertex > vertexes)
Definition: EAUtils.java:1248
static Candidate readCandidateFromFile(File srcFile, Monitor mnt, GAParameters settings)
Definition: EAUtils.java:769
static Candidate[] selectBasedOnFitness(List< Candidate > eligibleParents, int number, GAParameters settings)
Selects a number of members from the given population.
Definition: EAUtils.java:1440
static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol, List< CuttingRule > cuttingRules, Logger logger, ScaffoldingPolicy scaffoldingPolicy, double linearAngleLimit)
Converts a molecule into a DGraph by fragmentation and re-assembling of the fragments.
Definition: EAUtils.java:1070
static boolean setupRings(Object[] res, DGraph molGraph, GAParameters settings)
Evaluates the possibility of closing rings in a given graph and if any ring can be closed,...
Definition: EAUtils.java:1898
static Candidate buildCandidateByXOver(List< Candidate > eligibleParents, Population population, Monitor mnt, GAParameters settings)
Generates a new offspring by performing a crossover operation.
Definition: EAUtils.java:313
static List< Candidate > buildCandidatesByXOver(List< Candidate > eligibleParents, Population population, Monitor mnt, GAParameters settings)
Generates a pair of new offspring by performing a crossover operation.
Definition: EAUtils.java:293
static boolean canBeUsedForRingFusion(AttachmentPoint ap, Set< Long > originalVertexIDs, FragmentSpace fs)
Decides if an AttachmentPoint can be considered for making a ring fusion operation,...
Definition: EAUtils.java:2967
static final String NL
Definition: EAUtils.java:137
static void getPopulationFromFile(String filename, Population population, SizeControlledSet uniqueIDsSet, String genDir, GAParameters settings)
Reconstruct the molecular population from the file.
Definition: EAUtils.java:1692
static void writeUID(String outfile, HashSet< String > lstInchi, boolean append)
Definition: EAUtils.java:1749
static HashMap< Integer, ArrayList< String > > lstFragmentClass
Definition: EAUtils.java:128
static double getGrowthProbabilityAtLevel(int level, int scheme, double lambda, double sigmaOne, double sigmaTwo)
Calculates the probability of adding a fragment to the given level.
Definition: EAUtils.java:2134
static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol, List< CuttingRule > cuttingRules, Logger logger, ScaffoldingPolicy scaffoldingPolicy)
Converts a molecule into a DGraph by fragmentation and re-assembling of the fragments.
Definition: EAUtils.java:1044
static double getProbability(double value, int scheme, double lambda, double sigmaOne, double sigmaTwo)
Calculated a probability given parameters defining the shape of the probability function and a single...
Definition: EAUtils.java:2199
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:3038
static XoverSite performFBCC(List< Candidate > eligibleParents, Population population, int[] choiceOfParents, int choiceOfXOverSites, GAParameters settings)
Perform fitness-based, class-compatible selection of parents that can do crossover operations.
Definition: EAUtils.java:1518
static String getPathNameToFinalPopulationFolder(GAParameters settings)
Definition: EAUtils.java:1604
static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol, List< CuttingRule > cuttingRules, Logger logger, ScaffoldingPolicy scaffoldingPolicy, double linearAngleLimit, FragmentSpace fragSpace)
Converts a molecule into a DGraph by fragmentation and re-assembling of the fragments.
Definition: EAUtils.java:1122
static CandidateSource chooseGenerationMethod(GAParameters settings)
Choose one of the methods to make new Candidates.
Definition: EAUtils.java:207
static Locale enUsLocale
Locale used to write reports.
Definition: EAUtils.java:114
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:2254
static boolean foundForbiddenEnd(DGraph molGraph, FragmentSpaceParameters fsParams)
Check if there are forbidden ends: free attachment points that are not suitable for capping and not a...
Definition: EAUtils.java:2399
static List< List< RelatedAPPair > > searchRingFusionSites(DGraph graph, GAParameters gaParams)
Definition: EAUtils.java:2471
static void setVertexCounterValue(Population population)
Set the Vertex counter value according to the largest value found in the given population.
Definition: EAUtils.java:1782
static Candidate buildCandidateByMutation(List< Candidate > eligibleParents, Monitor mnt, GAParameters settings)
Definition: EAUtils.java:645
static Candidate buildCandidateByFragmentingMolecule(IAtomContainer mol, Monitor mnt, GAParameters settings, int index)
Generates a candidate by fragmenting a molecule and generating the graph that reconnects all fragment...
Definition: EAUtils.java:943
static DGraph buildGraph(GAParameters settings)
Graph construction starts with selecting a random core/scaffold.
Definition: EAUtils.java:1803
static Candidate buildCandidateByXOver(List< Candidate > eligibleParents, Population population, Monitor mnt, int[] choiceOfParents, int choiceOfXOverSites, int choiceOfOffstring, GAParameters settings)
Generates a new offspring by performing a crossover operation.
Definition: EAUtils.java:347
static double[] getFitnesses(Population mols)
Get the fitness values for the list of molecules.
Definition: EAUtils.java:2093
static String getSummaryStatistics(Population popln, GAParameters settings)
Definition: EAUtils.java:1383
static void createFolderForGeneration(int genId, GAParameters settings)
Creates a folder meant to hold all the data generated during a generation.
Definition: EAUtils.java:148
static double getMolSizeProbability(DGraph graph, int scheme, double lambda, double sigmaOne, double sigmaTwo)
Calculated the probability of extending a graph based on the current size of the molecular representa...
Definition: EAUtils.java:2180
static DecimalFormat initialiseFormatter()
Definition: EAUtils.java:120
static int getCrowdedness(AttachmentPoint ap)
Calculate the current crowdedness of the given attachment point.
Definition: EAUtils.java:2299
static int getCrowdedness(AttachmentPoint ap, boolean ignoreFreeRCVs)
Calculate the current crowdedness of the given attachment point.
Definition: EAUtils.java:2315
static HashMap< Integer, ArrayList< Integer > > fragmentPool
Definition: EAUtils.java:109
static List< List< RelatedAPPair > > combineRelatedAPPair(List< RelatedAPPair > pool, int k, int limit)
Definition: EAUtils.java:2833
static void combineRelatedAPPairUtil(List< RelatedAPPair > pool, int left, int k, List< RelatedAPPair > tmp, List< List< RelatedAPPair > > allCombs, int limit)
Definition: EAUtils.java:2844
static void outputPopulationDetails(Population population, String filename, GAParameters settings, boolean printpathNames)
Write out summary for the current GA population.
Definition: EAUtils.java:1324
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:2994
static Vertex selectNonScaffoldNonCapVertex(DGraph g, Randomizer randomizer)
Chose randomly a vertex that is neither scaffold or capping group.
Definition: EAUtils.java:1490
static double getCrowdingProbabilityForCrowdedness(int crowdedness, int scheme, double lambda, double sigmaOne, double sigmaTwo)
Calculated the crowding probability for a given level of crowdedness.
Definition: EAUtils.java:2382
static String getPathNameToGenerationFolder(int genID, GAParameters settings)
Definition: EAUtils.java:1568
static double getPopulationSD(Population molPopulation)
Check if fitness values have significant standard deviation.
Definition: EAUtils.java:2114
static String getPathNameToFinalPopulationDetailsFile(GAParameters settings)
Definition: EAUtils.java:1613
static Candidate buildCandidateFromScratch(Monitor mnt, GAParameters settings)
Definition: EAUtils.java:842
static double getCrowdingProbability(AttachmentPoint ap, int scheme, double lambda, double sigmaOne, double sigmaTwo)
Calculated the probability of using and attachment point rooted on an atom that is holding other atta...
Definition: EAUtils.java:2357
static boolean containsMolecule(Population mols, String molcode)
Check if the population contains the specified InChi code.
Definition: EAUtils.java:2070
static DecimalFormat df
Format for decimal fitness numbers that overwrites Locale to en_US.
Definition: EAUtils.java:119
static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol, List< CuttingRule > cuttingRules, Logger logger, ScaffoldingPolicy scaffoldingPolicy, FragmentSpace fragSpace)
Converts a molecule into a DGraph by fragmentation and re-assembling of the fragments.
Definition: EAUtils.java:1094
static List< List< RelatedAPPair > > searchRingFusionSites(DGraph graph, FragmentSpace fragSpace, RingClosureParameters rcParams, boolean projectOnSymmetricAPs, Logger logger, Randomizer rng)
Definition: EAUtils.java:2527
static void storePairsSymmetricRelations(RelatedAPPair pair, SymmetricAPs symAPs, Map< SymmetricSetWithMode, List< RelatedAPPair > > storage)
Definition: EAUtils.java:2880
static void readUID(String infile, HashSet< String > lstInchi)
Definition: EAUtils.java:2432
static final String FSEP
Definition: EAUtils.java:138
static String getPathNameToGenerationDetailsFile(int genID, GAParameters settings)
Definition: EAUtils.java:1584
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:2154
static Population importInitialPopulation(SizeControlledSet uniqueIDsSet, GAParameters settings)
Reads unique identifiers and initial population file according to the GAParameters.
Definition: EAUtils.java:162
static Boolean apPairsAreOverlapping(Iterable< RelatedAPPair > pairs)
Evaluates if any pair of AttachmentPoint pairs involve the same AttachmentPoint, i....
Definition: EAUtils.java:2905
Collection of operators meant to alter graphs and associated utilities.
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 boolean performMutation(DGraph graph, Monitor mnt, GAParameters settings)
Tries to do mutate the given graph.
static boolean performCrossover(XoverSite site, FragmentSpace fragSpace)
Performs the crossover that swaps the two subgraphs defining the given XoverSite.
A collection of candidates.
Definition: Population.java:48
List< XoverSite > getXoverSites(Candidate parentA, Candidate parentB)
Returns a list of crossover sites between the two given parents.
List< Candidate > getXoverPartners(Candidate memberA, List< Candidate > eligibleParents, FragmentSpace fragSpace)
Returns a list of population members that can do crossover with the specified member.
Class that offers methods to performs fitness-driven selection of candidates.
static Candidate[] performRandomSelection(List< Candidate > population, int sz, RunTimeParameters settings)
Randomly select k individuals from the population.
static Candidate[] performRWS(List< Candidate > population, int sz, RunTimeParameters settings)
Roulette wheel selection is implemented as follows:
static Candidate[] performSUS(List< Candidate > population, int sz, RunTimeParameters settings)
Stochastic Uniform Sampling Note: this implementation is based on the WATCHMAKER framework http://wat...
static Candidate[] performTournamentSelection(List< Candidate > eligibleParents, int sz, GAParameters settings)
Select a number individuals at random (i.e., tournamentSize).
This class collects the data identifying the subgraphs that would be swapped by a crossover event.
Definition: XoverSite.java:36
XoverSite projectToClonedGraphs()
Creates a new instance of this class that contains the list of vertexes that correspond to those cont...
Definition: XoverSite.java:275
String toString()
Produced a string for showing what this object is.
Definition: XoverSite.java:349
List< Vertex > getA()
Returns the collection of vertexes belonging to the first subgraph.
Definition: XoverSite.java:187
List< Vertex > getB()
Returns the collection of vertexes belonging to the second subgraph.
Definition: XoverSite.java:198
static final APClass RCACLASSMINUS
Conventional class of attachment points on ring-closing vertexes.
Definition: APClass.java:92
static final String ATPLUS
String defining a conventional APClass.
Definition: APClass.java:69
static APClass make(String ruleAndSubclass)
Creates an APClass if it does not exist already, or returns the reference to the existing instance.
Definition: APClass.java:164
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.
int getID()
Returns a unique integer that is used to sort list of attachment points.
int getAtomPositionNumber()
The index of the source atom in the atom list of the fragment.
boolean isAvailableThroughout()
Check availability of this attachment point throughout the graph level, i.e., check also across the i...
AttachmentPoint getLinkedAPThroughout()
Gets the attachment point (AP) that is connected to this AP via the edge user or in any edge user tha...
A candidate is the combination of a denoptim graph with molecular representation and may include also...
Definition: Candidate.java:40
void setSDFFile(String molFile)
Definition: Candidate.java:445
void setSmiles(String smiles)
Definition: Candidate.java:473
void setUID(String uid)
Definition: Candidate.java:466
int getGeneration()
The generation this candidate belong to is that in which it was generated.
Definition: Candidate.java:578
void setName(String name)
Definition: Candidate.java:495
void setChemicalRepresentation(IAtomContainer iac)
Just place the argument in the IAtomContainer field of this object.
Definition: Candidate.java:378
Container for the list of vertices and the edges that connect them.
Definition: DGraph.java:102
void setCandidateClosableChains(ArrayList< ClosableChain > closableChains)
Definition: DGraph.java:933
void addVertex(Vertex vertex)
Appends a vertex to this graph without creating any edge.
Definition: DGraph.java:1325
DGraph embedPatternsInTemplates(GraphPattern pattern, FragmentSpace fragSpace)
Searches for the given pattern type and generated a new graph where each set of (clones of) vertexes ...
Definition: DGraph.java:4845
void getChildrenTree(Vertex vertex, List< Vertex > children)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:3000
String getLocalMsg()
Definition: DGraph.java:287
void setGraphId(int id)
Definition: DGraph.java:264
ArrayList< Vertex > getFreeRCVertices()
Search for unused ring closing vertices: vertices that contain only a RingClosingAttractor and are no...
Definition: DGraph.java:1212
Object[] checkConsistency(RunTimeParameters settings)
Peeks into this graph to derive a preliminary chemical representation with SMILES and InChIKey.
Definition: DGraph.java:5582
List< Vertex > getVertexList()
Definition: DGraph.java:947
DGraph clone()
Returns almost "deep-copy" of this graph.
Definition: DGraph.java:3415
void renumberGraphVertices()
Reassign vertex IDs to all vertices of this graph.
Definition: DGraph.java:5512
boolean containsOrEmbedsVertex(Vertex v)
Check if the specified vertex is contained in this graph as a node or in any inner graphs that may be...
Definition: DGraph.java:2759
DGraph getOutermostGraphOwner()
Definition: DGraph.java:7209
void addCappingGroups(FragmentSpace fragSpace)
Add a capping groups on free unused attachment points.
Definition: DGraph.java:4398
void cleanup()
Wipes the data in this graph.
Definition: DGraph.java:3597
Candidate getCandidateOwner()
Returns the reference of the candidate item that is defined by this graph.
Definition: DGraph.java:257
ArrayList< Vertex > getUsedRCVertices()
Search for used ring closing vertices: vertices that contain only a RingClosingAttractor and are part...
Definition: DGraph.java:1235
int getHeavyAtomsCount()
Calculate the number of atoms from the graph representation.
Definition: DGraph.java:4182
List< Vertex > getMutableSites()
A list of mutation sites from within this graph.
Definition: DGraph.java:6858
void setLocalMsg(String msg)
Definition: DGraph.java:279
boolean detectSymVertexSets()
Detects and groups symmetric sets of Vertexes in the graph based on unique identification and path en...
Definition: DGraph.java:368
An empty vertex has the behaviors of a vertex, but has no molecular structure.
Class representing a continuously connected portion of chemical object holding attachment points.
Definition: Fragment.java:61
boolean isIsomorphicTo(Vertex other)
Checks for isomorphism of the graph representation of this and another fragment.
Definition: Fragment.java:1066
void updateAPs()
Changes the properties of each APs as to reflect the current atom list.
Definition: Fragment.java:511
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",...
Class representing a list of references pointing to instances that are related by some conventional c...
Class coupling a reference to a SymmetricSet with a string that we call "mode" and can is used to sto...
A vertex is a data structure that has an identity and holds a list of AttachmentPoints.
Definition: Vertex.java:62
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:305
void setVertexId(long vertexId2)
Definition: Vertex.java:282
DGraph getGraphOwner()
Returns the graph this vertex belongs to or null.
Definition: Vertex.java:852
abstract List< AttachmentPoint > getAttachmentPoints()
SymmetricAPs getSymmetricAPs(AttachmentPoint ap)
For the given attachment point index locate the symmetric partners i.e.
Definition: Vertex.java:354
abstract int getHeavyAtomsCount()
void setBuildingBlockType(Vertex.BBType buildingBlockType)
Definition: Vertex.java:326
abstract IAtomContainer getIAtomContainer()
boolean hasFreeAP()
Definition: Vertex.java:521
void setProperty(Object key, Object property)
Definition: Vertex.java:1236
AttachmentPoint getAP(int i)
Get attachment point i on this vertex.
Definition: Vertex.java:1008
This is a tool to identify and manage vertices' connections not included in the DGraph,...
List< Ring > getRandomCombinationOfRings(IAtomContainer inMol, DGraph molGraph, int maxRingClosures)
Identifies a random combination of ring closing paths and returns it as list of DENOPTIMRings ready t...
boolean checkChelatesGraph(DGraph molGraph, List< Ring > ringsSet)
Evaluates the combination of a DENOPTIMGraph and a set of DENOPTIMRings and decides whether it's a pr...
ArrayList< List< Ring > > getPossibleCombinationOfRings(IAtomContainer mol, DGraph molGraph)
Identifies all possible ring closing paths and returns them as list of DENOPTIMRings ready to be appe...
Parameters and setting related to handling ring closures.
boolean buildChelatesMode
Flag activating procedures favoring formation of chelates.
Data structure to store and handle information about sub-structures (i.e., chains of fragments) and r...
ArrayList< ClosableChain > getCCFromTurningPointId(int tpId)
Returns the library of closable chains having the given turning point (i.e., the fragments involved i...
Utility methods for input/output.
static ArrayList< Candidate > readCandidates(File file)
Reads SDF files that represent one or more tested candidates.
static void writeGraphsToSDF(File file, List< DGraph > graphs, Logger logger, Randomizer randomizer)
Writes the graphs to SDF file.
static void writeCandidateToFile(File file, Candidate candidate, boolean append)
Writes one candidate item to file.
static void writeGraphToSDF(File file, DGraph graph, boolean append, boolean make3D, Logger logger, Randomizer randomizer)
Writes the graph to SDF file.
static ArrayList< DGraph > readDENOPTIMGraphsFromFile(File inFile)
Reads a list of DGraphs from file.
static ArrayList< String > readList(String fileName)
Read list of data as text.
static void writeData(String fileName, String data, boolean append)
Write text-like data file.
static void writeCandidatesToFile(File file, List< Candidate > popMembers, boolean append)
Writes candidate items to file.
A collection of counters user to count actions taken by the evolutionary algorithm.
Definition: Monitor.java:37
void increase(CounterID cid)
Definition: Monitor.java:149
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.
boolean containsParameters(ParametersType type)
RunTimeParameters getParameters(ParametersType type)
Logger getLogger()
Get the name of the program specific logger.
final String NL
New line character.
Randomizer getRandomizer()
Returns the current program-specific randomizer.
Parameters for genetic algorithm.
boolean useMolSizeBasedProb
Flag recording the intention to use molecular size-controlled graph extension probability.
boolean recordMateSelection
Flag defining whether we record which mates are selected or not.
boolean useLevelBasedProb
Flag recording the intention to use level-controlled graph extension probability.
Parameters controlling execution of the fragmenter.
boolean embedRingsInTemplate
Flag that enables the embedding of rings in templates upon conversion of molecules into DGraph.
Toll to add/remove dummy atoms from linearities or multi-hapto sites.
static void addDummiesOnLinearities(Fragment frag, double angLim)
Append dummy atoms on otherwise linear arrangements of atoms.
static String getPaddedString(int count, int number)
returns the padded string with zeroes placed to the left of 'number' up to reach the desired number o...
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 int getUniqueMoleculeIndex()
Unique counter for the number of molecules generated.
static synchronized int getUniqueGraphIndex()
Unique counter for the number of graphs generated.
Container of lists of atoms matching a list of SMARTS.
Mappings getMatchesOfSMARTS(String ref)
int getNumMatchesOfQuery(String query)
Utilities for molecule conversion.
static String getInChIKeyForMolecule(IAtomContainer mol, Logger logger)
Generates the InChI key for the given atom container.
static String getSMILESForMolecule(IAtomContainer mol, Logger logger)
Returns the SMILES representation of the molecule.
static String getSymbolOrLabel(IAtom atm)
Gets either the elemental symbol (for standard atoms) of the label (for pseudo-atoms).
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.
double nextDouble()
Returns the next pseudo-random, uniformly distributed double value between 0.0 and 1....
Tool box for definition and management of the rotational space, which is given by the list of rotatab...
static ArrayList< ObjectPair > defineRotatableBonds(IAtomContainer mol, String defRotBndsFile, boolean addIterfragBonds, boolean excludeRings, Logger logger)
Define the rotational space (also torsional space) for a given molecule.
Class meant to collect unique strings without leading to memory overflow.
Utilities for calculating basic statistics.
Definition: StatUtils.java:26
static double mean(double[] numbers)
Returns the mean number in the numbers list.
Definition: StatUtils.java:53
static double stddev(double[] numbers, boolean biasCorrected)
Returns the standard deviation of the numbers.
Definition: StatUtils.java:107
static double skewness(double[] m, boolean biasCorrected)
Computes the skewness of the available values.
Definition: StatUtils.java:246
static double median(double[] m)
Calculates median value of a sorted list.
Definition: StatUtils.java:172
static double min(double[] numbers)
Returns the minimum value among the numbers .
Definition: StatUtils.java:67
static double max(double[] numbers)
Returns the maximum value among the numbers .
Definition: StatUtils.java:85
Defines how to define the scaffold vertex of a graph.
A chosen method for generation of new Candidates.
Definition: EAUtils.java:133
Possible chemical bond types an edge can represent.
Definition: Edge.java:303
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
The type of building block.
Definition: Vertex.java:87
Identifier of a counter.
Definition: CounterID.java:29
FS_PARAMS
Parameters pertaining the definition of the fragment space.
FRG_PARAMS
Parameters controlling the fragmenter.
FIT_PARAMS
Parameters pertaining the calculation of fitness (i.e., the fitness provider).
RC_PARAMS
Parameters pertaining to ring closures in graphs.