$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 frgParams.embedRingsInTemplate(),
984 frgParams.getEmbeddedRingsContract(),
985 fragSpace, mnt);
986 } catch (DENOPTIMException de)
987 {
988 String msg = "Unable to convert molecule (" + mol.getAtomCount()
989 + " atoms) to DENOPTIM graph. " + de.getMessage();
990 settings.getLogger().log(Level.WARNING, msg);
991 }
992 if (graph == null)
993 {
995 return null;
996 }
997
998 graph.setLocalMsg("INITIAL_MOL_FRAGMENTED");
999
1000 Object[] res = graph.checkConsistency(settings);
1001 if (res == null)
1002 {
1003 graph.cleanup();
1005 return null;
1006 }
1007
1008 Candidate candidate = new Candidate(graph);
1009 candidate.setUID(res[0].toString().trim());
1010 candidate.setSmiles(res[1].toString().trim());
1011 candidate.setChemicalRepresentation((IAtomContainer) res[2]);
1012
1013 candidate.setName("M" + GeneralUtils.getPaddedString(
1016
1017 return candidate;
1018 }
1019
1020//------------------------------------------------------------------------------
1021
1033 public static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol,
1034 List<CuttingRule> cuttingRules, Logger logger,
1035 ScaffoldingPolicy scaffoldingPolicy)
1036 throws DENOPTIMException
1037 {
1038 return makeGraphFromFragmentationOfMol(mol, cuttingRules, logger,
1039 scaffoldingPolicy, 190, new FragmentSpace());
1040 // NB: and angle of 190 means we are not adding Du on linearities
1041 // because the max possible bond angle is 180.
1042 }
1043
1044//------------------------------------------------------------------------------
1045
1059 public static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol,
1060 List<CuttingRule> cuttingRules, Logger logger,
1061 ScaffoldingPolicy scaffoldingPolicy, double linearAngleLimit)
1062 throws DENOPTIMException
1063 {
1064 return makeGraphFromFragmentationOfMol(mol, cuttingRules, logger,
1065 scaffoldingPolicy, linearAngleLimit, new FragmentSpace());
1066 }
1067
1068//------------------------------------------------------------------------------
1069
1083 public static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol,
1084 List<CuttingRule> cuttingRules, Logger logger,
1085 ScaffoldingPolicy scaffoldingPolicy, FragmentSpace fragSpace)
1086 throws DENOPTIMException
1087 {
1088 return makeGraphFromFragmentationOfMol(mol, cuttingRules, logger,
1089 scaffoldingPolicy, 190, fragSpace);
1090 // NB: and angle of 190 means we are not adding Du on linearities
1091 // because the max possible bond angle is 180.
1092 }
1093
1094//------------------------------------------------------------------------------
1095
1111 public static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol,
1112 List<CuttingRule> cuttingRules, Logger logger,
1113 ScaffoldingPolicy scaffoldingPolicy, double linearAngleLimit,
1114 FragmentSpace fragSpace)
1115 throws DENOPTIMException
1116 {
1117 return makeGraphFromFragmentationOfMol(mol, cuttingRules, logger,
1118 scaffoldingPolicy, linearAngleLimit, false, null,
1119 fragSpace, null);
1120 }
1121
1122//------------------------------------------------------------------------------
1123
1145 public static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol,
1146 List<CuttingRule> cuttingRules, Logger logger,
1147 ScaffoldingPolicy scaffoldingPolicy, double linearAngleLimit,
1148 boolean embedRingsInTemplates, ContractLevel ringTmplContract,
1149 FragmentSpace fragSpace, Monitor monitor)
1150 throws DENOPTIMException
1151 {
1152 // We expect only Fragments here.
1153 List<Vertex> fragments = FragmenterTools.fragmentation(mol,
1154 cuttingRules, logger);
1155 for (Vertex v : fragments)
1156 {
1157 Fragment frag = (Fragment) v;
1158
1159 // This is done to set the symmetry relations in each vertex
1160 frag.updateAPs();
1161
1162 // Add linearity-breaking dummy atoms
1163 DummyAtomHandler.addDummiesOnLinearities(frag, linearAngleLimit);
1164 }
1165 if (fragments.size()==0)
1166 {
1167 if (monitor!=null)
1168 {
1170 }
1171 throw new DENOPTIMException("Fragmentation of molecule with "
1172 + mol.getAtomCount() + " atoms produced 0 fragments.");
1173 }
1174
1175 // Define which fragment is the scaffold
1176 Vertex scaffold = null;
1177 switch (scaffoldingPolicy)
1178 {
1179 case ELEMENT:
1180 {
1181 for (Vertex v : fragments)
1182 {
1183 if (v instanceof Fragment)
1184 {
1185 boolean setAsScaffold = false;
1186 IAtomContainer iac = v.getIAtomContainer();
1187 for (IAtom atm : iac.atoms())
1188 {
1189 if (scaffoldingPolicy.label.equals(
1191 {
1192 setAsScaffold = true;
1193 break;
1194 }
1195 }
1196 if (setAsScaffold)
1197 {
1198 scaffold = v;
1199 break;
1200 }
1201 }
1202 }
1203 break;
1204 }
1205
1206 default:
1207 case LARGEST_FRAGMENT:
1208 {
1209 try {
1210 scaffold = fragments.stream()
1211 .max(Comparator.comparing(
1213 .get();
1214 } catch (Exception e)
1215 {
1216 if (monitor!=null)
1217 {
1219 }
1220 throw new DENOPTIMException("Cannot get largest fragment "
1221 + "among " + fragments.size() + " fragments.", e);
1222 }
1223 break;
1224 }
1225 }
1226 if (scaffold==null)
1227 {
1228 if (monitor!=null)
1229 {
1231 }
1232 throw new DENOPTIMException("No fragment matches criteria to be "
1233 + "identified as the "
1234 + BBType.SCAFFOLD.toString().toLowerCase() + ".");
1235 }
1236 scaffold.setVertexId(0);
1238
1239 // Build the graph
1240 DGraph graph = new DGraph();
1241 graph.addVertex(scaffold);
1242 AtomicInteger vId = new AtomicInteger(1);
1243 for (int i=1; i<fragments.size(); i++)
1244 {
1245 appendVertexesToGraphFollowingEdges(graph, vId, fragments);
1246 }
1247
1248 // Set symmetry relations: these depend on which scaffold we have chosen
1249 graph.detectSymVertexSets();
1250
1251 // Identify capping groups, i.e., fragments that reflect the capping
1252 // groups found in the fragment space, if any.
1253 if (fragSpace!=null && fragSpace.getCappingMap()!=null)
1254 {
1255 for (Vertex v : graph.getVertexList())
1256 {
1257 if (v.getAttachmentPoints().size()!=1 || v.isRCV())
1258 continue;
1259
1260 APClass srcAPC = v.getAP(0).getLinkedAPThroughout().getAPClass();
1261 APClass capAPC = fragSpace.getAPClassOfCappingVertex(srcAPC);
1262 Vertex cap = fragSpace.getCappingVertexWithAPClass(capAPC);
1263 if (cap==null)
1264 continue;
1265
1266 if (!(v instanceof Fragment && cap instanceof Fragment))
1267 continue;
1268
1269 Fragment f = (Fragment) v;
1270 // NB: here we ignore APClasses and Du atoms
1271 if (f.isIsomorphicTo(cap, true))
1272 {
1274 v.getAP(0).setAPClass(capAPC);
1275 }
1276 }
1277 }
1278
1279 if (embedRingsInTemplates)
1280 {
1281 try {
1283 fragSpace, ringTmplContract);
1284 } catch (DENOPTIMException e) {
1285 graph.cleanup();
1286 if (monitor!=null)
1287 {
1289 }
1290 return null;
1291 }
1292 }
1293
1294 return graph;
1295 }
1296
1297//------------------------------------------------------------------------------
1298
1300 AtomicInteger vId, List<Vertex> vertexes) throws DENOPTIMException
1301 {
1302 // We seek for the last and non-RCV vertex added to the graph
1303 Vertex lastlyAdded = null;
1304 for (int i=-1; i>-4; i--)
1305 {
1306 lastlyAdded = graph.getVertexList().get(
1307 graph.getVertexList().size()+i);
1308 if (!lastlyAdded.isRCV())
1309 break;
1310 }
1311 for (AttachmentPoint apI : lastlyAdded.getAttachmentPoints())
1312 {
1313 if (!apI.isAvailable())
1314 continue;
1315
1316 for (int j=0; j<vertexes.size(); j++)
1317 {
1318 Vertex fragJ = vertexes.get(j);
1319
1320 boolean ringClosure = false;
1321 if (graph.containsVertex(fragJ))
1322 {
1323 ringClosure = true;
1324 }
1325 for (AttachmentPoint apJ : fragJ.getAttachmentPoints())
1326 {
1327 if (apI==apJ)
1328 continue;
1329
1330 if (apI.getCutId()==apJ.getCutId())
1331 {
1332 if (ringClosure)
1333 {
1336 BondType.ANY));
1338 rcvI.setVertexId(vId.getAndIncrement());
1339 graph.appendVertexOnAP(apI, rcvI.getAP(0));
1340
1344 rcvJ.setVertexId(vId.getAndIncrement());
1345 graph.appendVertexOnAP(apJ, rcvJ.getAP(0));
1346 graph.addRing(rcvI, rcvJ);
1347 } else {
1349 fragJ.setVertexId(vId.getAndIncrement());
1350 graph.appendVertexOnAP(apI, apJ);
1351
1352 // Recursion into the branch of the graph that is
1353 // rooted onto the lastly added vertex
1355 vertexes);
1356 }
1357 }
1358 }
1359 }
1360 }
1361 }
1362
1363//------------------------------------------------------------------------------
1364
1375 public static void outputPopulationDetails(Population population,
1376 String filename, GAParameters settings, boolean printpathNames)
1377 throws DENOPTIMException
1378 {
1379 StringBuilder sb = new StringBuilder(512);
1381 sb.append(NL);
1382
1383 df.setMaximumFractionDigits(settings.getPrecisionLevel());
1384 df.setMinimumFractionDigits(settings.getPrecisionLevel());
1385
1386 // NB: we consider the configured size of the population, not the actual
1387 // size of list representing the population.
1388 String stats = "";
1389 synchronized (population)
1390 {
1391 List<Candidate> popMembers = new ArrayList<Candidate>();
1392 for (int i=0; i<settings.getPopulationSize(); i++)
1393 {
1394 Candidate mol = population.get(i);
1395 popMembers.add(mol);
1396 if (mol != null)
1397 {
1398 String mname = new File(mol.getSDFFile()).getName();
1399 if (mname != null)
1400 sb.append(String.format("%-20s", mname));
1401
1402 sb.append(String.format("%-20s",
1403 mol.getGraph().getGraphId()));
1404 sb.append(String.format("%-30s", mol.getUID()));
1405 sb.append(df.format(mol.getFitness()));
1406
1407 if (printpathNames)
1408 {
1409 sb.append(" ").append(mol.getSDFFile());
1410 }
1411
1412 sb.append(System.getProperty("line.separator"));
1413 }
1414 }
1415
1416 // calculate descriptive statistics for the population
1417 stats = getSummaryStatistics(population, settings);
1418
1419 if (settings.savePopFile())
1420 {
1421 File dest = new File(filename.replaceAll("\\.txt$", ".sdf"));
1422 DenoptimIO.writeCandidatesToFile(dest, popMembers, false);
1423 }
1424 }
1425 if (stats.trim().length() > 0)
1426 sb.append(stats);
1427 DenoptimIO.writeData(filename, sb.toString(), false);
1428
1429 sb.setLength(0);
1430 }
1431
1432//------------------------------------------------------------------------------
1433
1434 private static String getSummaryStatistics(Population popln,
1435 GAParameters settings)
1436 {
1437 double[] fitness = getFitnesses(popln);
1438 double sdev = StatUtils.stddev(fitness, true);
1439 String res = "";
1440 df.setMaximumFractionDigits(settings.getPrecisionLevel());
1441
1442 StringBuilder sb = new StringBuilder(128);
1443 sb.append(NL+NL+"#####POPULATION SUMMARY#####"+NL);
1444 int n = popln.size();
1445 sb.append(String.format("%-30s", "SIZE:"));
1446 sb.append(String.format("%12s", n));
1447 sb.append(NL);
1448 double f;
1449 f = StatUtils.max(fitness);
1450 sb.append(String.format("%-30s", "MAX:")).append(df.format(f));
1451 sb.append(NL);
1452 f = StatUtils.min(fitness);
1453 sb.append(String.format("%-30s", "MIN:")).append(df.format(f));
1454 sb.append(NL);
1455 f = StatUtils.mean(fitness);
1456 sb.append(String.format("%-30s", "MEAN:")).append(df.format(f));
1457 sb.append(NL);
1458 f = StatUtils.median(fitness);
1459 sb.append(String.format("%-30s", "MEDIAN:")).append(df.format(f));
1460 sb.append(NL);
1461 f = StatUtils.stddev(fitness, true);
1462 sb.append(String.format("%-30s", "STDDEV:")).append(df.format(f));
1463 sb.append(NL);
1464 if (sdev > 0.0001)
1465 {
1466 f = StatUtils.skewness(fitness, true);
1467 sb.append(String.format("%-30s", "SKEW:")).append(df.format(f));
1468 sb.append(NL);
1469 } else {
1470 sb.append(String.format("%-30s", "SKEW:")).append(" NaN (sdev too small)");
1471 sb.append(NL);
1472 }
1473
1474 res = sb.toString();
1475 sb.setLength(0);
1476
1477 return res;
1478 }
1479
1480//------------------------------------------------------------------------------
1481
1492 List<Candidate> eligibleParents, int number, GAParameters settings)
1493 {
1494 Candidate[] mates = new Candidate[number];
1495 switch (settings.getSelectionStrategyType())
1496 {
1497 case 1:
1498 mates = SelectionHelper.performTournamentSelection(eligibleParents,
1499 number, settings);
1500 break;
1501 case 2:
1502 mates = SelectionHelper.performRWS(eligibleParents, number, settings);
1503 break;
1504 case 3:
1505 mates = SelectionHelper.performSUS(eligibleParents, number, settings);
1506 break;
1507 case 4:
1508 mates = SelectionHelper.performRandomSelection(eligibleParents, number,
1509 settings);
1510 break;
1511 }
1512
1513 if (settings.recordMateSelection())
1514 {
1515 String matesStr="";
1516 for (int i=0; i < mates.length; i++)
1517 {
1518 if (i>0)
1519 matesStr = matesStr + settings.NL;
1520 matesStr = matesStr + mates[i].getUID();
1521 }
1522 try
1523 {
1524 DenoptimIO.writeData(settings.getMonitorFile()+".mates",
1525 matesStr, true);
1526 } catch (DENOPTIMException e)
1527 {
1528 // TODO Auto-generated catch block
1529 e.printStackTrace();
1530 }
1531 }
1532
1533 return mates;
1534 }
1535
1536//------------------------------------------------------------------------------
1537
1542 Randomizer randomizer)
1543 {
1544 List<Vertex> candidates = new ArrayList<Vertex>(
1545 g.getVertexList());
1546 candidates.removeIf(v ->
1547 v.getBuildingBlockType() == BBType.SCAFFOLD
1548 || v.getBuildingBlockType() == BBType.CAP);
1549 return randomizer.randomlyChooseOne(candidates);
1550 }
1551
1552//------------------------------------------------------------------------------
1553
1569 protected static XoverSite performFBCC(
1570 List<Candidate> eligibleParents, Population population,
1571 int[] choiceOfParents, int choiceOfXOverSites, GAParameters settings)
1572 {
1573 Candidate parentA = null;
1574 if (choiceOfParents==null)
1575 parentA = selectBasedOnFitness(eligibleParents, 1, settings)[0];
1576 else
1577 parentA = eligibleParents.get(choiceOfParents[0]);
1578
1579 if (parentA == null)
1580 return null;
1581
1584 {
1585 fsParams = (FragmentSpaceParameters)settings.getParameters(
1587 }
1588 FragmentSpace fragSpace = fsParams.getFragmentSpace();
1589 List<Candidate> matesCompatibleWithFirst = population.getXoverPartners(
1590 parentA, eligibleParents, fragSpace);
1591 if (matesCompatibleWithFirst.size() == 0)
1592 return null;
1593
1594 Candidate parentB = null;
1595 if (choiceOfParents==null)
1596 {
1597 parentB = selectBasedOnFitness(matesCompatibleWithFirst, 1,
1598 settings)[0];
1599 } else {
1600 parentB = eligibleParents.get(choiceOfParents[1]);
1601 }
1602 if (parentB == null)
1603 return null;
1604
1605 XoverSite result = null;
1606 if (choiceOfXOverSites<0)
1607 {
1608 result = settings.getRandomizer().randomlyChooseOne(
1609 population.getXoverSites(parentA, parentB));
1610 } else {
1611 result = population.getXoverSites(parentA, parentB).get(
1612 choiceOfXOverSites);
1613 }
1614 return result;
1615 }
1616
1617//------------------------------------------------------------------------------
1618
1619 public static String getPathNameToGenerationFolder(int genID,
1620 GAParameters settings)
1621 {
1622 StringBuilder sb = new StringBuilder(32);
1623
1624 int ndigits = String.valueOf(settings.getNumberOfGenerations()).length();
1625
1626 sb.append(settings.getDataDirectory()).append(FSEP).append(
1628 .append(GeneralUtils.getPaddedString(ndigits, genID));
1629
1630 return sb.toString();
1631 }
1632
1633//------------------------------------------------------------------------------
1634
1635 public static String getPathNameToGenerationDetailsFile(int genID,
1636 GAParameters settings)
1637 {
1638 StringBuilder sb = new StringBuilder(32);
1639
1640 int ndigits = String.valueOf(settings.getNumberOfGenerations()).length();
1641
1642 sb.append(settings.getDataDirectory()).append(FSEP)
1644 .append(GeneralUtils.getPaddedString(ndigits, genID))
1645 .append(FSEP)
1647 .append(GeneralUtils.getPaddedString(ndigits, genID))
1648 .append(".txt");
1649
1650 return sb.toString();
1651 }
1652
1653//------------------------------------------------------------------------------
1654
1656 {
1657 StringBuilder sb = new StringBuilder(32);
1658 sb.append(settings.getDataDirectory()).append(FSEP).append("Final");
1659 return sb.toString();
1660 }
1661
1662//------------------------------------------------------------------------------
1663
1665 GAParameters settings)
1666 {
1667 StringBuilder sb = new StringBuilder(32);
1668 sb.append(settings.getDataDirectory()).append(FSEP).append("Final")
1669 .append(FSEP).append("Final.txt");
1670 return sb.toString();
1671 }
1672
1673//------------------------------------------------------------------------------
1674
1685 protected static void outputFinalResults(Population popln,
1686 GAParameters settings) throws DENOPTIMException
1687 {
1688 String dirName = EAUtils.getPathNameToFinalPopulationFolder(settings);
1689 denoptim.files.FileUtils.createDirectory(dirName);
1690 File fileDir = new File(dirName);
1691
1692 boolean intermediateCandidatesAreOnDisk =
1693 ((FitnessParameters) settings.getParameters(
1694 ParametersType.FIT_PARAMS)).writeCandidatesOnDisk();
1695
1696 for (int i=0; i<popln.size(); i++)
1697 {
1698 Candidate c = popln.get(i);
1699 String sdfile = c.getSDFFile();
1700 String imgfile = c.getImageFile();
1701
1702 try {
1703 if (intermediateCandidatesAreOnDisk && sdfile!=null)
1704 {
1705 FileUtils.copyFileToDirectory(new File(sdfile), fileDir);
1706 } else {
1707 File candFile = new File(fileDir, c.getName()
1709 c.setSDFFile(candFile.getAbsolutePath());
1710 DenoptimIO.writeCandidateToFile(candFile, c, false);
1711 }
1712 } catch (IOException ioe) {
1713 throw new DENOPTIMException("Failed to copy file '"
1714 + sdfile + "' to '" + fileDir + "' for candidate "
1715 + c.getName(), ioe);
1716 }
1717 if (imgfile != null && intermediateCandidatesAreOnDisk)
1718 {
1719 try {
1720 FileUtils.copyFileToDirectory(new File(imgfile), fileDir);
1721 } catch (IOException ioe) {
1722 throw new DENOPTIMException("Failed to copy file '"
1723 + imgfile + "' to '" + fileDir + "' for candidate "
1724 + c.getName(), ioe);
1725 }
1726 }
1727 }
1730 settings, true);
1731 }
1732
1733//------------------------------------------------------------------------------
1734
1743 protected static void getPopulationFromFile(String filename,
1744 Population population, SizeControlledSet uniqueIDsSet,
1745 String genDir, GAParameters settings)
1746 throws DENOPTIMException, IOException
1747 {
1748 List<Candidate> candidates = DenoptimIO.readCandidates(
1749 new File(filename), true);
1750 if (candidates.size() == 0)
1751 {
1752 String msg = "Found 0 candidates in file " + filename;
1753 settings.getLogger().log(Level.SEVERE, msg);
1754 throw new DENOPTIMException(msg);
1755 }
1756
1757 for (Candidate candidate : candidates)
1758 {
1759 if (uniqueIDsSet.addNewUniqueEntry(candidate.getUID()))
1760 {
1762 int gctr = GraphUtils.getUniqueGraphIndex();
1763
1764 String molName = "M" + GeneralUtils.getPaddedString(8, ctr);
1765 candidate.setName(molName);
1766 candidate.getGraph().setGraphId(gctr);
1767 candidate.getGraph().setLocalMsg("INITIAL_POPULATION");
1768 String sdfPathName = genDir + System.getProperty("file.separator")
1770 candidate.setSDFFile(sdfPathName);
1771 candidate.setImageFile(null);
1772
1773 // Write the candidate to file as if it had been processed by fitness provider
1774 DenoptimIO.writeCandidateToFile(new File(sdfPathName),
1775 candidate, false);
1776
1777 population.add(candidate);
1778 } else {
1779 settings.getLogger().log(Level.WARNING, "Candidate from intial "
1780 + "population file '" + filename
1781 + "' is rejected because its identifier is "
1782 + "already listed among the previously visited "
1783 + "identifiers.");
1784 }
1785 }
1786
1787 if (population.isEmpty())
1788 {
1789 String msg = "Population is still empty after having processes "
1790 + candidates.size() + " candidates from file " + filename;
1791 settings.getLogger().log(Level.SEVERE, msg);
1792 throw new DENOPTIMException(msg);
1793 }
1794
1795 setVertexCounterValue(population);
1796 }
1797
1798//------------------------------------------------------------------------------
1799
1800 protected static void writeUID(String outfile, HashSet<String> lstInchi,
1801 boolean append) throws DENOPTIMException
1802 {
1803 StringBuilder sb = new StringBuilder(256);
1804 Iterator<String> iter = lstInchi.iterator();
1805
1806 boolean first = true;
1807 while(iter.hasNext())
1808 {
1809 if (first)
1810 {
1811 sb.append(iter.next());
1812 first = false;
1813 }
1814 else
1815 {
1816 sb.append(NL).append(iter.next());
1817 }
1818 }
1819
1820 DenoptimIO.writeData(outfile, sb.toString(), append);
1821 sb.setLength(0);
1822 }
1823
1824//------------------------------------------------------------------------------
1825
1833 protected static void setVertexCounterValue(Population population)
1834 throws DENOPTIMException
1835 {
1836 long val = Long.MIN_VALUE;
1837 for (Candidate popln1 : population)
1838 {
1839 DGraph g = popln1.getGraph();
1840 val = Math.max(val, g.getMaxVertexId());
1841 }
1843 }
1844
1845//------------------------------------------------------------------------------
1846
1854 protected static DGraph buildGraph(GAParameters settings)
1855 throws DENOPTIMException
1856 {
1858 if (settings.containsParameters(ParametersType.FS_PARAMS))
1859 {
1860 fsParams = (FragmentSpaceParameters)settings.getParameters(
1862 }
1863 FragmentSpace fragSpace = fsParams.getFragmentSpace();
1864
1865 DGraph graph = new DGraph();
1867
1868 // building a molecule starts by selecting a random scaffold
1869 Vertex scafVertex = fragSpace.makeRandomScaffold();
1870
1871 // add the scaffold as a vertex
1872 graph.addVertex(scafVertex);
1873 graph.setLocalMsg("NEW");
1874
1875 if (scafVertex instanceof Template
1876 && !((Template) scafVertex).getContractLevel().equals(
1878 {
1879 Monitor mnt = new Monitor();
1880 mnt.name = "IntraTemplateBuild";
1881 List<Vertex> initialMutableSites = graph.getMutableSites(
1882 settings.getExcludedMutationTypes());
1883 for (Vertex mutableSite : initialMutableSites)
1884 {
1885 // This accounts for the possibility that a mutation changes a
1886 // branch of the initial graph or deletes vertexes.
1887 if (!graph.containsOrEmbedsVertex(mutableSite))
1888 continue;
1889
1890 // TODO: need to discriminate between EmptyVertexes that
1891 // represent placeholders and those that represent property carriers
1892 // The first should always be mutated (as it happens now), but
1893 // the latter should be kept intact.
1894 // Possibly this is a case for subclassing the EmptyVertex.
1895
1896 if (!GraphOperations.performMutation(mutableSite, mnt,
1897 settings))
1898 {
1901 return null;
1902 }
1903 }
1904 }
1905
1906 // get settings //TODO: this should happen inside RunTimeParameters
1908 if (settings.containsParameters(ParametersType.RC_PARAMS))
1909 {
1910 rcParams = (RingClosureParameters)settings.getParameters(
1912 }
1913//TODO this works only for scaffolds at the moment. make the preference for
1914// fragments that lead to known closable chains operate also when fragments are
1915// the "turning point".
1918 scafVertex.getBuildingBlockId()));
1919
1920 if (scafVertex.hasFreeAP())
1921 {
1922 GraphOperations.extendGraph(scafVertex, true, false, settings);
1923 }
1924
1925 if (!(scafVertex instanceof Template)
1926 && graph.getVertexCount() == 0)
1927 {
1928 return null;
1929 }
1930
1931 graph.addCappingGroups(fragSpace);
1932 return graph;
1933 }
1934
1935//------------------------------------------------------------------------------
1936
1949 protected static boolean setupRings(Object[] res, DGraph molGraph,
1950 GAParameters settings) throws DENOPTIMException
1951 {
1952 // get settings //TODO: this should happen inside RunTimeParameters
1954 if (settings.containsParameters(ParametersType.RC_PARAMS))
1955 {
1956 rcParams = (RingClosureParameters)settings.getParameters(
1958 }
1960 if (settings.containsParameters(ParametersType.FS_PARAMS))
1961 {
1962 fsParams = (FragmentSpaceParameters)settings.getParameters(
1964 }
1965 FragmentSpace fragSpace = fsParams.getFragmentSpace();
1966
1967 if (!fragSpace.useAPclassBasedApproach())
1968 return true;
1969
1970 if (!rcParams.allowRingClosures())
1971 return true;
1972
1973 // get a atoms/bonds molecular representation (no 3D needed)
1974 ThreeDimTreeBuilder t3d = new ThreeDimTreeBuilder(settings.getLogger(),
1975 settings.getRandomizer());
1976 t3d.setAlignBBsIn3D(false);
1977 IAtomContainer mol = t3d.convertGraphTo3DAtomContainer(molGraph,true);
1978
1979 // Set rotatability property as property of IBond
1980 String rotoSpaceFile = "";
1981 if (settings.containsParameters(ParametersType.FS_PARAMS))
1982 {
1983 rotoSpaceFile = ((FragmentSpaceParameters) settings.getParameters(
1984 ParametersType.FS_PARAMS)).getRotSpaceDefFile();
1985 }
1986 RotationalSpaceUtils.defineRotatableBonds(mol, rotoSpaceFile, true,
1987 true, settings.getLogger());
1988
1989 // get the set of possible RCA combinations = ring closures
1990 CyclicGraphHandler cgh = new CyclicGraphHandler(rcParams,fragSpace);
1991
1992 //TODO: remove hard-coded variable that exclude considering all
1993 // combination of rings
1994 boolean onlyRandomCombOfRings = true;
1995
1996 if (onlyRandomCombOfRings)
1997 {
1998 List<Ring> combsOfRings = cgh.getRandomCombinationOfRings(
1999 mol, molGraph, rcParams.getMaxRingClosures());
2000 if (combsOfRings.size() > 0)
2001 {
2002 for (Ring ring : combsOfRings)
2003 {
2004 // Consider the crowding probability
2005 double shot = settings.getRandomizer().nextDouble();
2006 int crowdOnH = EAUtils.getCrowdedness(
2007 ring.getHeadVertex().getEdgeToParent().getSrcAP(),
2008 true);
2009 int crowdOnT = EAUtils.getCrowdedness(
2010 ring.getTailVertex().getEdgeToParent().getSrcAP(),
2011 true);
2012 double crowdProbH = EAUtils.getCrowdingProbability(crowdOnH,
2013 settings);
2014 double crowdProbT = EAUtils.getCrowdingProbability(crowdOnT,
2015 settings);
2016
2017 if (shot < crowdProbH && shot < crowdProbT)
2018 {
2019 molGraph.addRing(ring);
2020 }
2021 }
2022 }
2023 }
2024 else
2025 {
2026 ArrayList<List<Ring>> allCombsOfRings =
2027 cgh.getPossibleCombinationOfRings(mol, molGraph);
2028
2029 // Keep closable chains that are relevant for chelate formation
2030 if (rcParams.buildChelatesMode())
2031 {
2032 ArrayList<List<Ring>> toRemove = new ArrayList<>();
2033 for (List<Ring> setRings : allCombsOfRings)
2034 {
2035 if (!cgh.checkChelatesGraph(molGraph,setRings))
2036 {
2037 toRemove.add(setRings);
2038 }
2039 }
2040
2041 allCombsOfRings.removeAll(toRemove);
2042 if (allCombsOfRings.isEmpty())
2043 {
2044 String msg = "Setup Rings: no combination of rings.";
2045 settings.getLogger().log(Level.INFO, msg);
2046 return false;
2047 }
2048 }
2049
2050 // Select a combination, if any still available
2051 int sz = allCombsOfRings.size();
2052 if (sz > 0)
2053 {
2054 List<Ring> selected = new ArrayList<>();
2055 if (sz == 1)
2056 {
2057 selected = allCombsOfRings.get(0);
2058 }
2059 else
2060 {
2061 int selId = settings.getRandomizer().nextInt(sz);
2062 selected = allCombsOfRings.get(selId);
2063 }
2064
2065 // append new rings to existing list of rings in graph
2066 for (Ring ring : selected)
2067 {
2068 molGraph.addRing(ring);
2069 }
2070 }
2071 }
2072
2073 // Update the IAtomContainer representation
2074 //DENOPTIMMoleculeUtils.removeUsedRCA(mol,molGraph);
2075 // Done already at t3d.convertGraphTo3DAtomContainer
2076 if (res!=null)
2077 {
2078 res[2] = mol;
2079 }
2080 // Update the SMILES representation
2081 if (res!=null)
2082 {
2083 String molsmiles = MoleculeUtils.getSMILESForMolecule(mol,
2084 settings.getLogger());
2085 if (molsmiles == null)
2086 {
2087 String msg = "Evaluation of graph: SMILES is null! "
2088 + molGraph.toString();
2089 settings.getLogger().log(Level.INFO, msg);
2090 molsmiles = "FAIL: NO SMILES GENERATED";
2091 }
2092 res[1] = molsmiles;
2093 }
2094
2095 // Update the INCHI key representation
2096 if (res!=null)
2097 {
2098 String inchikey = MoleculeUtils.getInChIKeyForMolecule(mol,
2099 settings.getLogger());
2100 if (inchikey == null)
2101 {
2102 String msg = "Evaluation of graph: INCHI is null!";
2103 settings.getLogger().log(Level.INFO, msg);
2104 inchikey = "UNDEFINED";
2105 }
2106 res[0] = inchikey;
2107 }
2108
2109 return true;
2110 }
2111
2112//------------------------------------------------------------------------------
2113
2121 protected static boolean containsMolecule(Population mols, String molcode)
2122 {
2123 if(mols.isEmpty())
2124 return false;
2125
2126 for (Candidate mol : mols)
2127 {
2128 if (mol.getUID().compareToIgnoreCase(molcode) == 0)
2129 {
2130 return true;
2131 }
2132 }
2133 return false;
2134 }
2135
2136//------------------------------------------------------------------------------
2137
2144 protected static double[] getFitnesses(Population mols)
2145 {
2146 int k = mols.size();
2147 double[] arr = new double[k];
2148
2149 for (int i=0; i<k; i++)
2150 {
2151 arr[i] = mols.get(i).getFitness();
2152 }
2153 return arr;
2154 }
2155
2156//------------------------------------------------------------------------------
2157
2165 protected static double getPopulationSD(Population molPopulation)
2166 {
2167 double[] fitvals = getFitnesses(molPopulation);
2168 return StatUtils.stddev(fitvals, true);
2169 }
2170
2171//------------------------------------------------------------------------------
2172
2185 public static double getGrowthProbabilityAtLevel(int level, int scheme,
2186 double lambda, double sigmaOne, double sigmaTwo)
2187 {
2188 return getProbability(level, scheme, lambda, sigmaOne, sigmaTwo);
2189 }
2190
2191//------------------------------------------------------------------------------
2192
2205 public static double getMolSizeProbability(DGraph graph,
2206 GAParameters settings)
2207 {
2208 if (!settings.useMolSizeBasedProb())
2209 return 1.0;
2210 int scheme = settings.getMolGrowthProbabilityScheme();
2211 double lambda =settings.getMolGrowthMultiplier();
2212 double sigmaOne = settings.getMolGrowthFactorSteepSigma();
2213 double sigmaTwo = settings.getMolGrowthFactorMiddleSigma();
2214 return getMolSizeProbability(graph, scheme, lambda, sigmaOne, sigmaTwo);
2215 }
2216
2217//------------------------------------------------------------------------------
2218
2231 public static double getMolSizeProbability(DGraph graph,
2232 int scheme, double lambda, double sigmaOne, double sigmaTwo)
2233 {
2234 return getProbability(graph.getHeavyAtomsCount(), scheme, lambda,
2235 sigmaOne, sigmaTwo);
2236 }
2237
2238//------------------------------------------------------------------------------
2239
2250 public static double getProbability(double value,
2251 int scheme, double lambda, double sigmaOne, double sigmaTwo)
2252 {
2253 double prob = 1.0;
2254 if (scheme == 0)
2255 {
2256 double f = Math.exp(-1.0 * value * lambda);
2257 prob = 1 - ((1-f)/(1+f));
2258 }
2259 else if (scheme == 1)
2260 {
2261 prob = 1.0 - Math.tanh(lambda * value);
2262 }
2263 else if (scheme == 2)
2264 {
2265 prob = 1.0-1.0/(1.0 + Math.exp(-sigmaOne * (value - sigmaTwo)));
2266 }
2267 else if (scheme == 3)
2268 {
2269 prob = 1.0;
2270 }
2271 return prob;
2272 }
2273
2274//------------------------------------------------------------------------------
2275
2282 public static double getGrowthByLevelProbability(int level,
2283 GAParameters settings)
2284 {
2285 if (!settings.useLevelBasedProb())
2286 return 1.0;
2287 int scheme = settings.getGrowthProbabilityScheme();
2288 double lambda =settings.getGrowthMultiplier();
2289 double sigmaOne = settings.getGrowthFactorSteepSigma();
2290 double sigmaTwo = settings.getGrowthFactorMiddleSigma();
2291 return getGrowthProbabilityAtLevel(level, scheme, lambda, sigmaOne,
2292 sigmaTwo);
2293 }
2294
2295//------------------------------------------------------------------------------
2296
2306 GAParameters settings)
2307 {
2308 int scheme = settings.getCrowdingProbabilityScheme();
2309 double lambda =settings.getCrowdingMultiplier();
2310 double sigmaOne = settings.getCrowdingFactorSteepSigma();
2311 double sigmaTwo = settings.getCrowdingFactorMiddleSigma();
2312 return getCrowdingProbability(ap, scheme, lambda, sigmaOne, sigmaTwo);
2313 }
2314
2315//------------------------------------------------------------------------------
2316
2330 public static double getCrowdingProbability(int crowdedness,
2331 GAParameters settings)
2332 {
2333 int scheme = settings.getCrowdingProbabilityScheme();
2334 double lambda =settings.getCrowdingMultiplier();
2335 double sigmaOne = settings.getCrowdingFactorSteepSigma();
2336 double sigmaTwo = settings.getCrowdingFactorMiddleSigma();
2337 return getCrowdingProbabilityForCrowdedness(crowdedness, scheme, lambda,
2338 sigmaOne, sigmaTwo);
2339 }
2340
2341//------------------------------------------------------------------------------
2342
2350 public static int getCrowdedness(AttachmentPoint ap)
2351 {
2352 return getCrowdedness(ap,false);
2353 }
2354
2355//------------------------------------------------------------------------------
2356
2366 public static int getCrowdedness(AttachmentPoint ap,
2367 boolean ignoreFreeRCVs)
2368 {
2369 if (ap.getOwner() instanceof EmptyVertex)
2370 {
2371 return 0;
2372 }
2373 int crowdness = 0;
2374 DGraph g = ap.getOwner().getGraphOwner();
2376 {
2377 if (oap.getAtomPositionNumber() == ap.getAtomPositionNumber()
2378 && !oap.isAvailableThroughout()
2379 && oap.getLinkedAP().getOwner()
2380 .getBuildingBlockType() != BBType.CAP)
2381 {
2382 if (ignoreFreeRCVs && oap.getLinkedAP().getOwner().isRCV())
2383 {
2384 if (g.getUsedRCVertices().contains(oap.getLinkedAP().getOwner()))
2385 crowdness = crowdness + 1;
2386 } else {
2387 crowdness = crowdness + 1;
2388 }
2389 }
2390 }
2391 return crowdness;
2392 }
2393
2394//------------------------------------------------------------------------------
2395
2408 public static double getCrowdingProbability(AttachmentPoint ap,
2409 int scheme,
2410 double lambda, double sigmaOne, double sigmaTwo)
2411 {
2412 //Applies only to molecular fragments
2413 if (ap.getOwner() instanceof Fragment == false)
2414 {
2415 return 1.0;
2416 }
2417 int crowdness = getCrowdedness(ap);
2418 return getCrowdingProbabilityForCrowdedness(crowdness, scheme, lambda,
2419 sigmaOne, sigmaTwo);
2420 }
2421
2422//------------------------------------------------------------------------------
2423
2433 public static double getCrowdingProbabilityForCrowdedness(int crowdedness,
2434 int scheme,
2435 double lambda, double sigmaOne, double sigmaTwo)
2436 {
2437 return getProbability(crowdedness, scheme, lambda, sigmaOne, sigmaTwo);
2438 }
2439
2440//------------------------------------------------------------------------------
2441
2450 protected static boolean foundForbiddenEnd(DGraph molGraph,
2451 FragmentSpaceParameters fsParams)
2452 {
2453 List<Vertex> vertices = molGraph.getVertexList();
2454 Set<APClass> classOfForbEnds = fsParams.getFragmentSpace()
2456 for (Vertex vtx : vertices)
2457 {
2458 List<AttachmentPoint> daps = vtx.getAttachmentPoints();
2459 for (AttachmentPoint dp : daps)
2460 {
2461 if (dp.isAvailable())
2462 {
2463 APClass apClass = dp.getAPClass();
2464 if (classOfForbEnds.contains(apClass))
2465 {
2466 String msg = "Forbidden free AP for Vertex: "
2467 + vtx.getVertexId()
2468 + " MolId: " + (vtx.getBuildingBlockId() + 1)
2469 + " Ftype: " + vtx.getBuildingBlockType()
2470 + "\n"+ molGraph+" \n "
2471 + " AP class: " + apClass;
2472 fsParams.getLogger().log(Level.WARNING, msg);
2473 return true;
2474 }
2475 }
2476 }
2477 }
2478 return false;
2479 }
2480
2481//------------------------------------------------------------------------------
2482
2483 protected static void readUID(String infile, HashSet<String> lstInchi)
2484 throws DENOPTIMException
2485 {
2486 ArrayList<String> lst = DenoptimIO.readList(infile);
2487 for (String str:lst)
2488 lstInchi.add(str);
2489 lst.clear();
2490 }
2491
2492//------------------------------------------------------------------------------
2493
2519 //NB: we return a List to retain ordering of the items, but the list must
2520 // not contain redundancies, i.e., lists of AP pairs that are made of the
2521 // same set of AP pairs.
2522 public static List<List<RelatedAPPair>> searchRingFusionSites(
2523 DGraph graph, GAParameters gaParams) throws DENOPTIMException
2524 {
2526 if (gaParams.containsParameters(ParametersType.RC_PARAMS))
2527 {
2528 rcParams = (RingClosureParameters)gaParams.getParameters(
2530 }
2532 if (gaParams.containsParameters(ParametersType.FS_PARAMS))
2533 {
2534 fsParams = (FragmentSpaceParameters)gaParams.getParameters(
2536 }
2537 FragmentSpace fragSpace = fsParams.getFragmentSpace();
2538 Randomizer rng = gaParams.getRandomizer();
2539 boolean projectOnSymmetricAPs = rng.nextBoolean(
2540 gaParams.getSymmetryProbability());
2541 // NB: imposeSymmetryOnAPsOfClass is evaluated inside the
2542 // method searchRingFusionSites
2543 Logger logger = gaParams.getLogger();
2544 return searchRingFusionSites(graph, fragSpace, rcParams,
2545 projectOnSymmetricAPs, logger, rng);
2546 }
2547
2548//------------------------------------------------------------------------------
2549
2575 //NB: we return a List to retain ordering of the items, but the list must
2576 // not contain redundancies, i.e., lists of AP pairs that are made of the
2577 // same set of AP pairs.
2578 public static List<List<RelatedAPPair>> searchRingFusionSites(
2579 DGraph graph, FragmentSpace fragSpace,
2580 RingClosureParameters rcParams, boolean projectOnSymmetricAPs,
2581 Logger logger, Randomizer rng) throws DENOPTIMException
2582 {
2583 // Prepare the empty collector of combinations
2584 List<List<RelatedAPPair>> result = new ArrayList<List<RelatedAPPair>>();
2585
2586 // Most of the work is done on a clone to prevent any modification of the
2587 // 3D molecular representation of the graph, which is here rebuilt in
2588 // a crude way because we only need the connectivity.
2589 DGraph tmpGraph = graph.clone();
2590
2591 // Keep track of which vertexes come from the original graph. We need
2592 // to distinguish them from the capping groups we add here.
2593 Set<Long> originalVertexIDs = new HashSet<Long>();
2594 tmpGraph.getVertexList().stream()
2595 .forEach(v -> originalVertexIDs.add(v.getVertexId()));
2596
2597 // We add capping groups to facilitate the search for substructures
2598 // otherwise we have to write SMARTS that match systems with potentially
2599 // unsaturated valences, and that is a mess.
2600 // Here we change both graph and molecular representation, but it all
2601 // happens on the tmp copy, so the original graph and mol representation
2602 // remain intact. Also, note that the order of atoms does not have a
2603 // role because we only use the position of the atom in the list of atoms
2604 // within the tmp system, and then we use the reference to the
2605 // AP to project the information back into the original system.
2606 tmpGraph.addCappingGroups(fragSpace);
2607
2608 // Get a molecular representation
2609 ThreeDimTreeBuilder t3d = new ThreeDimTreeBuilder(logger, rng);
2610 t3d.setAlignBBsIn3D(false); //3D not needed
2611 IAtomContainer mol = t3d.convertGraphTo3DAtomContainer(tmpGraph, true);
2612
2613 // Search for potential half-ring environments, i.e., sets of atoms
2614 // that belongs to a cyclic system and could hold a chord that would
2615 // define the fused ring.
2616 Map<String, String> smarts = new HashMap<String, String>();
2617 for (BridgeHeadFindingRule rule : rcParams.getBridgeHeadFindingRules())
2618 {
2619 smarts.put(rule.getName(), rule.getSMARTS());
2620 }
2621
2622 ManySMARTSQuery msq = new ManySMARTSQuery(mol, smarts);
2623 if (msq.hasProblems())
2624 {
2625 throw new DENOPTIMException(msq.getMessage());
2626 }
2627 Map<SymmetricSetWithMode,List<RelatedAPPair>> symmRelatedBridgeHeadAPs =
2628 new HashMap<SymmetricSetWithMode,List<RelatedAPPair>>();
2629 List<RelatedAPPair> symBridgeHeadAPs = new ArrayList<RelatedAPPair>();
2630 List<RelatedAPPair> asymBridgeHeadAPs = new ArrayList<RelatedAPPair>();
2631 for (BridgeHeadFindingRule rule : rcParams.getBridgeHeadFindingRules())
2632 {
2633 if (msq.getNumMatchesOfQuery(rule.getName()) == 0)
2634 {
2635 continue;
2636 }
2637
2638 // Get bridge-head atoms
2639 Mappings halfRingAtms = msq.getMatchesOfSMARTS(rule.getName());
2640 // We use a string to facilitate detection of pairs of ids
2641 // irrespectively on the order of ids, i.e., 1-2 vs. 2-1.
2642 Set<String> doneIdPairs = new HashSet<String>();
2643 for (int[] idSubstructure : halfRingAtms)
2644 {
2645 if (idSubstructure.length<2)
2646 {
2647 throw new Error("SMARTS for matching half-ring pattern '"
2648 + rule.getName()
2649 + "' has identified " + idSubstructure.length
2650 + " atoms "
2651 + "instead of at least 2. Modify rule to make it "
2652 + "find 2 or more atoms.");
2653 }
2654
2655 // Potential bridge-head atoms
2656 int[] ids = new int[] {
2657 idSubstructure[rule.getBridgeHeadPositions()[0]],
2658 idSubstructure[rule.getBridgeHeadPositions()[1]]};
2659
2660 IAtom bhA = mol.getAtom(ids[0]);
2661 IAtom bhB = mol.getAtom(ids[1]);
2662
2663 // Avoid duplicate pairs with inverted AP identity
2664 String idPairIdentifier = "";
2665 if (ids[0]<ids[1])
2666 idPairIdentifier = ids[0]+"_"+ids[1];
2667 else
2668 idPairIdentifier = ids[1]+"_"+ids[0];
2669 if (doneIdPairs.contains(idPairIdentifier))
2670 continue;
2671 doneIdPairs.add(idPairIdentifier);
2672
2673 // Bridge-head atoms must have attachment points
2674 if (bhA.getProperty(DENOPTIMConstants.ATMPROPAPS)==null
2675 || bhB.getProperty(DENOPTIMConstants.ATMPROPAPS)==null)
2676 continue;
2677 if (bhA.getProperty(DENOPTIMConstants.ATMPROPVERTEXID)==null
2678 || bhB.getProperty(DENOPTIMConstants.ATMPROPVERTEXID)==null)
2679 throw new IllegalStateException("Atoms in 3d molecular "
2680 + "models of graph objects must have the "
2681 + DENOPTIMConstants.ATMPROPVERTEXID + " property.");
2682
2683 long vrtxIdA = (Long)
2684 bhA.getProperty(DENOPTIMConstants.ATMPROPVERTEXID);
2685 long vrtxIdB = (Long)
2686 bhB.getProperty(DENOPTIMConstants.ATMPROPVERTEXID);
2687
2688 // Each AP on each side can be used
2689 @SuppressWarnings("unchecked")
2690 List<AttachmentPoint> apsOnA = (List<AttachmentPoint>)
2691 bhA.getProperty(DENOPTIMConstants.ATMPROPAPS);
2692 @SuppressWarnings("unchecked")
2693 List<AttachmentPoint> apsOnB = (List<AttachmentPoint>)
2694 bhB.getProperty(DENOPTIMConstants.ATMPROPAPS);
2695 for (int iAPA=0; iAPA<apsOnA.size(); iAPA++)
2696 {
2697 AttachmentPoint copyOfApA = apsOnA.get(iAPA);
2698
2699 // for extreme debug only
2700 /*
2701 System.out.println(rule.getName()+" "+idPairIdentifier+" "
2702 +MoleculeUtils.getAtomRef(bhA, mol)+"-"
2703 +MoleculeUtils.getAtomRef(bhB, mol)+" "
2704 +copyOfApA.getIndexInOwner()
2705 +" in "+copyOfApA.getOwner());
2706 */
2707
2708 if (!canBeUsedForRingFusion(copyOfApA, originalVertexIDs,
2709 fragSpace))
2710 continue;
2711 for (int iAPB=0; iAPB<apsOnB.size(); iAPB++)
2712 {
2713 AttachmentPoint copyOfApB = apsOnB.get(iAPB);
2714
2715 // for extreme debug only
2716 /*
2717 System.out.println(" "+idPairIdentifier+" "
2718 +MoleculeUtils.getAtomRef(bhA, mol)+"-"
2719 +MoleculeUtils.getAtomRef(bhB, mol)+" "
2720 +copyOfApA.getIndexInOwner()
2721 +" in "+copyOfApA.getOwner()
2722 + "--- "
2723 +copyOfApB.getIndexInOwner()
2724 +" in "+copyOfApB.getOwner());
2725 */
2726
2727 if (!canBeUsedForRingFusion(copyOfApB, originalVertexIDs,
2728 fragSpace))
2729 continue;
2730
2731 // Now take the references to the actual APs
2732 AttachmentPoint apA = tmpGraph.getVertexWithId(vrtxIdA)
2733 .getAPWithId(copyOfApA.getID());
2734 AttachmentPoint apB = tmpGraph.getVertexWithId(vrtxIdB)
2735 .getAPWithId(copyOfApB.getID());
2736 if (apA==null || apB==null)
2737 continue;
2738
2739 // Now we have identified a pair of APs suitable to ring fusion
2740 RelatedAPPair pair = new RelatedAPPair(apA, apB, rule,
2741 rule.getName());
2742
2743 //Record symmetric relations
2744 SymmetricAPs symInA = apA.getOwner().getSymmetricAPs(apA);
2745 SymmetricAPs symInB = apB.getOwner().getSymmetricAPs(apB);
2746 if (symInA.size()!=0 && symInB.size()!=0)
2747 {
2748 if (symInA==symInB)
2749 {
2750 storePairsSymmetricRelations(pair, symInA,
2751 symmRelatedBridgeHeadAPs);
2752 } else {
2753 storePairsSymmetricRelations(pair, symInA,
2754 symmRelatedBridgeHeadAPs);
2755 storePairsSymmetricRelations(pair, symInB,
2756 symmRelatedBridgeHeadAPs);
2757 }
2758 symBridgeHeadAPs.add(pair);
2759 } else {
2760 asymBridgeHeadAPs.add(pair);
2761 }
2762 }
2763 }
2764 }
2765 }
2766 if (asymBridgeHeadAPs.size()==0 && symBridgeHeadAPs.size()==0)
2767 {
2768 return result;
2769 }
2770
2771 // Collect potential set of pairs of APs that can be used to create
2772 // fused ring systems accounting for symmetric AP relations.
2773 List<List<RelatedAPPair>> candidateBridgeHeadAPPairs =
2774 new ArrayList<List<RelatedAPPair>>();
2775 if (symmRelatedBridgeHeadAPs.size()>0)
2776 {
2777 for (SymmetricSetWithMode key : symmRelatedBridgeHeadAPs.keySet())
2778 {
2779 List<RelatedAPPair> chosenSymSet =
2780 symmRelatedBridgeHeadAPs.get(key);
2781
2782 @SuppressWarnings("unchecked")
2783 SymmetricSet<AttachmentPoint> symmRelatedAPs =
2784 (SymmetricSet<AttachmentPoint>) key.getItems();
2785 boolean apcImposedSymm = fragSpace.imposeSymmetryOnAPsOfClass(
2786 symmRelatedAPs.get(0).getAPClass());
2787
2788 if (projectOnSymmetricAPs || apcImposedSymm)
2789 {
2790 // We try to get the biggest combination (k is the size)
2791 // but we do limit to avoid combinatorial explosion.
2792 for (int k=Math.min(chosenSymSet.size(), 6); k>0; k--)
2793 {
2794 // Generate combinations that use non-overlapping pairs of APs
2795 List<List<RelatedAPPair>> combs = combineRelatedAPPair(
2796 chosenSymSet, k, 50);
2797 //TODO: make limit of combinations tuneable?
2798
2799 if (combs.size()>0)
2800 {
2801 // We keep only combinations that are not already
2802 // among previously known ones
2803 for (List<RelatedAPPair> comb : combs)
2804 {
2805 boolean isNew = true;
2806 for (List<RelatedAPPair> knownComb :
2807 candidateBridgeHeadAPPairs)
2808 {
2809 if (knownComb.containsAll(comb)
2810 && comb.containsAll(knownComb))
2811 {
2812 isNew = false;
2813 break;
2814 }
2815 }
2816 if (isNew)
2817 {
2818 candidateBridgeHeadAPPairs.add(comb);
2819 for (RelatedAPPair pair : comb)
2820 symBridgeHeadAPs.remove(pair);
2821 }
2822 }
2823 break;
2824 }
2825 }
2826 }
2827 }
2828 // Add left over pairs, if any.
2829 for (RelatedAPPair pair : symBridgeHeadAPs)
2830 {
2831 List<RelatedAPPair> single = new ArrayList<RelatedAPPair>();
2832 single.add(pair);
2833 candidateBridgeHeadAPPairs.add(single);
2834 }
2835 }
2836 for (RelatedAPPair pair : asymBridgeHeadAPs)
2837 {
2838 List<RelatedAPPair> single = new ArrayList<RelatedAPPair>();
2839 single.add(pair);
2840 candidateBridgeHeadAPPairs.add(single);
2841 }
2842
2843 // Project ring fusions into the actual graph (considering symmetry)
2844 for (List<RelatedAPPair> combOnTmpGraph : candidateBridgeHeadAPPairs)
2845 {
2846 List<RelatedAPPair> combOnOriginalGraph =
2847 new ArrayList<RelatedAPPair>();
2848 for (RelatedAPPair pairOnTmpGraph : combOnTmpGraph)
2849 {
2850 Vertex headVertexOnGraph = graph.getVertexAtPosition(
2851 tmpGraph.indexOf(pairOnTmpGraph.apA.getOwner()));
2852 int apHeadID = pairOnTmpGraph.apA.getIndexInOwner();
2853 List<Vertex> symHeadVrts = graph.getSymVerticesForVertex(
2854 headVertexOnGraph);
2855 if (symHeadVrts.size()==0)
2856 symHeadVrts.add(headVertexOnGraph);
2857
2858 Vertex tailVertexOnGraph = graph.getVertexAtPosition(
2859 tmpGraph.indexOf(pairOnTmpGraph.apB.getOwner()));
2860 int apTailID = pairOnTmpGraph.apB.getIndexInOwner();
2861 List<Vertex> symTailVrts = graph.getSymVerticesForVertex(
2862 tailVertexOnGraph);
2863 if (symTailVrts.size()==0)
2864 symTailVrts.add(tailVertexOnGraph);
2865
2866 int numPairs = Math.min(symHeadVrts.size(), symTailVrts.size());
2867 for (int iPair=0; iPair<numPairs; iPair++)
2868 {
2869 RelatedAPPair pairOnOriginalGraph = new RelatedAPPair(
2870 symHeadVrts.get(iPair).getAP(apHeadID),
2871 symTailVrts.get(iPair).getAP(apTailID),
2872 pairOnTmpGraph.property,
2873 pairOnTmpGraph.propID);
2874 combOnOriginalGraph.add(pairOnOriginalGraph);
2875 }
2876 }
2877 result.add(combOnOriginalGraph);
2878 }
2879 return result;
2880 }
2881
2882//------------------------------------------------------------------------------
2883
2884 private static List<List<RelatedAPPair>> combineRelatedAPPair(
2885 List<RelatedAPPair> pool, int k, int limit)
2886 {
2887 List<RelatedAPPair> tmp = new ArrayList<RelatedAPPair>();
2888 List<List<RelatedAPPair>> allCombs = new ArrayList<List<RelatedAPPair>>();
2889 combineRelatedAPPairUtil(pool, 0, k, tmp, allCombs, limit);
2890 return allCombs;
2891 }
2892
2893//------------------------------------------------------------------------------
2894
2895 private static void combineRelatedAPPairUtil(List<RelatedAPPair> pool,
2896 int left, int k,
2897 List<RelatedAPPair> tmp,
2898 List<List<RelatedAPPair>> allCombs, int limit)
2899 {
2900 // PRevent combinatorial explosion: stop if the number of combinations
2901 // grown above the limit
2902 if (allCombs.size()>=limit)
2903 return;
2904
2905 // For last iteration: save answer
2906 if (k == 0)
2907 {
2908 if (!apPairsAreOverlapping(tmp))
2909 {
2910 List<RelatedAPPair> oneComb = new ArrayList<RelatedAPPair>(tmp);
2911 allCombs.add(oneComb);
2912 }
2913 return;
2914 }
2915 // In normal iteration, do recursion
2916 for (int i=left; i<pool.size(); ++i)
2917 {
2918 RelatedAPPair next = pool.get(i);
2919 if (shareAPs(next, tmp))
2920 {
2921 continue;
2922 }
2923 tmp.add(next);
2924 combineRelatedAPPairUtil(pool, i + 1, k-1, tmp, allCombs, limit);
2925 tmp.remove(tmp.size() - 1);
2926 }
2927 }
2928
2929//------------------------------------------------------------------------------
2930
2932 SymmetricAPs symAPs,
2933 Map<SymmetricSetWithMode,List<RelatedAPPair>> storage)
2934 {
2935 SymmetricSetWithMode key = new SymmetricSetWithMode(symAPs, pair.propID);
2936 if (storage.containsKey(key))
2937 {
2938 storage.get(key).add(pair);
2939 } else {
2940 List<RelatedAPPair> lst = new ArrayList<RelatedAPPair>();
2941 lst.add(pair);
2942 storage.put(key, lst);
2943 }
2944 }
2945
2946//------------------------------------------------------------------------------
2947
2956 public static Boolean apPairsAreOverlapping(Iterable<RelatedAPPair> pairs)
2957 {
2958 Set<AttachmentPoint> aps = new HashSet<AttachmentPoint>();
2959
2960 for (RelatedAPPair pair : pairs)
2961 {
2962 if (aps.contains(pair.apA) || aps.contains(pair.apB))
2963 {
2964 return true;
2965 }
2966 aps.add(pair.apA);
2967 aps.add(pair.apB);
2968 }
2969 return false;
2970 }
2971
2972//------------------------------------------------------------------------------
2973
2982 public static Boolean shareAPs(RelatedAPPair pairA,
2983 Iterable<RelatedAPPair> lstB)
2984 {
2985 Set<AttachmentPoint> aps = new HashSet<AttachmentPoint>();
2986 for (RelatedAPPair pairB : lstB)
2987 {
2988 aps.add(pairB.apA);
2989 aps.add(pairB.apB);
2990 }
2991 return aps.contains(pairA.apA) || aps.contains(pairA.apB);
2992 }
2993
2994//------------------------------------------------------------------------------
2995
3018 private static boolean canBeUsedForRingFusion(AttachmentPoint ap,
3019 Set<Long> originalVertexIDs, FragmentSpace fs)
3020 {
3021 if (ap.isAvailableThroughout()
3022 || !originalVertexIDs.contains(
3024 {
3025 if (fs.getRCCompatibilityMatrix().containsKey(ap.getAPClass()))
3026 return true;
3027 }
3028 return false;
3029 }
3030
3031//------------------------------------------------------------------------------
3032
3045 public static List<Vertex> getUsableAromaticBridges(
3046 String elInIncomingFrag, int[] allowedLengths,
3047 FragmentSpace fragSpace)
3048 {
3049 List<Vertex> usableBridgesOriginals =
3050 fragSpace.getVerticesWithAPClassStartingWith(elInIncomingFrag);
3051 List<Vertex> usableBridges = new ArrayList<Vertex>();
3052 final String rootAPC = elInIncomingFrag;
3053 for (Vertex bridge : usableBridgesOriginals)
3054 {
3055 IAtomContainer iacFrag = bridge.getIAtomContainer();
3056 List<Integer> atomIDs = new ArrayList<Integer>();
3057 bridge.getAttachmentPoints()
3058 .stream()
3059 .filter(ap -> ap.getAPClass().getRule().startsWith(
3060 rootAPC))
3061 .forEach(ap -> atomIDs.add(ap.getAtomPositionNumber()));
3062 ShortestPaths sp = new ShortestPaths(iacFrag, iacFrag.getAtom
3063 (atomIDs.get(0)));
3064 List<IAtom> path = new ArrayList<IAtom>(Arrays.asList(
3065 sp.atomsTo(atomIDs.get(1))));
3066 if (IntStream.of(allowedLengths).anyMatch(x -> x == path.size()))
3067 {
3068 Vertex clone = bridge.clone();
3070 path.size());
3071 usableBridges.add(clone);
3072 }
3073 }
3074 return usableBridges;
3075 }
3076
3077//------------------------------------------------------------------------------
3078
3089 public static List<Vertex> getUsableAliphaticBridges(APClass apcA,
3090 APClass apcB, int[] allowedLengths, FragmentSpace fragSpace)
3091 {
3092 List<Vertex> usableBridges = new ArrayList<Vertex>();
3093
3094 List<APClass> compatApClassesA = fragSpace.getCompatibleAPClasses(apcA);
3095 List<APClass> compatApClassesB = fragSpace.getCompatibleAPClasses(apcB);
3096 for (APClass compatA : compatApClassesA)
3097 {
3098 for (APClass compatB : compatApClassesB)
3099 {
3100 boolean sameAPC = compatA.equals(compatB);
3101 Map<APClass,Integer> apFingerprint =
3102 new HashMap<APClass,Integer>();
3103 if (sameAPC)
3104 {
3105 apFingerprint.put(compatA,2);
3106 } else {
3107 apFingerprint.put(compatA,1);
3108 apFingerprint.put(compatB,1);
3109 }
3110 for (Vertex bridge : fragSpace.getVerticesWithAPFingerprint(
3111 apFingerprint))
3112 {
3113 IAtomContainer iacFrag = bridge.getIAtomContainer();
3114
3115 // Identify APs that can be used for each side
3116 List<AttachmentPoint> apsForA = new ArrayList<AttachmentPoint>();
3117 List<AttachmentPoint> apsForB = new ArrayList<AttachmentPoint>();
3118 for (AttachmentPoint apOnBridge : bridge.getAttachmentPoints())
3119 {
3120 if (compatA.equals(apOnBridge.getAPClass()))
3121 apsForA.add(apOnBridge);
3122 if (compatB.equals(apOnBridge.getAPClass()))
3123 apsForB.add(apOnBridge);
3124 }
3125
3126 // Find combinations of usable APs
3127 for (AttachmentPoint apForA : apsForA)
3128 {
3129 ShortestPaths sp = new ShortestPaths(iacFrag,
3130 iacFrag.getAtom(apForA.getAtomPositionNumber()));
3131 for (AttachmentPoint apForB : apsForB)
3132 {
3133 if (apForA.equals(apForB))
3134 continue;
3135 // Retains only combinations of allowed length
3136 List<IAtom> path = new ArrayList<IAtom>(
3137 Arrays.asList(sp.atomsTo(
3138 apForB.getAtomPositionNumber())));
3139 if (IntStream.of(allowedLengths).anyMatch(
3140 x -> x == path.size()))
3141 {
3142 Vertex clone = bridge.clone();
3143 clone.setProperty(
3145 path.size());
3146 clone.setProperty(
3148 apForA.getIndexInOwner());
3149 clone.setProperty(
3151 apForB.getIndexInOwner());
3152 usableBridges.add(clone);
3153 }
3154 }
3155 }
3156 }
3157 }
3158 }
3159 return usableBridges;
3160 }
3161
3162//------------------------------------------------------------------------------
3163
3164}
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 boolean prepareMolToFragmentation(IAtomContainer mol, FragmenterParameters settings, int index)
Do any pre-processing on a IAtomContainer meant to be fragmented.
static Vertex getRCVForAP(AttachmentPoint ap, APClass rcvApClass)
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:2982
static void outputFinalResults(Population popln, GAParameters settings)
Saves the final results to disk.
Definition: EAUtils.java:1685
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:2282
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:2330
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:1299
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:1491
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:1059
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:1949
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:3018
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:1743
static void writeUID(String outfile, HashSet< String > lstInchi, boolean append)
Definition: EAUtils.java:1800
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:2185
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:1033
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:2250
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:3089
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:1569
static String getPathNameToFinalPopulationFolder(GAParameters settings)
Definition: EAUtils.java:1655
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:1111
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:2305
static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol, List< CuttingRule > cuttingRules, Logger logger, ScaffoldingPolicy scaffoldingPolicy, double linearAngleLimit, boolean embedRingsInTemplates, ContractLevel ringTmplContract, FragmentSpace fragSpace, Monitor monitor)
Converts a molecule into a DGraph by fragmentation and re-assembling of the fragments.
Definition: EAUtils.java:1145
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:2450
static List< List< RelatedAPPair > > searchRingFusionSites(DGraph graph, GAParameters gaParams)
Definition: EAUtils.java:2522
static void setVertexCounterValue(Population population)
Set the Vertex counter value according to the largest value found in the given population.
Definition: EAUtils.java:1833
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:1854
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:2144
static String getSummaryStatistics(Population popln, GAParameters settings)
Definition: EAUtils.java:1434
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:2231
static DecimalFormat initialiseFormatter()
Definition: EAUtils.java:120
static int getCrowdedness(AttachmentPoint ap)
Calculate the current crowdedness of the given attachment point.
Definition: EAUtils.java:2350
static int getCrowdedness(AttachmentPoint ap, boolean ignoreFreeRCVs)
Calculate the current crowdedness of the given attachment point.
Definition: EAUtils.java:2366
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:2884
static void combineRelatedAPPairUtil(List< RelatedAPPair > pool, int left, int k, List< RelatedAPPair > tmp, List< List< RelatedAPPair > > allCombs, int limit)
Definition: EAUtils.java:2895
static void outputPopulationDetails(Population population, String filename, GAParameters settings, boolean printpathNames)
Write out summary for the current GA population.
Definition: EAUtils.java:1375
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:3045
static Vertex selectNonScaffoldNonCapVertex(DGraph g, Randomizer randomizer)
Chose randomly a vertex that is neither scaffold or capping group.
Definition: EAUtils.java:1541
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:2433
static String getPathNameToGenerationFolder(int genID, GAParameters settings)
Definition: EAUtils.java:1619
static double getPopulationSD(Population molPopulation)
Check if fitness values have significant standard deviation.
Definition: EAUtils.java:2165
static String getPathNameToFinalPopulationDetailsFile(GAParameters settings)
Definition: EAUtils.java:1664
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:2408
static boolean containsMolecule(Population mols, String molcode)
Check if the population contains the specified InChi code.
Definition: EAUtils.java:2121
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:1083
static List< List< RelatedAPPair > > searchRingFusionSites(DGraph graph, FragmentSpace fragSpace, RingClosureParameters rcParams, boolean projectOnSymmetricAPs, Logger logger, Randomizer rng)
Definition: EAUtils.java:2578
static void storePairsSymmetricRelations(RelatedAPPair pair, SymmetricAPs symAPs, Map< SymmetricSetWithMode, List< RelatedAPPair > > storage)
Definition: EAUtils.java:2931
static void readUID(String infile, HashSet< String > lstInchi)
Definition: EAUtils.java:2483
static final String FSEP
Definition: EAUtils.java:138
static String getPathNameToGenerationDetailsFile(int genID, GAParameters settings)
Definition: EAUtils.java:1635
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:2205
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:2956
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.