$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.text.DecimalFormat;
25import java.text.NumberFormat;
26import java.util.ArrayList;
27import java.util.Arrays;
28import java.util.Comparator;
29import java.util.HashMap;
30import java.util.HashSet;
31import java.util.Iterator;
32import java.util.List;
33import java.util.Locale;
34import java.util.Map;
35import java.util.Set;
36import java.util.concurrent.atomic.AtomicInteger;
37import java.util.logging.Level;
38import java.util.logging.Logger;
39
40import org.apache.commons.io.FileUtils;
41import org.apache.commons.io.FilenameUtils;
42import org.openscience.cdk.graph.ShortestPaths;
43import org.openscience.cdk.interfaces.IAtom;
44import org.openscience.cdk.interfaces.IAtomContainer;
45import org.openscience.cdk.isomorphism.Mappings;
46
47import java.util.stream.IntStream;
48
49import denoptim.constants.DENOPTIMConstants;
50import denoptim.exception.DENOPTIMException;
51import denoptim.fitness.FitnessParameters;
52import denoptim.fragmenter.BridgeHeadFindingRule;
53import denoptim.fragmenter.FragmenterTools;
54import denoptim.fragmenter.ScaffoldingPolicy;
55import denoptim.fragspace.FragmentSpace;
56import denoptim.fragspace.FragmentSpaceParameters;
57import denoptim.graph.APClass;
58import denoptim.graph.AttachmentPoint;
59import denoptim.graph.Candidate;
60import denoptim.graph.DGraph;
61import denoptim.graph.Edge.BondType;
62import denoptim.graph.EmptyVertex;
63import denoptim.graph.Fragment;
64import denoptim.graph.GraphPattern;
65import denoptim.graph.RelatedAPPair;
66import denoptim.graph.Ring;
67import denoptim.graph.SymmetricAPs;
68import denoptim.graph.SymmetricSet;
69import denoptim.graph.SymmetricSetWithMode;
70import denoptim.graph.Template;
71import denoptim.graph.Template.ContractLevel;
72import denoptim.graph.Vertex;
73import denoptim.graph.Vertex.BBType;
74import denoptim.graph.rings.CyclicGraphHandler;
75import denoptim.graph.rings.RingClosureParameters;
76import denoptim.graph.rings.RingClosuresArchive;
77import denoptim.io.DenoptimIO;
78import denoptim.logging.CounterID;
79import denoptim.logging.Monitor;
80import denoptim.molecularmodeling.ThreeDimTreeBuilder;
81import denoptim.programs.RunTimeParameters.ParametersType;
82import denoptim.programs.denovo.GAParameters;
83import denoptim.programs.fragmenter.CuttingRule;
84import denoptim.programs.fragmenter.FragmenterParameters;
85import denoptim.utils.DummyAtomHandler;
86import denoptim.utils.GeneralUtils;
87import denoptim.utils.GraphUtils;
88import denoptim.utils.ManySMARTSQuery;
89import denoptim.utils.MoleculeUtils;
90import denoptim.utils.Randomizer;
91import denoptim.utils.RotationalSpaceUtils;
92import denoptim.utils.SizeControlledSet;
93import denoptim.utils.StatUtils;
94
95
101public class EAUtils
102{
103 // cluster the fragments based on their #APs
104 protected static HashMap<Integer, ArrayList<Integer>> fragmentPool;
105
109 private static Locale enUsLocale = new Locale("en", "US");
110
114 private static DecimalFormat df = initialiseFormatter();
115 private static DecimalFormat initialiseFormatter() {
116 DecimalFormat df = (DecimalFormat) NumberFormat.getNumberInstance(
117 enUsLocale);
118 df.setGroupingUsed(false);
119 return df;
120 }
121
122 // for each fragment store the reactions associated with it
123 protected static HashMap<Integer, ArrayList<String>> lstFragmentClass;
124
128 public enum CandidateSource {
129 CROSSOVER, MUTATION, CONSTRUCTION, MANUAL;
130 }
131
132 private static final String NL =System.getProperty("line.separator");
133 private static final String FSEP = System.getProperty("file.separator");
134
135//------------------------------------------------------------------------------
136
143 protected static void createFolderForGeneration(int genId,
144 GAParameters settings)
145 {
146 denoptim.files.FileUtils.createDirectory(
147 EAUtils.getPathNameToGenerationFolder(genId, settings));
148 }
149
150//------------------------------------------------------------------------------
151
158 SizeControlledSet uniqueIDsSet, GAParameters settings)
159 throws DENOPTIMException, IOException
160 {
161 Population population = new Population(settings);
162
163 // Read existing or previously visited UIDs
164 HashSet<String> lstUID = new HashSet<>(1024);
165 if (!settings.getUIDFileIn().equals(""))
166 {
167 EAUtils.readUID(settings.getUIDFileIn(),lstUID);
168 for (String uid : lstUID)
169 {
170 uniqueIDsSet.addNewUniqueEntry(uid);
171 }
172 settings.getLogger().log(Level.INFO, "Read " + lstUID.size()
173 + " known UIDs from " + settings.getUIDFileIn());
174 }
175
176 // Read existing graphs
177 int numFromInitGraphs = 0;
178 String initPopFile = settings.getInitialPopulationFile();
179 if (initPopFile.length() > 0)
180 {
181 EAUtils.getPopulationFromFile(initPopFile, population, uniqueIDsSet,
183 settings);
184 numFromInitGraphs = population.size();
185 settings.getLogger().log(Level.INFO, "Imported " + numFromInitGraphs
186 + " candidates (as graphs) from " + initPopFile);
187 }
188
189 return population;
190 }
191
192//------------------------------------------------------------------------------
193
203 {
205 settings.getCrossoverWeight(),
206 settings.getMutationWeight(),
207 settings.getConstructionWeight(),
208 settings.getRandomizer());
209 }
210
211//------------------------------------------------------------------------------
212
219 public static int chooseNumberOfSitesToMutate(double[] multiSiteMutationProb,
220 double hit)
221 {
222 double tot = 0;
223 for (int i=0; i<multiSiteMutationProb.length; i++)
224 tot = tot + multiSiteMutationProb[i];
225
226 double scaledHit = hit * tot;
227
228 double min = 0;
229 double max = 0;
230 int choice = 0;
231 for (int i=0; i<multiSiteMutationProb.length; i++)
232 {
233 max = max + multiSiteMutationProb[i];
234 if (min < scaledHit && scaledHit <= max)
235 {
236 choice = i;
237 break;
238 }
239 min = Math.max(min,min+multiSiteMutationProb[i]);
240 }
241 return choice;
242 }
243
244//------------------------------------------------------------------------------
245
259 double xoverWeight, double mutWeight, double newWeight,
260 Randomizer randomizer)
261 {
262 double hit = randomizer.nextDouble()
263 * (xoverWeight + mutWeight + newWeight);
264 if (hit <= xoverWeight)
265 {
267 } else if (xoverWeight < hit && hit <= (mutWeight+xoverWeight))
268 {
270 } else {
272 }
273 }
274
275//------------------------------------------------------------------------------
276
288 protected static List<Candidate> buildCandidatesByXOver(
289 List<Candidate> eligibleParents, Population population,
290 Monitor mnt, GAParameters settings) throws DENOPTIMException
291 {
292 return buildCandidatesByXOver(eligibleParents, population, mnt,
293 null, -1, -1, settings, settings.maxOffsprintFromXover());
294 }
295
296//------------------------------------------------------------------------------
297
309 List<Candidate> eligibleParents, Population population,
310 Monitor mnt, GAParameters settings) throws DENOPTIMException
311 {
312 return buildCandidateByXOver(eligibleParents, population, mnt,
313 null, -1, -1, settings);
314 }
315
316//------------------------------------------------------------------------------
317
343 List<Candidate> eligibleParents, Population population,
344 Monitor mnt, int[] choiceOfParents, int choiceOfXOverSites,
345 int choiceOfOffstring, GAParameters settings)
346 throws DENOPTIMException
347 {
348 List<Candidate> cands = buildCandidatesByXOver(eligibleParents,
349 population, mnt,
350 choiceOfParents, choiceOfXOverSites, choiceOfOffstring,
351 settings, 1);
352 if (cands.size()>0)
353 return cands.get(0);
354 else
355 return null;
356 }
357
358//------------------------------------------------------------------------------
359
387 protected static List<Candidate> buildCandidatesByXOver(
388 List<Candidate> eligibleParents, Population population,
389 Monitor mnt, int[] choiceOfParents, int choiceOfXOverSites,
390 int choiceOfOffstring, GAParameters settings,
391 int maxCandidatesToReturn) throws DENOPTIMException
392 {
394 if (settings.containsParameters(ParametersType.FS_PARAMS))
395 {
396 fsParams = (FragmentSpaceParameters)settings.getParameters(
398 }
399 FragmentSpace fragSpace = fsParams.getFragmentSpace();
400
401 mnt.increase(CounterID.XOVERATTEMPTS);
402 mnt.increase(CounterID.NEWCANDIDATEATTEMPTS);
403
404 int numatt = 1;
405
406 // Identify a pair of parents that can do crossover, and a pair of
407 // vertexes from which we can define a subgraph (or a branch) to swap
408 XoverSite xos = null;
409 boolean foundPars = false;
410 while (numatt < settings.getMaxGeneticOpAttempts())
411 {
412 if (fragSpace.useAPclassBasedApproach())
413 {
414 xos = EAUtils.performFBCC(eligibleParents,
415 population, choiceOfParents, choiceOfXOverSites,
416 settings);
417 if (xos == null)
418 {
419 numatt++;
420 continue;
421 }
422 } else {
423 //TODO: make it reproducible using choiceOfParents and choiceOfXOverSites
425 eligibleParents, 2, settings);
426 if (parents[0] == null || parents[1] == null)
427 {
428 numatt++;
429 continue;
430 }
431 //NB: this does not go into templates!
432 DGraph gpA = parents[0].getGraph();
433 List<Vertex> subGraphA = new ArrayList<Vertex>();
435 gpA, settings.getRandomizer()),subGraphA);
436
437 DGraph gpB = parents[1].getGraph();
438 List<Vertex> subGraphB = new ArrayList<Vertex>();
440 gpB, settings.getRandomizer()),subGraphB);
441 }
442 foundPars = true;
443 break;
444 }
445 mnt.increaseBy(CounterID.XOVERPARENTSEARCH, numatt);
446
447 if (!foundPars)
448 {
450 mnt.increase(CounterID.FAILEDXOVERATTEMPTS);
451 return new ArrayList<Candidate>();
452 }
453
454 Candidate cA = null, cB = null;
455 Vertex vA = null, vB = null;
456 vA = xos.getA().get(0);
457 vB = xos.getB().get(0);
458 DGraph gA = vA.getGraphOwner();
460 DGraph gB = vB.getGraphOwner();
462
463 String candIdA = cA.getName();
464 String candIdB = cB.getName();
465 int gid1 = gA.getGraphId();
466 int gid2 = gB.getGraphId();
467
468 // Start building the offspring
469 XoverSite xosOnClones = xos.projectToClonedGraphs();
470 DGraph gAClone = xosOnClones.getA().get(0).getGraphOwner();
471 DGraph gBClone = xosOnClones.getB().get(0).getGraphOwner();
472
473 try
474 {
475 if (!GraphOperations.performCrossover(xosOnClones,fragSpace))
476 {
478 mnt.increase(CounterID.FAILEDXOVERATTEMPTS);
479 return new ArrayList<Candidate>();
480 }
481 } catch (Throwable t) {
482 if (!settings.xoverFailureTolerant)
483 {
484 t.printStackTrace();
485 ArrayList<DGraph> parents = new ArrayList<DGraph>();
486 parents.add(gA);
487 parents.add(gB);
488 DenoptimIO.writeGraphsToSDF(new File(settings.getDataDirectory()
489 + "_failed_xover.sdf"), parents, true,
490 settings.getLogger(), settings.getRandomizer());
491 throw new DENOPTIMException("Error while performing crossover! "+NL
492 + "XOverSite: " + xos.toString() + NL
493 + "XOverSite(C): " + xosOnClones.toString() + NL
494 + " Please, report this to the authors ",t);
495 }
497 mnt.increase(CounterID.FAILEDXOVERATTEMPTS);
498 return new ArrayList<Candidate>();
499 }
502 String lstIdVA = "";
503 for (Vertex v : xos.getA())
504 lstIdVA = lstIdVA + "_" + v.getVertexId();
505 String lstIdVB = "";
506 for (Vertex v : xos.getB())
507 lstIdVB = lstIdVB + "_" + v.getVertexId();
508 String[] msgs = new String[2];
509 msgs[0] = "Xover: "
510 + "Gen:" + cA.getGeneration() + " Cand:" + candIdA
511 + "|" + gid1 + "|" + lstIdVA
512 + " X "
513 + "Gen:" + cB.getGeneration() + " Cand:" + candIdB
514 + "|" + gid2 + "|" + lstIdVB;
515 msgs[1] = "Xover: "
516 + "Gen:" + cB.getGeneration() + " Cand:" + candIdB
517 + "|" + gid2 + "|" + lstIdVB
518 + " X "
519 + "Gen:" + cA.getGeneration() + " Cand:" + candIdA
520 + "|" + gid1 + "|" + lstIdVA;
521
522 DGraph[] graphsAffectedByXover = new DGraph[2];
523 graphsAffectedByXover[0] = gAClone;
524 graphsAffectedByXover[1] = gBClone;
525
526 List<Candidate> validOffspring = new Population(settings);
527 for (int ig=0; ig<graphsAffectedByXover.length; ig++)
528 {
529 DGraph g = graphsAffectedByXover[ig];
530
531 // It makes sense to do this on the possibly embedded graph and not
532 // on their embedding owners because there cannot be any new cycle
533 // affecting the latter, but there can be ones affecting the first.
534 if (!EAUtils.setupRings(null, g, settings))
535 {
537 continue;
538 }
539
540 // Finalize the graph that is at the outermost level
541 DGraph gOutermost = g.getOutermostGraphOwner();
542 gOutermost.addCappingGroups(fragSpace);
543 gOutermost.renumberGraphVertices();
544 gOutermost.setLocalMsg(msgs[ig]);
545
546 // Consider if the result can be used to define a new candidate
547 Object[] res = null;
548 try
549 {
550 res = gOutermost.checkConsistency(settings);
551 } catch (NullPointerException|IllegalArgumentException e)
552 {
553 if (!settings.xoverGraphFailedEvalTolerant)
554 {
555 ArrayList<DGraph> parents = new ArrayList<DGraph>();
556 parents.add(gA);
557 parents.add(gB);
558 parents.add(gAClone);
559 parents.add(gBClone);
560 DenoptimIO.writeGraphsToSDF(new File(settings.getDataDirectory()
561 + "_failed_xover-ed_check.sdf"), parents, true,
562 settings.getLogger(), settings.getRandomizer());
563 throw e;
564 } else {
565 res = null;
566 }
567 }
568 if (res != null)
569 {
570 if (!EAUtils.setupRings(res, gOutermost, settings))
571 {
573 res = null;
574 }
575 } else {
577 }
578
579 // Check if the chosen combination gives rise to forbidden ends
580 for (Vertex rcv : gOutermost.getFreeRCVertices())
581 {
582 APClass apc = rcv.getEdgeToParent().getSrcAP().getAPClass();
583 if (fragSpace.getCappingMap().get(apc)==null
584 && fragSpace.getForbiddenEndList().contains(apc))
585 {
587 res = null;
588 }
589 }
590 if (res == null)
591 {
592 mnt.increase(CounterID.FAILEDXOVERATTEMPTS);
593 gOutermost.cleanup();
594 gOutermost = null;
595 continue;
596 }
597
598 // OK: we can now use it to make a new candidate
599 Candidate offspring = new Candidate(gOutermost);
600 offspring.setUID(res[0].toString().trim());
601 offspring.setSmiles(res[1].toString().trim());
602 offspring.setChemicalRepresentation((IAtomContainer) res[2]);
603
604 validOffspring.add(offspring);
605 }
606
607 if (validOffspring.size() == 0)
608 {
609 mnt.increase(CounterID.FAILEDXOVERATTEMPTS);
610 return new ArrayList<Candidate>();
611 }
612
613 if (maxCandidatesToReturn==1)
614 {
615 Candidate chosenOffspring = null;
616 if (choiceOfOffstring<0)
617 {
618 chosenOffspring = settings.getRandomizer().randomlyChooseOne(
619 validOffspring);
620 chosenOffspring.setName("M" + GeneralUtils.getPaddedString(
623 } else {
624 chosenOffspring = validOffspring.get(choiceOfOffstring);
625 }
626 validOffspring.retainAll(Arrays.asList(chosenOffspring));
627 } else {
628 for (Candidate cand : validOffspring)
629 {
633 }
634 }
635 return validOffspring;
636 }
637
638//------------------------------------------------------------------------------
639
641 List<Candidate> eligibleParents, Monitor mnt,
642 GAParameters settings) throws DENOPTIMException
643 {
645 if (settings.containsParameters(ParametersType.FS_PARAMS))
646 {
647 fsParams = (FragmentSpaceParameters)settings.getParameters(
649 }
650 FragmentSpace fragSpace = fsParams.getFragmentSpace();
651
652 mnt.increase(CounterID.MUTATTEMPTS);
653 mnt.increase(CounterID.NEWCANDIDATEATTEMPTS);
654
655 int numatt = 0;
656 Candidate parent = null;
657 while (numatt < settings.getMaxGeneticOpAttempts())
658 {
659 parent = EAUtils.selectBasedOnFitness(eligibleParents,1, settings)[0];
660 if (parent == null)
661 {
662 numatt++;
663 continue;
664 }
665 break;
666 }
667 mnt.increaseBy(CounterID.MUTPARENTSEARCH,numatt);
668 if (parent == null)
669 {
670 mnt.increase(CounterID.FAILEDMUTATTEMTS);
671 return null;
672 }
673
674 DGraph graph = parent.getGraph().clone();
675 graph.renumberGraphVertices();
676
677 String parentMolName = FilenameUtils.getBaseName(parent.getSDFFile());
678 int parentGraphId = parent.getGraph().getGraphId();
679 graph.setLocalMsg("Mutation:"
680 + " Gen:" + parent.getGeneration() + " Cand:" + parentMolName
681 + "|" + parentGraphId);
682
683 if (!GraphOperations.performMutation(graph, mnt, settings))
684 {
686 mnt.increase(CounterID.FAILEDMUTATTEMTS);
687 return null;
688 }
689
691
692 graph.addCappingGroups(fragSpace);
693
694 Object[] res = null;
695 try
696 {
697 res = graph.checkConsistency(settings);
698 } catch (NullPointerException|IllegalArgumentException e)
699 {
700 if (!settings.mutatedGraphFailedEvalTolerant)
701 {
702 settings.getLogger().log(Level.INFO, "WRITING DEBUG FILE for "
703 + graph.getLocalMsg());
704 DenoptimIO.writeGraphToSDF(new File("debug_evalGrp_parent.sdf"),
705 parent.getGraph(),false, settings.getLogger(),
706 settings.getRandomizer());
707 DenoptimIO.writeGraphToSDF(new File("debug_evalGrp_curr.sdf"),
708 graph,false, settings.getLogger(),
709 settings.getRandomizer());
710 throw e;
711 } else {
712 res = null;
713 mnt.increase(CounterID.FAILEDMUTATTEMTS_EVAL);
714 }
715 }
716
717 if (res != null)
718 {
719 if (!EAUtils.setupRings(res,graph,settings))
720 {
721 res = null;
723 }
724 } else {
725 mnt.increase(CounterID.FAILEDMUTATTEMTS_EVAL);
726 }
727
728 // Check if the chosen combination gives rise to forbidden ends
729 //TODO this should be considered already when making the list of
730 // possible combination of rings
731 for (Vertex rcv : graph.getFreeRCVertices())
732 {
733 APClass apc = rcv.getEdgeToParent().getSrcAP().getAPClass();
734 if (fragSpace.getCappingMap().get(apc)==null
735 && fragSpace.getForbiddenEndList().contains(apc))
736 {
737 res = null;
739 }
740 }
741
742 if (res == null)
743 {
744 graph.cleanup();
745 graph = null;
746 mnt.increase(CounterID.FAILEDMUTATTEMTS);
747 return null;
748 }
749
750 Candidate offspring = new Candidate(graph);
751 offspring.setUID(res[0].toString().trim());
752 offspring.setSmiles(res[1].toString().trim());
753 offspring.setChemicalRepresentation((IAtomContainer) res[2]);
754 offspring.setName("M" + GeneralUtils.getPaddedString(
757
758 return offspring;
759 }
760
761//------------------------------------------------------------------------------
762
763 //TODO: move to IO class
764 protected static Candidate readCandidateFromFile(File srcFile, Monitor mnt,
765 GAParameters settings) throws DENOPTIMException
766 {
767 mnt.increase(CounterID.MANUALADDATTEMPTS);
768 mnt.increase(CounterID.NEWCANDIDATEATTEMPTS);
769
770 ArrayList<DGraph> graphs;
771 try
772 {
773 graphs = DenoptimIO.readDENOPTIMGraphsFromFile(srcFile);
774 } catch (Exception e)
775 {
776 e.printStackTrace();
778 String msg = "Could not read graphs from file " + srcFile
779 + ". No candidate generated!";
780 settings.getLogger().log(Level.SEVERE, msg);
781 return null;
782 }
783 if (graphs.size() == 0 || graphs.size() > 1)
784 {
786 String msg = "Found " + graphs.size() + " graphs in file " + srcFile
787 + ". I expect one and only one graph. "
788 + "No candidate generated!";
789 settings.getLogger().log(Level.SEVERE, msg);
790 return null;
791 }
792
793 DGraph graph = graphs.get(0);
794 if (graph == null)
795 {
797 String msg = "Null graph from file " + srcFile
798 + ". Expected one and only one graph. "
799 + "No candidate generated!";
800 settings.getLogger().log(Level.SEVERE, msg);
801 return null;
802 }
803 graph.setLocalMsg("MANUAL_ADD");
804
805 // We expect users to know what they ask for. Therefore, we do
806 // evaluate the graph, but in a permissive manner, meaning that
807 // several filters are disabled to permit the introduction of graphs
808 // that cannot be generated automatically.
809 Object[] res = graph.checkConsistency(settings, true);
810
811 if (res == null)
812 {
813 graph.cleanup();
816 return null;
817 }
818
819 Candidate candidate = new Candidate(graph);
820 candidate.setUID(res[0].toString().trim());
821 candidate.setSmiles(res[1].toString().trim());
822 candidate.setChemicalRepresentation((IAtomContainer) res[2]);
823
824 candidate.setName("M" + GeneralUtils.getPaddedString(
827
828 String msg = "Candidate " + candidate.getName() + " is imported from "
829 + srcFile;
830 settings.getLogger().log(Level.INFO, msg);
831
832 return candidate;
833 }
834
835//------------------------------------------------------------------------------
836
838 GAParameters settings)
839 throws DENOPTIMException
840 {
842 if (settings.containsParameters(ParametersType.FS_PARAMS))
843 {
844 fsParams = (FragmentSpaceParameters)settings.getParameters(
846 }
847 FragmentSpace fragSpace = fsParams.getFragmentSpace();
848
849 mnt.increase(CounterID.BUILDANEWATTEMPTS);
850 mnt.increase(CounterID.NEWCANDIDATEATTEMPTS);
851
852 DGraph graph = EAUtils.buildGraph(settings);
853 if (graph == null)
854 {
856 mnt.increase(CounterID.FAILEDBUILDATTEMPTS);
857 return null;
858 }
859 graph.setLocalMsg("NEW");
860
861 Object[] res = graph.checkConsistency(settings);
862
863 if (res != null)
864 {
865 if (!EAUtils.setupRings(res,graph, settings))
866 {
867 graph.cleanup();
869 mnt.increase(CounterID.FAILEDBUILDATTEMPTS);
870 return null;
871 }
872 } else {
873 graph.cleanup();
875 mnt.increase(CounterID.FAILEDBUILDATTEMPTS);
876 return null;
877 }
878
879 // Check if the chosen combination gives rise to forbidden ends
880 //TODO: this should be considered already when making the list of
881 // possible combination of rings
882 for (Vertex rcv : graph.getFreeRCVertices())
883 {
884 // Also exclude any RCV that is not bound to anything?
885 if (rcv.getEdgeToParent() == null)
886 {
887 res = null;
889 }
890 if (rcv.getEdgeToParent() == null)
891 {
892 // RCV as scaffold! Ignore special case
893 continue;
894 }
895 APClass apc = rcv.getEdgeToParent().getSrcAP().getAPClass();
896 if (fragSpace.getCappingMap().get(apc)==null
897 && fragSpace.getForbiddenEndList().contains(apc))
898 {
899 res = null;
901 }
902 }
903
904 if (res == null)
905 {
906 graph.cleanup();
907 mnt.increase(CounterID.FAILEDBUILDATTEMPTS);
908 return null;
909 }
910
911 Candidate candidate = new Candidate(graph);
912 candidate.setUID(res[0].toString().trim());
913 candidate.setSmiles(res[1].toString().trim());
914 candidate.setChemicalRepresentation((IAtomContainer) res[2]);
915
916 candidate.setName("M" + GeneralUtils.getPaddedString(
919
920 return candidate;
921 }
922
923//------------------------------------------------------------------------------
924
938 public static Candidate buildCandidateByFragmentingMolecule(IAtomContainer mol,
939 Monitor mnt, GAParameters settings, int index) throws DENOPTIMException
940 {
942 if (settings.containsParameters(ParametersType.FS_PARAMS))
943 {
944 fsParams = (FragmentSpaceParameters) settings.getParameters(
946 }
947 FragmentSpace fragSpace = fsParams.getFragmentSpace();
948
950 if (settings.containsParameters(ParametersType.FRG_PARAMS))
951 {
952 frgParams = (FragmenterParameters) settings.getParameters(
954 }
955
956 if (frgParams.getCuttingRules()==null
957 || frgParams.getCuttingRules().isEmpty())
958 {
959 throw new DENOPTIMException("Request to generate candidates by "
960 + "fragmentation but no cutting rules provided. Please,"
961 + "add FRG-CUTTINGRULESFILE=path/to/your/file to the "
962 + "input.");
963 }
964 mnt.increase(CounterID.CONVERTBYFRAGATTEMPTS);
965 mnt.increase(CounterID.NEWCANDIDATEATTEMPTS);
966
967 // Adjust molecular representation to our settings
968 if (!FragmenterTools.prepareMolToFragmentation(mol, frgParams, index))
969 return null;
970
971 // Do actual fragmentation
972 DGraph graph = null;
973 try {
975 frgParams.getCuttingRules(), settings.getLogger(),
976 frgParams.getScaffoldingPolicy(),
977 frgParams.getLinearAngleLimit(),
978 frgParams.embedRingsInTemplate(),
979 frgParams.getEmbeddedRingsContract(),
980 fragSpace, mnt);
981 } catch (DENOPTIMException de)
982 {
983 String msg = "Unable to convert molecule (" + mol.getAtomCount()
984 + " atoms) to DENOPTIM graph. " + de.getMessage();
985 settings.getLogger().log(Level.WARNING, msg);
986 }
987 if (graph == null)
988 {
990 return null;
991 }
992
993 graph.setLocalMsg("INITIAL_MOL_FRAGMENTED");
994
995 Object[] res = graph.checkConsistency(settings);
996 if (res == null)
997 {
998 graph.cleanup();
1000 return null;
1001 }
1002
1003 Candidate candidate = new Candidate(graph);
1004 candidate.setUID(res[0].toString().trim());
1005 candidate.setSmiles(res[1].toString().trim());
1006 candidate.setChemicalRepresentation((IAtomContainer) res[2]);
1007
1008 candidate.setName("M" + GeneralUtils.getPaddedString(
1011
1012 return candidate;
1013 }
1014
1015//------------------------------------------------------------------------------
1016
1028 public static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol,
1029 List<CuttingRule> cuttingRules, Logger logger,
1030 ScaffoldingPolicy scaffoldingPolicy)
1031 throws DENOPTIMException
1032 {
1033 return makeGraphFromFragmentationOfMol(mol, cuttingRules, logger,
1034 scaffoldingPolicy, 190, new FragmentSpace());
1035 // NB: and angle of 190 means we are not adding Du on linearities
1036 // because the max possible bond angle is 180.
1037 }
1038
1039//------------------------------------------------------------------------------
1040
1054 public static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol,
1055 List<CuttingRule> cuttingRules, Logger logger,
1056 ScaffoldingPolicy scaffoldingPolicy, double linearAngleLimit)
1057 throws DENOPTIMException
1058 {
1059 return makeGraphFromFragmentationOfMol(mol, cuttingRules, logger,
1060 scaffoldingPolicy, linearAngleLimit, new FragmentSpace());
1061 }
1062
1063//------------------------------------------------------------------------------
1064
1078 public static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol,
1079 List<CuttingRule> cuttingRules, Logger logger,
1080 ScaffoldingPolicy scaffoldingPolicy, FragmentSpace fragSpace)
1081 throws DENOPTIMException
1082 {
1083 return makeGraphFromFragmentationOfMol(mol, cuttingRules, logger,
1084 scaffoldingPolicy, 190, fragSpace);
1085 // NB: and angle of 190 means we are not adding Du on linearities
1086 // because the max possible bond angle is 180.
1087 }
1088
1089//------------------------------------------------------------------------------
1090
1106 public static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol,
1107 List<CuttingRule> cuttingRules, Logger logger,
1108 ScaffoldingPolicy scaffoldingPolicy, double linearAngleLimit,
1109 FragmentSpace fragSpace)
1110 throws DENOPTIMException
1111 {
1112 return makeGraphFromFragmentationOfMol(mol, cuttingRules, logger,
1113 scaffoldingPolicy, linearAngleLimit, false, null,
1114 fragSpace, null);
1115 }
1116
1117//------------------------------------------------------------------------------
1118
1140 public static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol,
1141 List<CuttingRule> cuttingRules, Logger logger,
1142 ScaffoldingPolicy scaffoldingPolicy, double linearAngleLimit,
1143 boolean embedRingsInTemplates, ContractLevel ringTmplContract,
1144 FragmentSpace fragSpace, Monitor monitor)
1145 throws DENOPTIMException
1146 {
1147 // We expect only Fragments here.
1148 List<Vertex> fragments = FragmenterTools.fragmentation(mol,
1149 cuttingRules, logger);
1150 for (Vertex v : fragments)
1151 {
1152 Fragment frag = (Fragment) v;
1153
1154 // This is done to set the symmetry relations in each vertex
1155 frag.updateAPs();
1156
1157 // Add linearity-breaking dummy atoms
1158 DummyAtomHandler.addDummiesOnLinearities(frag, linearAngleLimit);
1159 }
1160 if (fragments.size()==0)
1161 {
1162 if (monitor!=null)
1163 {
1165 }
1166 throw new DENOPTIMException("Fragmentation of molecule with "
1167 + mol.getAtomCount() + " atoms produced 0 fragments.");
1168 }
1169
1170 // Define which fragment is the scaffold
1171 Vertex scaffold = null;
1172 switch (scaffoldingPolicy)
1173 {
1174 case ELEMENT:
1175 {
1176 for (Vertex v : fragments)
1177 {
1178 if (v instanceof Fragment)
1179 {
1180 boolean setAsScaffold = false;
1181 IAtomContainer iac = v.getIAtomContainer();
1182 for (IAtom atm : iac.atoms())
1183 {
1184 if (scaffoldingPolicy.label.equals(
1186 {
1187 setAsScaffold = true;
1188 break;
1189 }
1190 }
1191 if (setAsScaffold)
1192 {
1193 scaffold = v;
1194 break;
1195 }
1196 }
1197 }
1198 break;
1199 }
1200
1201 default:
1202 case LARGEST_FRAGMENT:
1203 {
1204 try {
1205 scaffold = fragments.stream()
1206 .max(Comparator.comparing(
1208 .get();
1209 } catch (Exception e)
1210 {
1211 if (monitor!=null)
1212 {
1214 }
1215 throw new DENOPTIMException("Cannot get largest fragment "
1216 + "among " + fragments.size() + " fragments.", e);
1217 }
1218 break;
1219 }
1220 }
1221 if (scaffold==null)
1222 {
1223 if (monitor!=null)
1224 {
1226 }
1227 throw new DENOPTIMException("No fragment matches criteria to be "
1228 + "identified as the "
1229 + BBType.SCAFFOLD.toString().toLowerCase() + ".");
1230 }
1231 scaffold.setVertexId(0);
1233
1234 // Build the graph
1235 DGraph graph = new DGraph();
1236 graph.addVertex(scaffold);
1237 AtomicInteger vId = new AtomicInteger(1);
1238 for (int i=1; i<fragments.size(); i++)
1239 {
1240 appendVertexesToGraphFollowingEdges(graph, vId, fragments);
1241 }
1242
1243 // Set symmetry relations: these depend on which scaffold we have chosen
1244 graph.detectSymVertexSets();
1245
1246 // Identify capping groups, i.e., fragments that reflect the capping
1247 // groups found in the fragment space, if any.
1248 if (fragSpace!=null && fragSpace.getCappingMap()!=null)
1249 {
1250 for (Vertex v : graph.getVertexList())
1251 {
1252 if (v.getAttachmentPoints().size()!=1 || v.isRCV())
1253 continue;
1254
1255 APClass srcAPC = v.getAP(0).getLinkedAPThroughout().getAPClass();
1256 APClass capAPC = fragSpace.getAPClassOfCappingVertex(srcAPC);
1257 Vertex cap = fragSpace.getCappingVertexWithAPClass(capAPC);
1258 if (cap==null)
1259 continue;
1260
1261 if (!(v instanceof Fragment && cap instanceof Fragment))
1262 continue;
1263
1264 Fragment f = (Fragment) v;
1265 // NB: here we ignore APClasses and Du atoms
1266 if (f.isIsomorphicTo(cap, true))
1267 {
1269 v.getAP(0).setAPClass(capAPC);
1270 }
1271 }
1272 }
1273
1274 if (embedRingsInTemplates)
1275 {
1276 try {
1278 fragSpace, ringTmplContract);
1279 } catch (DENOPTIMException e) {
1280 graph.cleanup();
1281 if (monitor!=null)
1282 {
1284 }
1285 return null;
1286 }
1287 }
1288
1289 return graph;
1290 }
1291
1292//------------------------------------------------------------------------------
1293
1295 AtomicInteger vId, List<Vertex> vertexes) throws DENOPTIMException
1296 {
1297 // We seek for the last and non-RCV vertex added to the graph
1298 Vertex lastlyAdded = null;
1299 for (int i=-1; i>-4; i--)
1300 {
1301 lastlyAdded = graph.getVertexList().get(
1302 graph.getVertexList().size()+i);
1303 if (!lastlyAdded.isRCV())
1304 break;
1305 }
1306 for (AttachmentPoint apI : lastlyAdded.getAttachmentPoints())
1307 {
1308 if (!apI.isAvailable())
1309 continue;
1310
1311 for (int j=0; j<vertexes.size(); j++)
1312 {
1313 Vertex fragJ = vertexes.get(j);
1314
1315 boolean ringClosure = false;
1316 if (graph.containsVertex(fragJ))
1317 {
1318 ringClosure = true;
1319 }
1320 for (AttachmentPoint apJ : fragJ.getAttachmentPoints())
1321 {
1322 if (apI==apJ)
1323 continue;
1324
1325 if (apI.getCutId()==apJ.getCutId())
1326 {
1327 if (ringClosure)
1328 {
1331 BondType.ANY));
1333 rcvI.setVertexId(vId.getAndIncrement());
1334 graph.appendVertexOnAP(apI, rcvI.getAP(0));
1335
1339 rcvJ.setVertexId(vId.getAndIncrement());
1340 graph.appendVertexOnAP(apJ, rcvJ.getAP(0));
1341 graph.addRing(rcvI, rcvJ);
1342 } else {
1344 fragJ.setVertexId(vId.getAndIncrement());
1345 graph.appendVertexOnAP(apI, apJ);
1346
1347 // Recursion into the branch of the graph that is
1348 // rooted onto the lastly added vertex
1350 vertexes);
1351 }
1352 }
1353 }
1354 }
1355 }
1356 }
1357
1358//------------------------------------------------------------------------------
1359
1370 public static void outputPopulationDetails(Population population,
1371 String filename, GAParameters settings, boolean printpathNames)
1372 throws DENOPTIMException
1373 {
1374 StringBuilder sb = new StringBuilder(512);
1376 sb.append(NL);
1377
1378 df.setMaximumFractionDigits(settings.getPrecisionLevel());
1379 df.setMinimumFractionDigits(settings.getPrecisionLevel());
1380
1381 // NB: we consider the configured size of the population, not the actual
1382 // size of list representing the population.
1383 String stats = "";
1384 synchronized (population)
1385 {
1386 List<Candidate> popMembers = new ArrayList<Candidate>();
1387 for (int i=0; i<settings.getPopulationSize(); i++)
1388 {
1389 Candidate mol = population.get(i);
1390 popMembers.add(mol);
1391 if (mol != null)
1392 {
1393 String mname = new File(mol.getSDFFile()).getName();
1394 if (mname != null)
1395 sb.append(String.format("%-20s", mname));
1396
1397 sb.append(String.format("%-20s",
1398 mol.getGraph().getGraphId()));
1399 sb.append(String.format("%-30s", mol.getUID()));
1400 sb.append(df.format(mol.getFitness()));
1401
1402 if (printpathNames)
1403 {
1404 sb.append(" ").append(mol.getSDFFile());
1405 }
1406
1407 sb.append(System.getProperty("line.separator"));
1408 }
1409 }
1410
1411 // calculate descriptive statistics for the population
1412 stats = getSummaryStatistics(population, settings);
1413
1414 if (settings.savePopFile())
1415 {
1416 File dest = new File(filename.replaceAll("\\.txt$", ".sdf"));
1417 DenoptimIO.writeCandidatesToFile(dest, popMembers, false);
1418 }
1419 }
1420 if (stats.trim().length() > 0)
1421 sb.append(stats);
1422 DenoptimIO.writeData(filename, sb.toString(), false);
1423
1424 sb.setLength(0);
1425 }
1426
1427//------------------------------------------------------------------------------
1428
1429 private static String getSummaryStatistics(Population popln,
1430 GAParameters settings)
1431 {
1432 double[] fitness = getFitnesses(popln);
1433 double sdev = StatUtils.stddev(fitness, true);
1434 String res = "";
1435 df.setMaximumFractionDigits(settings.getPrecisionLevel());
1436
1437 StringBuilder sb = new StringBuilder(128);
1438 sb.append(NL+NL+"#####POPULATION SUMMARY#####"+NL);
1439 int n = popln.size();
1440 sb.append(String.format("%-30s", "SIZE:"));
1441 sb.append(String.format("%12s", n));
1442 sb.append(NL);
1443 double f;
1444 f = StatUtils.max(fitness);
1445 sb.append(String.format("%-30s", "MAX:")).append(df.format(f));
1446 sb.append(NL);
1447 f = StatUtils.min(fitness);
1448 sb.append(String.format("%-30s", "MIN:")).append(df.format(f));
1449 sb.append(NL);
1450 f = StatUtils.mean(fitness);
1451 sb.append(String.format("%-30s", "MEAN:")).append(df.format(f));
1452 sb.append(NL);
1453 f = StatUtils.median(fitness);
1454 sb.append(String.format("%-30s", "MEDIAN:")).append(df.format(f));
1455 sb.append(NL);
1456 f = StatUtils.stddev(fitness, true);
1457 sb.append(String.format("%-30s", "STDDEV:")).append(df.format(f));
1458 sb.append(NL);
1459 if (sdev > 0.0001)
1460 {
1461 f = StatUtils.skewness(fitness, true);
1462 sb.append(String.format("%-30s", "SKEW:")).append(df.format(f));
1463 sb.append(NL);
1464 } else {
1465 sb.append(String.format("%-30s", "SKEW:")).append(" NaN (sdev too small)");
1466 sb.append(NL);
1467 }
1468
1469 res = sb.toString();
1470 sb.setLength(0);
1471
1472 return res;
1473 }
1474
1475//------------------------------------------------------------------------------
1476
1487 List<Candidate> eligibleParents, int number, GAParameters settings)
1488 {
1489 Candidate[] mates = new Candidate[number];
1490 switch (settings.getSelectionStrategyType())
1491 {
1492 case 1:
1493 mates = SelectionHelper.performTournamentSelection(eligibleParents,
1494 number, settings);
1495 break;
1496 case 2:
1497 mates = SelectionHelper.performRWS(eligibleParents, number, settings);
1498 break;
1499 case 3:
1500 mates = SelectionHelper.performSUS(eligibleParents, number, settings);
1501 break;
1502 case 4:
1503 mates = SelectionHelper.performRandomSelection(eligibleParents, number,
1504 settings);
1505 break;
1506 }
1507
1508 if (settings.recordMateSelection())
1509 {
1510 String matesStr="";
1511 for (int i=0; i < mates.length; i++)
1512 {
1513 if (i>0)
1514 matesStr = matesStr + settings.NL;
1515 matesStr = matesStr + mates[i].getUID();
1516 }
1517 try
1518 {
1519 DenoptimIO.writeData(settings.getMonitorFile()+".mates",
1520 matesStr, true);
1521 } catch (DENOPTIMException e)
1522 {
1523 // TODO Auto-generated catch block
1524 e.printStackTrace();
1525 }
1526 }
1527
1528 return mates;
1529 }
1530
1531//------------------------------------------------------------------------------
1532
1537 Randomizer randomizer)
1538 {
1539 List<Vertex> candidates = new ArrayList<Vertex>(
1540 g.getVertexList());
1541 candidates.removeIf(v ->
1542 v.getBuildingBlockType() == BBType.SCAFFOLD
1543 || v.getBuildingBlockType() == BBType.CAP);
1544 return randomizer.randomlyChooseOne(candidates);
1545 }
1546
1547//------------------------------------------------------------------------------
1548
1564 protected static XoverSite performFBCC(
1565 List<Candidate> eligibleParents, Population population,
1566 int[] choiceOfParents, int choiceOfXOverSites, GAParameters settings)
1567 {
1568 Candidate parentA = null;
1569 if (choiceOfParents==null)
1570 parentA = selectBasedOnFitness(eligibleParents, 1, settings)[0];
1571 else
1572 parentA = eligibleParents.get(choiceOfParents[0]);
1573
1574 if (parentA == null)
1575 return null;
1576
1579 {
1580 fsParams = (FragmentSpaceParameters)settings.getParameters(
1582 }
1583 FragmentSpace fragSpace = fsParams.getFragmentSpace();
1584 List<Candidate> matesCompatibleWithFirst = population.getXoverPartners(
1585 parentA, eligibleParents, fragSpace);
1586 if (matesCompatibleWithFirst.size() == 0)
1587 return null;
1588
1589 Candidate parentB = null;
1590 if (choiceOfParents==null)
1591 {
1592 parentB = selectBasedOnFitness(matesCompatibleWithFirst, 1,
1593 settings)[0];
1594 } else {
1595 parentB = eligibleParents.get(choiceOfParents[1]);
1596 }
1597 if (parentB == null)
1598 return null;
1599
1600 XoverSite result = null;
1601 if (choiceOfXOverSites<0)
1602 {
1603 result = settings.getRandomizer().randomlyChooseOne(
1604 population.getXoverSites(parentA, parentB));
1605 } else {
1606 result = population.getXoverSites(parentA, parentB).get(
1607 choiceOfXOverSites);
1608 }
1609 return result;
1610 }
1611
1612//------------------------------------------------------------------------------
1613
1614 public static String getPathNameToGenerationFolder(int genID,
1615 GAParameters settings)
1616 {
1617 StringBuilder sb = new StringBuilder(32);
1618
1619 int ndigits = String.valueOf(settings.getNumberOfGenerations()).length();
1620
1621 sb.append(settings.getDataDirectory()).append(FSEP).append(
1623 .append(GeneralUtils.getPaddedString(ndigits, genID));
1624
1625 return sb.toString();
1626 }
1627
1628//------------------------------------------------------------------------------
1629
1630 public static String getPathNameToGenerationDetailsFile(int genID,
1631 GAParameters settings)
1632 {
1633 StringBuilder sb = new StringBuilder(32);
1634
1635 int ndigits = String.valueOf(settings.getNumberOfGenerations()).length();
1636
1637 sb.append(settings.getDataDirectory()).append(FSEP)
1639 .append(GeneralUtils.getPaddedString(ndigits, genID))
1640 .append(FSEP)
1642 .append(GeneralUtils.getPaddedString(ndigits, genID))
1643 .append(".txt");
1644
1645 return sb.toString();
1646 }
1647
1648//------------------------------------------------------------------------------
1649
1651 {
1652 StringBuilder sb = new StringBuilder(32);
1653 sb.append(settings.getDataDirectory()).append(FSEP).append("Final");
1654 return sb.toString();
1655 }
1656
1657//------------------------------------------------------------------------------
1658
1660 GAParameters settings)
1661 {
1662 StringBuilder sb = new StringBuilder(32);
1663 sb.append(settings.getDataDirectory()).append(FSEP).append("Final")
1664 .append(FSEP).append("Final.txt");
1665 return sb.toString();
1666 }
1667
1668//------------------------------------------------------------------------------
1669
1680 protected static void outputFinalResults(Population popln,
1681 GAParameters settings) throws DENOPTIMException
1682 {
1683 String dirName = EAUtils.getPathNameToFinalPopulationFolder(settings);
1684 denoptim.files.FileUtils.createDirectory(dirName);
1685 File fileDir = new File(dirName);
1686
1687 boolean intermediateCandidatesAreOnDisk =
1688 ((FitnessParameters) settings.getParameters(
1689 ParametersType.FIT_PARAMS)).writeCandidatesOnDisk();
1690
1691 for (int i=0; i<popln.size(); i++)
1692 {
1693 Candidate c = popln.get(i);
1694 String sdfile = c.getSDFFile();
1695 String imgfile = c.getImageFile();
1696
1697 try {
1698 if (intermediateCandidatesAreOnDisk && sdfile!=null)
1699 {
1700 FileUtils.copyFileToDirectory(new File(sdfile), fileDir);
1701 } else {
1702 File candFile = new File(fileDir, c.getName()
1704 c.setSDFFile(candFile.getAbsolutePath());
1705 DenoptimIO.writeCandidateToFile(candFile, c, false);
1706 }
1707 } catch (IOException ioe) {
1708 throw new DENOPTIMException("Failed to copy file '"
1709 + sdfile + "' to '" + fileDir + "' for candidate "
1710 + c.getName(), ioe);
1711 }
1712 if (imgfile != null && intermediateCandidatesAreOnDisk)
1713 {
1714 try {
1715 FileUtils.copyFileToDirectory(new File(imgfile), fileDir);
1716 } catch (IOException ioe) {
1717 throw new DENOPTIMException("Failed to copy file '"
1718 + imgfile + "' to '" + fileDir + "' for candidate "
1719 + c.getName(), ioe);
1720 }
1721 }
1722 }
1725 settings, true);
1726 }
1727
1728//------------------------------------------------------------------------------
1729
1738 protected static void getPopulationFromFile(String filename,
1739 Population population, SizeControlledSet uniqueIDsSet,
1740 String genDir, GAParameters settings)
1741 throws DENOPTIMException, IOException
1742 {
1743 List<Candidate> candidates = DenoptimIO.readCandidates(
1744 new File(filename), true);
1745 if (candidates.size() == 0)
1746 {
1747 String msg = "Found 0 candidates in file " + filename;
1748 settings.getLogger().log(Level.SEVERE, msg);
1749 throw new DENOPTIMException(msg);
1750 }
1751
1752 for (Candidate candidate : candidates)
1753 {
1754 if (uniqueIDsSet.addNewUniqueEntry(candidate.getUID()))
1755 {
1757 int gctr = GraphUtils.getUniqueGraphIndex();
1758
1759 String molName = "M" + GeneralUtils.getPaddedString(8, ctr);
1760 candidate.setName(molName);
1761 candidate.getGraph().setGraphId(gctr);
1762 candidate.getGraph().setLocalMsg("INITIAL_POPULATION");
1763 String sdfPathName = genDir + System.getProperty("file.separator")
1765 candidate.setSDFFile(sdfPathName);
1766 candidate.setImageFile(null);
1767
1768 // Write the candidate to file as if it had been processed by fitness provider
1769 DenoptimIO.writeCandidateToFile(new File(sdfPathName),
1770 candidate, false);
1771
1772 population.add(candidate);
1773 } else {
1774 settings.getLogger().log(Level.WARNING, "Candidate from intial "
1775 + "population file '" + filename
1776 + "' is rejected because its identifier is "
1777 + "already listed among the previously visited "
1778 + "identifiers.");
1779 }
1780 }
1781
1782 if (population.isEmpty())
1783 {
1784 String msg = "Population is still empty after having processes "
1785 + candidates.size() + " candidates from file " + filename;
1786 settings.getLogger().log(Level.SEVERE, msg);
1787 throw new DENOPTIMException(msg);
1788 }
1789
1790 setVertexCounterValue(population);
1791 }
1792
1793//------------------------------------------------------------------------------
1794
1795 protected static void writeUID(String outfile, HashSet<String> lstInchi,
1796 boolean append) throws DENOPTIMException
1797 {
1798 StringBuilder sb = new StringBuilder(256);
1799 Iterator<String> iter = lstInchi.iterator();
1800
1801 boolean first = true;
1802 while(iter.hasNext())
1803 {
1804 if (first)
1805 {
1806 sb.append(iter.next());
1807 first = false;
1808 }
1809 else
1810 {
1811 sb.append(NL).append(iter.next());
1812 }
1813 }
1814
1815 DenoptimIO.writeData(outfile, sb.toString(), append);
1816 sb.setLength(0);
1817 }
1818
1819//------------------------------------------------------------------------------
1820
1828 protected static void setVertexCounterValue(Population population)
1829 throws DENOPTIMException
1830 {
1831 long val = Long.MIN_VALUE;
1832 for (Candidate popln1 : population)
1833 {
1834 DGraph g = popln1.getGraph();
1835 val = Math.max(val, g.getMaxVertexId());
1836 }
1838 }
1839
1840//------------------------------------------------------------------------------
1841
1849 protected static DGraph buildGraph(GAParameters settings)
1850 throws DENOPTIMException
1851 {
1853 if (settings.containsParameters(ParametersType.FS_PARAMS))
1854 {
1855 fsParams = (FragmentSpaceParameters)settings.getParameters(
1857 }
1858 FragmentSpace fragSpace = fsParams.getFragmentSpace();
1859
1860 DGraph graph = new DGraph();
1862
1863 // building a molecule starts by selecting a random scaffold
1864 Vertex scafVertex = fragSpace.makeRandomScaffold();
1865
1866 // add the scaffold as a vertex
1867 graph.addVertex(scafVertex);
1868 graph.setLocalMsg("NEW");
1869
1870 if (scafVertex instanceof Template
1871 && !((Template) scafVertex).getContractLevel().equals(
1873 {
1874 Monitor mnt = new Monitor();
1875 mnt.name = "IntraTemplateBuild";
1876 List<Vertex> initialMutableSites = graph.getMutableSites(
1877 settings.getExcludedMutationTypes());
1878 for (Vertex mutableSite : initialMutableSites)
1879 {
1880 // This accounts for the possibility that a mutation changes a
1881 // branch of the initial graph or deletes vertexes.
1882 if (!graph.containsOrEmbedsVertex(mutableSite))
1883 continue;
1884
1885 // TODO: need to discriminate between EmptyVertexes that
1886 // represent placeholders and those that represent property carriers
1887 // The first should always be mutated (as it happens now), but
1888 // the latter should be kept intact.
1889 // Possibly this is a case for subclassing the EmptyVertex.
1890
1891 if (!GraphOperations.performMutation(mutableSite, mnt,
1892 settings))
1893 {
1896 return null;
1897 }
1898 }
1899 }
1900
1901 // get settings //TODO: this should happen inside RunTimeParameters
1903 if (settings.containsParameters(ParametersType.RC_PARAMS))
1904 {
1905 rcParams = (RingClosureParameters)settings.getParameters(
1907 }
1908//TODO this works only for scaffolds at the moment. make the preference for
1909// fragments that lead to known closable chains operate also when fragments are
1910// the "turning point".
1913 scafVertex.getBuildingBlockId()));
1914
1915 if (scafVertex.hasFreeAP())
1916 {
1917 GraphOperations.extendGraph(scafVertex, true, false, settings);
1918 }
1919
1920 if (!(scafVertex instanceof Template)
1921 && graph.getVertexCount() == 0)
1922 {
1923 return null;
1924 }
1925
1926 graph.addCappingGroups(fragSpace);
1927 return graph;
1928 }
1929
1930//------------------------------------------------------------------------------
1931
1944 protected static boolean setupRings(Object[] res, DGraph molGraph,
1945 GAParameters settings) throws DENOPTIMException
1946 {
1947 // get settings //TODO: this should happen inside RunTimeParameters
1949 if (settings.containsParameters(ParametersType.RC_PARAMS))
1950 {
1951 rcParams = (RingClosureParameters)settings.getParameters(
1953 }
1955 if (settings.containsParameters(ParametersType.FS_PARAMS))
1956 {
1957 fsParams = (FragmentSpaceParameters)settings.getParameters(
1959 }
1960 FragmentSpace fragSpace = fsParams.getFragmentSpace();
1961
1962 if (!fragSpace.useAPclassBasedApproach())
1963 return true;
1964
1965 if (!rcParams.allowRingClosures())
1966 return true;
1967
1968 // get a atoms/bonds molecular representation (no 3D needed)
1969 ThreeDimTreeBuilder t3d = new ThreeDimTreeBuilder(settings.getLogger(),
1970 settings.getRandomizer());
1971 t3d.setAlignBBsIn3D(false);
1972 IAtomContainer mol = t3d.convertGraphTo3DAtomContainer(molGraph,true);
1973
1974 // Set rotatability property as property of IBond
1975 String rotoSpaceFile = "";
1976 if (settings.containsParameters(ParametersType.FS_PARAMS))
1977 {
1978 rotoSpaceFile = ((FragmentSpaceParameters) settings.getParameters(
1979 ParametersType.FS_PARAMS)).getRotSpaceDefFile();
1980 }
1981 RotationalSpaceUtils.defineRotatableBonds(mol, rotoSpaceFile, true,
1982 true, settings.getLogger());
1983
1984 // get the set of possible RCA combinations = ring closures
1985 CyclicGraphHandler cgh = new CyclicGraphHandler(rcParams,fragSpace);
1986
1987 //TODO: remove hard-coded variable that exclude considering all
1988 // combination of rings
1989 boolean onlyRandomCombOfRings = true;
1990
1991 if (onlyRandomCombOfRings)
1992 {
1993 List<Ring> combsOfRings = cgh.getRandomCombinationOfRings(
1994 mol, molGraph, rcParams.getMaxRingClosures());
1995 if (combsOfRings.size() > 0)
1996 {
1997 for (Ring ring : combsOfRings)
1998 {
1999 // Consider the crowding probability
2000 double shot = settings.getRandomizer().nextDouble();
2001 int crowdOnH = EAUtils.getCrowdedness(
2002 ring.getHeadVertex().getEdgeToParent().getSrcAP(),
2003 true);
2004 int crowdOnT = EAUtils.getCrowdedness(
2005 ring.getTailVertex().getEdgeToParent().getSrcAP(),
2006 true);
2007 double crowdProbH = EAUtils.getCrowdingProbability(crowdOnH,
2008 settings);
2009 double crowdProbT = EAUtils.getCrowdingProbability(crowdOnT,
2010 settings);
2011
2012 if (shot < crowdProbH && shot < crowdProbT)
2013 {
2014 molGraph.addRing(ring);
2015 }
2016 }
2017 }
2018 }
2019 else
2020 {
2021 ArrayList<List<Ring>> allCombsOfRings =
2022 cgh.getPossibleCombinationOfRings(mol, molGraph);
2023
2024 // Keep closable chains that are relevant for chelate formation
2025 if (rcParams.buildChelatesMode())
2026 {
2027 ArrayList<List<Ring>> toRemove = new ArrayList<>();
2028 for (List<Ring> setRings : allCombsOfRings)
2029 {
2030 if (!cgh.checkChelatesGraph(molGraph,setRings))
2031 {
2032 toRemove.add(setRings);
2033 }
2034 }
2035
2036 allCombsOfRings.removeAll(toRemove);
2037 if (allCombsOfRings.isEmpty())
2038 {
2039 String msg = "Setup Rings: no combination of rings.";
2040 settings.getLogger().log(Level.INFO, msg);
2041 return false;
2042 }
2043 }
2044
2045 // Select a combination, if any still available
2046 int sz = allCombsOfRings.size();
2047 if (sz > 0)
2048 {
2049 List<Ring> selected = new ArrayList<>();
2050 if (sz == 1)
2051 {
2052 selected = allCombsOfRings.get(0);
2053 }
2054 else
2055 {
2056 int selId = settings.getRandomizer().nextInt(sz);
2057 selected = allCombsOfRings.get(selId);
2058 }
2059
2060 // append new rings to existing list of rings in graph
2061 for (Ring ring : selected)
2062 {
2063 molGraph.addRing(ring);
2064 }
2065 }
2066 }
2067
2068 // Update the IAtomContainer representation
2069 //DENOPTIMMoleculeUtils.removeUsedRCA(mol,molGraph);
2070 // Done already at t3d.convertGraphTo3DAtomContainer
2071 if (res!=null)
2072 {
2073 res[2] = mol;
2074 }
2075 // Update the SMILES representation
2076 if (res!=null)
2077 {
2078 String molsmiles = MoleculeUtils.getSMILESForMolecule(mol,
2079 settings.getLogger());
2080 if (molsmiles == null)
2081 {
2082 String msg = "Evaluation of graph: SMILES is null! "
2083 + molGraph.toString();
2084 settings.getLogger().log(Level.INFO, msg);
2085 molsmiles = "FAIL: NO SMILES GENERATED";
2086 }
2087 res[1] = molsmiles;
2088 }
2089
2090 // Update the INCHI key representation
2091 if (res!=null)
2092 {
2093 String inchikey = MoleculeUtils.getInChIKeyForMolecule(mol,
2094 settings.getLogger());
2095 if (inchikey == null)
2096 {
2097 String msg = "Evaluation of graph: INCHI is null!";
2098 settings.getLogger().log(Level.INFO, msg);
2099 inchikey = "UNDEFINED";
2100 }
2101 res[0] = inchikey;
2102 }
2103
2104 return true;
2105 }
2106
2107//------------------------------------------------------------------------------
2108
2116 protected static boolean containsMolecule(Population mols, String molcode)
2117 {
2118 if(mols.isEmpty())
2119 return false;
2120
2121 for (Candidate mol : mols)
2122 {
2123 if (mol.getUID().compareToIgnoreCase(molcode) == 0)
2124 {
2125 return true;
2126 }
2127 }
2128 return false;
2129 }
2130
2131//------------------------------------------------------------------------------
2132
2139 protected static double[] getFitnesses(Population mols)
2140 {
2141 int k = mols.size();
2142 double[] arr = new double[k];
2143
2144 for (int i=0; i<k; i++)
2145 {
2146 arr[i] = mols.get(i).getFitness();
2147 }
2148 return arr;
2149 }
2150
2151//------------------------------------------------------------------------------
2152
2160 protected static double getPopulationSD(Population molPopulation)
2161 {
2162 double[] fitvals = getFitnesses(molPopulation);
2163 return StatUtils.stddev(fitvals, true);
2164 }
2165
2166//------------------------------------------------------------------------------
2167
2180 public static double getGrowthProbabilityAtLevel(int level, int scheme,
2181 double lambda, double sigmaOne, double sigmaTwo)
2182 {
2183 return getProbability(level, scheme, lambda, sigmaOne, sigmaTwo);
2184 }
2185
2186//------------------------------------------------------------------------------
2187
2200 public static double getMolSizeProbability(DGraph graph,
2201 GAParameters settings)
2202 {
2203 if (!settings.useMolSizeBasedProb())
2204 return 1.0;
2205 int scheme = settings.getMolGrowthProbabilityScheme();
2206 double lambda =settings.getMolGrowthMultiplier();
2207 double sigmaOne = settings.getMolGrowthFactorSteepSigma();
2208 double sigmaTwo = settings.getMolGrowthFactorMiddleSigma();
2209 return getMolSizeProbability(graph, scheme, lambda, sigmaOne, sigmaTwo);
2210 }
2211
2212//------------------------------------------------------------------------------
2213
2226 public static double getMolSizeProbability(DGraph graph,
2227 int scheme, double lambda, double sigmaOne, double sigmaTwo)
2228 {
2229 return getProbability(graph.getHeavyAtomsCount(), scheme, lambda,
2230 sigmaOne, sigmaTwo);
2231 }
2232
2233//------------------------------------------------------------------------------
2234
2245 public static double getProbability(double value,
2246 int scheme, double lambda, double sigmaOne, double sigmaTwo)
2247 {
2248 double prob = 1.0;
2249 if (scheme == 0)
2250 {
2251 double f = Math.exp(-1.0 * value * lambda);
2252 prob = 1 - ((1-f)/(1+f));
2253 }
2254 else if (scheme == 1)
2255 {
2256 prob = 1.0 - Math.tanh(lambda * value);
2257 }
2258 else if (scheme == 2)
2259 {
2260 prob = 1.0-1.0/(1.0 + Math.exp(-sigmaOne * (value - sigmaTwo)));
2261 }
2262 else if (scheme == 3)
2263 {
2264 prob = 1.0;
2265 }
2266 return prob;
2267 }
2268
2269//------------------------------------------------------------------------------
2270
2277 public static double getGrowthByLevelProbability(int level,
2278 GAParameters settings)
2279 {
2280 if (!settings.useLevelBasedProb())
2281 return 1.0;
2282 int scheme = settings.getGrowthProbabilityScheme();
2283 double lambda =settings.getGrowthMultiplier();
2284 double sigmaOne = settings.getGrowthFactorSteepSigma();
2285 double sigmaTwo = settings.getGrowthFactorMiddleSigma();
2286 return getGrowthProbabilityAtLevel(level, scheme, lambda, sigmaOne,
2287 sigmaTwo);
2288 }
2289
2290//------------------------------------------------------------------------------
2291
2301 GAParameters settings)
2302 {
2303 int scheme = settings.getCrowdingProbabilityScheme();
2304 double lambda =settings.getCrowdingMultiplier();
2305 double sigmaOne = settings.getCrowdingFactorSteepSigma();
2306 double sigmaTwo = settings.getCrowdingFactorMiddleSigma();
2307 return getCrowdingProbability(ap, scheme, lambda, sigmaOne, sigmaTwo);
2308 }
2309
2310//------------------------------------------------------------------------------
2311
2325 public static double getCrowdingProbability(int crowdedness,
2326 GAParameters settings)
2327 {
2328 int scheme = settings.getCrowdingProbabilityScheme();
2329 double lambda =settings.getCrowdingMultiplier();
2330 double sigmaOne = settings.getCrowdingFactorSteepSigma();
2331 double sigmaTwo = settings.getCrowdingFactorMiddleSigma();
2332 return getCrowdingProbabilityForCrowdedness(crowdedness, scheme, lambda,
2333 sigmaOne, sigmaTwo);
2334 }
2335
2336//------------------------------------------------------------------------------
2337
2345 public static int getCrowdedness(AttachmentPoint ap)
2346 {
2347 return getCrowdedness(ap,false);
2348 }
2349
2350//------------------------------------------------------------------------------
2351
2361 public static int getCrowdedness(AttachmentPoint ap,
2362 boolean ignoreFreeRCVs)
2363 {
2364 if (ap.getOwner() instanceof EmptyVertex)
2365 {
2366 return 0;
2367 }
2368 int crowdness = 0;
2369 DGraph g = ap.getOwner().getGraphOwner();
2371 {
2372 if (oap.getAtomPositionNumber() == ap.getAtomPositionNumber()
2373 && !oap.isAvailableThroughout()
2374 && oap.getLinkedAP().getOwner()
2375 .getBuildingBlockType() != BBType.CAP)
2376 {
2377 if (ignoreFreeRCVs && oap.getLinkedAP().getOwner().isRCV())
2378 {
2379 if (g.getUsedRCVertices().contains(oap.getLinkedAP().getOwner()))
2380 crowdness = crowdness + 1;
2381 } else {
2382 crowdness = crowdness + 1;
2383 }
2384 }
2385 }
2386 return crowdness;
2387 }
2388
2389//------------------------------------------------------------------------------
2390
2403 public static double getCrowdingProbability(AttachmentPoint ap,
2404 int scheme,
2405 double lambda, double sigmaOne, double sigmaTwo)
2406 {
2407 //Applies only to molecular fragments
2408 if (ap.getOwner() instanceof Fragment == false)
2409 {
2410 return 1.0;
2411 }
2412 int crowdness = getCrowdedness(ap);
2413 return getCrowdingProbabilityForCrowdedness(crowdness, scheme, lambda,
2414 sigmaOne, sigmaTwo);
2415 }
2416
2417//------------------------------------------------------------------------------
2418
2428 public static double getCrowdingProbabilityForCrowdedness(int crowdedness,
2429 int scheme,
2430 double lambda, double sigmaOne, double sigmaTwo)
2431 {
2432 return getProbability(crowdedness, scheme, lambda, sigmaOne, sigmaTwo);
2433 }
2434
2435//------------------------------------------------------------------------------
2436
2445 protected static boolean foundForbiddenEnd(DGraph molGraph,
2446 FragmentSpaceParameters fsParams)
2447 {
2448 List<Vertex> vertices = molGraph.getVertexList();
2449 Set<APClass> classOfForbEnds = fsParams.getFragmentSpace()
2451 for (Vertex vtx : vertices)
2452 {
2453 List<AttachmentPoint> daps = vtx.getAttachmentPoints();
2454 for (AttachmentPoint dp : daps)
2455 {
2456 if (dp.isAvailable())
2457 {
2458 APClass apClass = dp.getAPClass();
2459 if (classOfForbEnds.contains(apClass))
2460 {
2461 String msg = "Forbidden free AP for Vertex: "
2462 + vtx.getVertexId()
2463 + " MolId: " + (vtx.getBuildingBlockId() + 1)
2464 + " Ftype: " + vtx.getBuildingBlockType()
2465 + "\n"+ molGraph+" \n "
2466 + " AP class: " + apClass;
2467 fsParams.getLogger().log(Level.WARNING, msg);
2468 return true;
2469 }
2470 }
2471 }
2472 }
2473 return false;
2474 }
2475
2476//------------------------------------------------------------------------------
2477
2478 protected static void readUID(String infile, HashSet<String> lstInchi)
2479 throws DENOPTIMException
2480 {
2481 ArrayList<String> lst = DenoptimIO.readList(infile);
2482 for (String str:lst)
2483 lstInchi.add(str);
2484 lst.clear();
2485 }
2486
2487//------------------------------------------------------------------------------
2488
2514 //NB: we return a List to retain ordering of the items, but the list must
2515 // not contain redundancies, i.e., lists of AP pairs that are made of the
2516 // same set of AP pairs.
2517 public static List<List<RelatedAPPair>> searchRingFusionSites(
2518 DGraph graph, GAParameters gaParams) throws DENOPTIMException
2519 {
2521 if (gaParams.containsParameters(ParametersType.RC_PARAMS))
2522 {
2523 rcParams = (RingClosureParameters)gaParams.getParameters(
2525 }
2527 if (gaParams.containsParameters(ParametersType.FS_PARAMS))
2528 {
2529 fsParams = (FragmentSpaceParameters)gaParams.getParameters(
2531 }
2532 FragmentSpace fragSpace = fsParams.getFragmentSpace();
2533 Randomizer rng = gaParams.getRandomizer();
2534 boolean projectOnSymmetricAPs = rng.nextBoolean(
2535 gaParams.getSymmetryProbability());
2536 // NB: imposeSymmetryOnAPsOfClass is evaluated inside the
2537 // method searchRingFusionSites
2538 Logger logger = gaParams.getLogger();
2539 return searchRingFusionSites(graph, fragSpace, rcParams,
2540 projectOnSymmetricAPs, logger, rng);
2541 }
2542
2543//------------------------------------------------------------------------------
2544
2570 //NB: we return a List to retain ordering of the items, but the list must
2571 // not contain redundancies, i.e., lists of AP pairs that are made of the
2572 // same set of AP pairs.
2573 public static List<List<RelatedAPPair>> searchRingFusionSites(
2574 DGraph graph, FragmentSpace fragSpace,
2575 RingClosureParameters rcParams, boolean projectOnSymmetricAPs,
2576 Logger logger, Randomizer rng) throws DENOPTIMException
2577 {
2578 // Prepare the empty collector of combinations
2579 List<List<RelatedAPPair>> result = new ArrayList<List<RelatedAPPair>>();
2580
2581 // Most of the work is done on a clone to prevent any modification of the
2582 // 3D molecular representation of the graph, which is here rebuilt in
2583 // a crude way because we only need the connectivity.
2584 DGraph tmpGraph = graph.clone();
2585
2586 // Keep track of which vertexes come from the original graph. We need
2587 // to distinguish them from the capping groups we add here.
2588 Set<Long> originalVertexIDs = new HashSet<Long>();
2589 tmpGraph.getVertexList().stream()
2590 .forEach(v -> originalVertexIDs.add(v.getVertexId()));
2591
2592 // We add capping groups to facilitate the search for substructures
2593 // otherwise we have to write SMARTS that match systems with potentially
2594 // unsaturated valences, and that is a mess.
2595 // Here we change both graph and molecular representation, but it all
2596 // happens on the tmp copy, so the original graph and mol representation
2597 // remain intact. Also, note that the order of atoms does not have a
2598 // role because we only use the position of the atom in the list of atoms
2599 // within the tmp system, and then we use the reference to the
2600 // AP to project the information back into the original system.
2601 tmpGraph.addCappingGroups(fragSpace);
2602
2603 // Get a molecular representation
2604 ThreeDimTreeBuilder t3d = new ThreeDimTreeBuilder(logger, rng);
2605 t3d.setAlignBBsIn3D(false); //3D not needed
2606 IAtomContainer mol = t3d.convertGraphTo3DAtomContainer(tmpGraph, true);
2607
2608 // Search for potential half-ring environments, i.e., sets of atoms
2609 // that belongs to a cyclic system and could hold a chord that would
2610 // define the fused ring.
2611 Map<String, String> smarts = new HashMap<String, String>();
2612 for (BridgeHeadFindingRule rule : rcParams.getBridgeHeadFindingRules())
2613 {
2614 smarts.put(rule.getName(), rule.getSMARTS());
2615 }
2616
2617 ManySMARTSQuery msq = new ManySMARTSQuery(mol, smarts);
2618 if (msq.hasProblems())
2619 {
2620 throw new DENOPTIMException(msq.getMessage());
2621 }
2622 Map<SymmetricSetWithMode,List<RelatedAPPair>> symmRelatedBridgeHeadAPs =
2623 new HashMap<SymmetricSetWithMode,List<RelatedAPPair>>();
2624 List<RelatedAPPair> symBridgeHeadAPs = new ArrayList<RelatedAPPair>();
2625 List<RelatedAPPair> asymBridgeHeadAPs = new ArrayList<RelatedAPPair>();
2626 for (BridgeHeadFindingRule rule : rcParams.getBridgeHeadFindingRules())
2627 {
2628 if (msq.getNumMatchesOfQuery(rule.getName()) == 0)
2629 {
2630 continue;
2631 }
2632
2633 // Get bridge-head atoms
2634 Mappings halfRingAtms = msq.getMatchesOfSMARTS(rule.getName());
2635 // We use a string to facilitate detection of pairs of ids
2636 // irrespectively on the order of ids, i.e., 1-2 vs. 2-1.
2637 Set<String> doneIdPairs = new HashSet<String>();
2638 for (int[] idSubstructure : halfRingAtms)
2639 {
2640 if (idSubstructure.length<2)
2641 {
2642 throw new Error("SMARTS for matching half-ring pattern '"
2643 + rule.getName()
2644 + "' has identified " + idSubstructure.length
2645 + " atoms "
2646 + "instead of at least 2. Modify rule to make it "
2647 + "find 2 or more atoms.");
2648 }
2649
2650 // Potential bridge-head atoms
2651 int[] ids = new int[] {
2652 idSubstructure[rule.getBridgeHeadPositions()[0]],
2653 idSubstructure[rule.getBridgeHeadPositions()[1]]};
2654
2655 IAtom bhA = mol.getAtom(ids[0]);
2656 IAtom bhB = mol.getAtom(ids[1]);
2657
2658 // Avoid duplicate pairs with inverted AP identity
2659 String idPairIdentifier = "";
2660 if (ids[0]<ids[1])
2661 idPairIdentifier = ids[0]+"_"+ids[1];
2662 else
2663 idPairIdentifier = ids[1]+"_"+ids[0];
2664 if (doneIdPairs.contains(idPairIdentifier))
2665 continue;
2666 doneIdPairs.add(idPairIdentifier);
2667
2668 // Bridge-head atoms must have attachment points
2669 if (bhA.getProperty(DENOPTIMConstants.ATMPROPAPS)==null
2670 || bhB.getProperty(DENOPTIMConstants.ATMPROPAPS)==null)
2671 continue;
2672 if (bhA.getProperty(DENOPTIMConstants.ATMPROPVERTEXID)==null
2673 || bhB.getProperty(DENOPTIMConstants.ATMPROPVERTEXID)==null)
2674 throw new IllegalStateException("Atoms in 3d molecular "
2675 + "models of graph objects must have the "
2676 + DENOPTIMConstants.ATMPROPVERTEXID + " property.");
2677
2678 long vrtxIdA = (Long)
2679 bhA.getProperty(DENOPTIMConstants.ATMPROPVERTEXID);
2680 long vrtxIdB = (Long)
2681 bhB.getProperty(DENOPTIMConstants.ATMPROPVERTEXID);
2682
2683 // Each AP on each side can be used
2684 @SuppressWarnings("unchecked")
2685 List<AttachmentPoint> apsOnA = (List<AttachmentPoint>)
2686 bhA.getProperty(DENOPTIMConstants.ATMPROPAPS);
2687 @SuppressWarnings("unchecked")
2688 List<AttachmentPoint> apsOnB = (List<AttachmentPoint>)
2689 bhB.getProperty(DENOPTIMConstants.ATMPROPAPS);
2690 for (int iAPA=0; iAPA<apsOnA.size(); iAPA++)
2691 {
2692 AttachmentPoint copyOfApA = apsOnA.get(iAPA);
2693
2694 // for extreme debug only
2695 /*
2696 System.out.println(rule.getName()+" "+idPairIdentifier+" "
2697 +MoleculeUtils.getAtomRef(bhA, mol)+"-"
2698 +MoleculeUtils.getAtomRef(bhB, mol)+" "
2699 +copyOfApA.getIndexInOwner()
2700 +" in "+copyOfApA.getOwner());
2701 */
2702
2703 if (!canBeUsedForRingFusion(copyOfApA, originalVertexIDs,
2704 fragSpace))
2705 continue;
2706 for (int iAPB=0; iAPB<apsOnB.size(); iAPB++)
2707 {
2708 AttachmentPoint copyOfApB = apsOnB.get(iAPB);
2709
2710 // for extreme debug only
2711 /*
2712 System.out.println(" "+idPairIdentifier+" "
2713 +MoleculeUtils.getAtomRef(bhA, mol)+"-"
2714 +MoleculeUtils.getAtomRef(bhB, mol)+" "
2715 +copyOfApA.getIndexInOwner()
2716 +" in "+copyOfApA.getOwner()
2717 + "--- "
2718 +copyOfApB.getIndexInOwner()
2719 +" in "+copyOfApB.getOwner());
2720 */
2721
2722 if (!canBeUsedForRingFusion(copyOfApB, originalVertexIDs,
2723 fragSpace))
2724 continue;
2725
2726 // Now take the references to the actual APs
2727 AttachmentPoint apA = tmpGraph.getVertexWithId(vrtxIdA)
2728 .getAPWithId(copyOfApA.getID());
2729 AttachmentPoint apB = tmpGraph.getVertexWithId(vrtxIdB)
2730 .getAPWithId(copyOfApB.getID());
2731 if (apA==null || apB==null)
2732 continue;
2733
2734 // Now we have identified a pair of APs suitable to ring fusion
2735 RelatedAPPair pair = new RelatedAPPair(apA, apB, rule,
2736 rule.getName());
2737
2738 //Record symmetric relations
2739 SymmetricAPs symInA = apA.getOwner().getSymmetricAPs(apA);
2740 SymmetricAPs symInB = apB.getOwner().getSymmetricAPs(apB);
2741 if (symInA.size()!=0 && symInB.size()!=0)
2742 {
2743 if (symInA==symInB)
2744 {
2745 storePairsSymmetricRelations(pair, symInA,
2746 symmRelatedBridgeHeadAPs);
2747 } else {
2748 storePairsSymmetricRelations(pair, symInA,
2749 symmRelatedBridgeHeadAPs);
2750 storePairsSymmetricRelations(pair, symInB,
2751 symmRelatedBridgeHeadAPs);
2752 }
2753 symBridgeHeadAPs.add(pair);
2754 } else {
2755 asymBridgeHeadAPs.add(pair);
2756 }
2757 }
2758 }
2759 }
2760 }
2761 if (asymBridgeHeadAPs.size()==0 && symBridgeHeadAPs.size()==0)
2762 {
2763 return result;
2764 }
2765
2766 // Collect potential set of pairs of APs that can be used to create
2767 // fused ring systems accounting for symmetric AP relations.
2768 List<List<RelatedAPPair>> candidateBridgeHeadAPPairs =
2769 new ArrayList<List<RelatedAPPair>>();
2770 if (symmRelatedBridgeHeadAPs.size()>0)
2771 {
2772 for (SymmetricSetWithMode key : symmRelatedBridgeHeadAPs.keySet())
2773 {
2774 List<RelatedAPPair> chosenSymSet =
2775 symmRelatedBridgeHeadAPs.get(key);
2776
2777 @SuppressWarnings("unchecked")
2778 SymmetricSet<AttachmentPoint> symmRelatedAPs =
2779 (SymmetricSet<AttachmentPoint>) key.getItems();
2780 boolean apcImposedSymm = fragSpace.imposeSymmetryOnAPsOfClass(
2781 symmRelatedAPs.get(0).getAPClass());
2782
2783 if (projectOnSymmetricAPs || apcImposedSymm)
2784 {
2785 // We try to get the biggest combination (k is the size)
2786 // but we do limit to avoid combinatorial explosion.
2787 for (int k=Math.min(chosenSymSet.size(), 6); k>0; k--)
2788 {
2789 // Generate combinations that use non-overlapping pairs of APs
2790 List<List<RelatedAPPair>> combs = combineRelatedAPPair(
2791 chosenSymSet, k, 50);
2792 //TODO: make limit of combinations tuneable?
2793
2794 if (combs.size()>0)
2795 {
2796 // We keep only combinations that are not already
2797 // among previously known ones
2798 for (List<RelatedAPPair> comb : combs)
2799 {
2800 boolean isNew = true;
2801 for (List<RelatedAPPair> knownComb :
2802 candidateBridgeHeadAPPairs)
2803 {
2804 if (knownComb.containsAll(comb)
2805 && comb.containsAll(knownComb))
2806 {
2807 isNew = false;
2808 break;
2809 }
2810 }
2811 if (isNew)
2812 {
2813 candidateBridgeHeadAPPairs.add(comb);
2814 for (RelatedAPPair pair : comb)
2815 symBridgeHeadAPs.remove(pair);
2816 }
2817 }
2818 break;
2819 }
2820 }
2821 }
2822 }
2823 // Add left over pairs, if any.
2824 for (RelatedAPPair pair : symBridgeHeadAPs)
2825 {
2826 List<RelatedAPPair> single = new ArrayList<RelatedAPPair>();
2827 single.add(pair);
2828 candidateBridgeHeadAPPairs.add(single);
2829 }
2830 }
2831 for (RelatedAPPair pair : asymBridgeHeadAPs)
2832 {
2833 List<RelatedAPPair> single = new ArrayList<RelatedAPPair>();
2834 single.add(pair);
2835 candidateBridgeHeadAPPairs.add(single);
2836 }
2837
2838 // Project ring fusions into the actual graph (considering symmetry)
2839 for (List<RelatedAPPair> combOnTmpGraph : candidateBridgeHeadAPPairs)
2840 {
2841 List<RelatedAPPair> combOnOriginalGraph =
2842 new ArrayList<RelatedAPPair>();
2843 for (RelatedAPPair pairOnTmpGraph : combOnTmpGraph)
2844 {
2845 Vertex headVertexOnGraph = graph.getVertexAtPosition(
2846 tmpGraph.indexOf(pairOnTmpGraph.apA.getOwner()));
2847 int apHeadID = pairOnTmpGraph.apA.getIndexInOwner();
2848 List<Vertex> symHeadVrts = graph.getSymVerticesForVertex(
2849 headVertexOnGraph);
2850 if (symHeadVrts.size()==0)
2851 symHeadVrts.add(headVertexOnGraph);
2852
2853 Vertex tailVertexOnGraph = graph.getVertexAtPosition(
2854 tmpGraph.indexOf(pairOnTmpGraph.apB.getOwner()));
2855 int apTailID = pairOnTmpGraph.apB.getIndexInOwner();
2856 List<Vertex> symTailVrts = graph.getSymVerticesForVertex(
2857 tailVertexOnGraph);
2858 if (symTailVrts.size()==0)
2859 symTailVrts.add(tailVertexOnGraph);
2860
2861 int numPairs = Math.min(symHeadVrts.size(), symTailVrts.size());
2862 for (int iPair=0; iPair<numPairs; iPair++)
2863 {
2864 RelatedAPPair pairOnOriginalGraph = new RelatedAPPair(
2865 symHeadVrts.get(iPair).getAP(apHeadID),
2866 symTailVrts.get(iPair).getAP(apTailID),
2867 pairOnTmpGraph.property,
2868 pairOnTmpGraph.propID);
2869 combOnOriginalGraph.add(pairOnOriginalGraph);
2870 }
2871 }
2872 result.add(combOnOriginalGraph);
2873 }
2874 return result;
2875 }
2876
2877//------------------------------------------------------------------------------
2878
2879 private static List<List<RelatedAPPair>> combineRelatedAPPair(
2880 List<RelatedAPPair> pool, int k, int limit)
2881 {
2882 List<RelatedAPPair> tmp = new ArrayList<RelatedAPPair>();
2883 List<List<RelatedAPPair>> allCombs = new ArrayList<List<RelatedAPPair>>();
2884 combineRelatedAPPairUtil(pool, 0, k, tmp, allCombs, limit);
2885 return allCombs;
2886 }
2887
2888//------------------------------------------------------------------------------
2889
2890 private static void combineRelatedAPPairUtil(List<RelatedAPPair> pool,
2891 int left, int k,
2892 List<RelatedAPPair> tmp,
2893 List<List<RelatedAPPair>> allCombs, int limit)
2894 {
2895 // PRevent combinatorial explosion: stop if the number of combinations
2896 // grown above the limit
2897 if (allCombs.size()>=limit)
2898 return;
2899
2900 // For last iteration: save answer
2901 if (k == 0)
2902 {
2903 if (!apPairsAreOverlapping(tmp))
2904 {
2905 List<RelatedAPPair> oneComb = new ArrayList<RelatedAPPair>(tmp);
2906 allCombs.add(oneComb);
2907 }
2908 return;
2909 }
2910 // In normal iteration, do recursion
2911 for (int i=left; i<pool.size(); ++i)
2912 {
2913 RelatedAPPair next = pool.get(i);
2914 if (shareAPs(next, tmp))
2915 {
2916 continue;
2917 }
2918 tmp.add(next);
2919 combineRelatedAPPairUtil(pool, i + 1, k-1, tmp, allCombs, limit);
2920 tmp.remove(tmp.size() - 1);
2921 }
2922 }
2923
2924//------------------------------------------------------------------------------
2925
2927 SymmetricAPs symAPs,
2928 Map<SymmetricSetWithMode,List<RelatedAPPair>> storage)
2929 {
2930 SymmetricSetWithMode key = new SymmetricSetWithMode(symAPs, pair.propID);
2931 if (storage.containsKey(key))
2932 {
2933 storage.get(key).add(pair);
2934 } else {
2935 List<RelatedAPPair> lst = new ArrayList<RelatedAPPair>();
2936 lst.add(pair);
2937 storage.put(key, lst);
2938 }
2939 }
2940
2941//------------------------------------------------------------------------------
2942
2951 public static Boolean apPairsAreOverlapping(Iterable<RelatedAPPair> pairs)
2952 {
2953 Set<AttachmentPoint> aps = new HashSet<AttachmentPoint>();
2954
2955 for (RelatedAPPair pair : pairs)
2956 {
2957 if (aps.contains(pair.apA) || aps.contains(pair.apB))
2958 {
2959 return true;
2960 }
2961 aps.add(pair.apA);
2962 aps.add(pair.apB);
2963 }
2964 return false;
2965 }
2966
2967//------------------------------------------------------------------------------
2968
2977 public static Boolean shareAPs(RelatedAPPair pairA,
2978 Iterable<RelatedAPPair> lstB)
2979 {
2980 Set<AttachmentPoint> aps = new HashSet<AttachmentPoint>();
2981 for (RelatedAPPair pairB : lstB)
2982 {
2983 aps.add(pairB.apA);
2984 aps.add(pairB.apB);
2985 }
2986 return aps.contains(pairA.apA) || aps.contains(pairA.apB);
2987 }
2988
2989//------------------------------------------------------------------------------
2990
3013 private static boolean canBeUsedForRingFusion(AttachmentPoint ap,
3014 Set<Long> originalVertexIDs, FragmentSpace fs)
3015 {
3016 if (ap.isAvailableThroughout()
3017 || !originalVertexIDs.contains(
3019 {
3020 if (fs.getRCCompatibilityMatrix().containsKey(ap.getAPClass()))
3021 return true;
3022 }
3023 return false;
3024 }
3025
3026//------------------------------------------------------------------------------
3027
3040 public static List<Vertex> getUsableAromaticBridges(
3041 String elInIncomingFrag, int[] allowedLengths,
3042 FragmentSpace fragSpace)
3043 {
3044 List<Vertex> usableBridgesOriginals =
3045 fragSpace.getVerticesWithAPClassStartingWith(elInIncomingFrag);
3046 List<Vertex> usableBridges = new ArrayList<Vertex>();
3047 final String rootAPC = elInIncomingFrag;
3048 for (Vertex bridge : usableBridgesOriginals)
3049 {
3050 IAtomContainer iacFrag = bridge.getIAtomContainer();
3051 List<Integer> atomIDs = new ArrayList<Integer>();
3052 bridge.getAttachmentPoints()
3053 .stream()
3054 .filter(ap -> ap.getAPClass().getRule().startsWith(
3055 rootAPC))
3056 .forEach(ap -> atomIDs.add(ap.getAtomPositionNumber()));
3057 ShortestPaths sp = new ShortestPaths(iacFrag, iacFrag.getAtom
3058 (atomIDs.get(0)));
3059 List<IAtom> path = new ArrayList<IAtom>(Arrays.asList(
3060 sp.atomsTo(atomIDs.get(1))));
3061 if (IntStream.of(allowedLengths).anyMatch(x -> x == path.size()))
3062 {
3063 Vertex clone = bridge.clone();
3065 path.size());
3066 usableBridges.add(clone);
3067 }
3068 }
3069 return usableBridges;
3070 }
3071
3072//------------------------------------------------------------------------------
3073
3084 public static List<Vertex> getUsableAliphaticBridges(APClass apcA,
3085 APClass apcB, int[] allowedLengths, FragmentSpace fragSpace)
3086 {
3087 List<Vertex> usableBridges = new ArrayList<Vertex>();
3088
3089 List<APClass> compatApClassesA = fragSpace.getCompatibleAPClasses(apcA);
3090 List<APClass> compatApClassesB = fragSpace.getCompatibleAPClasses(apcB);
3091 for (APClass compatA : compatApClassesA)
3092 {
3093 for (APClass compatB : compatApClassesB)
3094 {
3095 boolean sameAPC = compatA.equals(compatB);
3096 Map<APClass,Integer> apFingerprint =
3097 new HashMap<APClass,Integer>();
3098 if (sameAPC)
3099 {
3100 apFingerprint.put(compatA,2);
3101 } else {
3102 apFingerprint.put(compatA,1);
3103 apFingerprint.put(compatB,1);
3104 }
3105 for (Vertex bridge : fragSpace.getVerticesWithAPFingerprint(
3106 apFingerprint))
3107 {
3108 IAtomContainer iacFrag = bridge.getIAtomContainer();
3109
3110 // Identify APs that can be used for each side
3111 List<AttachmentPoint> apsForA = new ArrayList<AttachmentPoint>();
3112 List<AttachmentPoint> apsForB = new ArrayList<AttachmentPoint>();
3113 for (AttachmentPoint apOnBridge : bridge.getAttachmentPoints())
3114 {
3115 if (compatA.equals(apOnBridge.getAPClass()))
3116 apsForA.add(apOnBridge);
3117 if (compatB.equals(apOnBridge.getAPClass()))
3118 apsForB.add(apOnBridge);
3119 }
3120
3121 // Find combinations of usable APs
3122 for (AttachmentPoint apForA : apsForA)
3123 {
3124 ShortestPaths sp = new ShortestPaths(iacFrag,
3125 iacFrag.getAtom(apForA.getAtomPositionNumber()));
3126 for (AttachmentPoint apForB : apsForB)
3127 {
3128 if (apForA.equals(apForB))
3129 continue;
3130 // Retains only combinations of allowed length
3131 List<IAtom> path = new ArrayList<IAtom>(
3132 Arrays.asList(sp.atomsTo(
3133 apForB.getAtomPositionNumber())));
3134 if (IntStream.of(allowedLengths).anyMatch(
3135 x -> x == path.size()))
3136 {
3137 Vertex clone = bridge.clone();
3138 clone.setProperty(
3140 path.size());
3141 clone.setProperty(
3143 apForA.getIndexInOwner());
3144 clone.setProperty(
3146 apForB.getIndexInOwner());
3147 usableBridges.add(clone);
3148 }
3149 }
3150 }
3151 }
3152 }
3153 }
3154 return usableBridges;
3155 }
3156
3157//------------------------------------------------------------------------------
3158
3159}
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:102
static Boolean shareAPs(RelatedAPPair pairA, Iterable< RelatedAPPair > lstB)
Evaluates if a RelatedAPPair involves the same AttachmentPoint present in a collection.
Definition: EAUtils.java:2977
static void outputFinalResults(Population popln, GAParameters settings)
Saves the final results to disk.
Definition: EAUtils.java:1680
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:387
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:258
static double getGrowthByLevelProbability(int level, GAParameters settings)
Calculates the probability of adding a fragment to the given level.
Definition: EAUtils.java:2277
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:2325
static int chooseNumberOfSitesToMutate(double[] multiSiteMutationProb, double hit)
Takes a decision on how many sites to mutate on a candidate.
Definition: EAUtils.java:219
static void appendVertexesToGraphFollowingEdges(DGraph graph, AtomicInteger vId, List< Vertex > vertexes)
Definition: EAUtils.java:1294
static Candidate readCandidateFromFile(File srcFile, Monitor mnt, GAParameters settings)
Definition: EAUtils.java:764
static Candidate[] selectBasedOnFitness(List< Candidate > eligibleParents, int number, GAParameters settings)
Selects a number of members from the given population.
Definition: EAUtils.java:1486
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:1054
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:1944
static Candidate buildCandidateByXOver(List< Candidate > eligibleParents, Population population, Monitor mnt, GAParameters settings)
Generates a new offspring by performing a crossover operation.
Definition: EAUtils.java:308
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:288
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:3013
static final String NL
Definition: EAUtils.java:132
static void getPopulationFromFile(String filename, Population population, SizeControlledSet uniqueIDsSet, String genDir, GAParameters settings)
Reconstruct the molecular population from the file.
Definition: EAUtils.java:1738
static void writeUID(String outfile, HashSet< String > lstInchi, boolean append)
Definition: EAUtils.java:1795
static HashMap< Integer, ArrayList< String > > lstFragmentClass
Definition: EAUtils.java:123
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:2180
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:1028
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:2245
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:3084
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:1564
static String getPathNameToFinalPopulationFolder(GAParameters settings)
Definition: EAUtils.java:1650
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:1106
static CandidateSource chooseGenerationMethod(GAParameters settings)
Choose one of the methods to make new Candidates.
Definition: EAUtils.java:202
static Locale enUsLocale
Locale used to write reports.
Definition: EAUtils.java:109
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:2300
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:1140
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:2445
static List< List< RelatedAPPair > > searchRingFusionSites(DGraph graph, GAParameters gaParams)
Definition: EAUtils.java:2517
static void setVertexCounterValue(Population population)
Set the Vertex counter value according to the largest value found in the given population.
Definition: EAUtils.java:1828
static Candidate buildCandidateByMutation(List< Candidate > eligibleParents, Monitor mnt, GAParameters settings)
Definition: EAUtils.java:640
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:938
static DGraph buildGraph(GAParameters settings)
Graph construction starts with selecting a random core/scaffold.
Definition: EAUtils.java:1849
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:342
static double[] getFitnesses(Population mols)
Get the fitness values for the list of molecules.
Definition: EAUtils.java:2139
static String getSummaryStatistics(Population popln, GAParameters settings)
Definition: EAUtils.java:1429
static void createFolderForGeneration(int genId, GAParameters settings)
Creates a folder meant to hold all the data generated during a generation.
Definition: EAUtils.java:143
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:2226
static DecimalFormat initialiseFormatter()
Definition: EAUtils.java:115
static int getCrowdedness(AttachmentPoint ap)
Calculate the current crowdedness of the given attachment point.
Definition: EAUtils.java:2345
static int getCrowdedness(AttachmentPoint ap, boolean ignoreFreeRCVs)
Calculate the current crowdedness of the given attachment point.
Definition: EAUtils.java:2361
static HashMap< Integer, ArrayList< Integer > > fragmentPool
Definition: EAUtils.java:104
static List< List< RelatedAPPair > > combineRelatedAPPair(List< RelatedAPPair > pool, int k, int limit)
Definition: EAUtils.java:2879
static void combineRelatedAPPairUtil(List< RelatedAPPair > pool, int left, int k, List< RelatedAPPair > tmp, List< List< RelatedAPPair > > allCombs, int limit)
Definition: EAUtils.java:2890
static void outputPopulationDetails(Population population, String filename, GAParameters settings, boolean printpathNames)
Write out summary for the current GA population.
Definition: EAUtils.java:1370
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:3040
static Vertex selectNonScaffoldNonCapVertex(DGraph g, Randomizer randomizer)
Chose randomly a vertex that is neither scaffold or capping group.
Definition: EAUtils.java:1536
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:2428
static String getPathNameToGenerationFolder(int genID, GAParameters settings)
Definition: EAUtils.java:1614
static double getPopulationSD(Population molPopulation)
Check if fitness values have significant standard deviation.
Definition: EAUtils.java:2160
static String getPathNameToFinalPopulationDetailsFile(GAParameters settings)
Definition: EAUtils.java:1659
static Candidate buildCandidateFromScratch(Monitor mnt, GAParameters settings)
Definition: EAUtils.java:837
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:2403
static boolean containsMolecule(Population mols, String molcode)
Check if the population contains the specified InChi code.
Definition: EAUtils.java:2116
static DecimalFormat df
Format for decimal fitness numbers that overwrites Locale to en_US.
Definition: EAUtils.java:114
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:1078
static List< List< RelatedAPPair > > searchRingFusionSites(DGraph graph, FragmentSpace fragSpace, RingClosureParameters rcParams, boolean projectOnSymmetricAPs, Logger logger, Randomizer rng)
Definition: EAUtils.java:2573
static void storePairsSymmetricRelations(RelatedAPPair pair, SymmetricAPs symAPs, Map< SymmetricSetWithMode, List< RelatedAPPair > > storage)
Definition: EAUtils.java:2926
static void readUID(String infile, HashSet< String > lstInchi)
Definition: EAUtils.java:2478
static final String FSEP
Definition: EAUtils.java:133
static String getPathNameToGenerationDetailsFile(int genID, GAParameters settings)
Definition: EAUtils.java:1630
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:2200
static Population importInitialPopulation(SizeControlledSet uniqueIDsSet, GAParameters settings)
Reads unique identifiers and initial population file according to the GAParameters.
Definition: EAUtils.java:157
static Boolean apPairsAreOverlapping(Iterable< RelatedAPPair > pairs)
Evaluates if any pair of AttachmentPoint pairs involve the same AttachmentPoint, i....
Definition: EAUtils.java:2951
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:7206
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:6855
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:61
abstract Vertex clone()
Returns a deep-copy of this vertex.
int getBuildingBlockId()
Returns the index of the building block that should correspond to the position of the building block ...
Definition: Vertex.java:304
void setVertexId(long vertexId2)
Definition: Vertex.java:281
DGraph getGraphOwner()
Returns the graph this vertex belongs to or null.
Definition: Vertex.java:851
abstract List< AttachmentPoint > getAttachmentPoints()
SymmetricAPs getSymmetricAPs(AttachmentPoint ap)
For the given attachment point index locate the symmetric partners i.e.
Definition: Vertex.java:353
abstract int getHeavyAtomsCount()
void setBuildingBlockType(Vertex.BBType buildingBlockType)
Definition: Vertex.java:325
abstract IAtomContainer getIAtomContainer()
boolean hasFreeAP()
Definition: Vertex.java:520
void setProperty(Object key, Object property)
Definition: Vertex.java:1235
AttachmentPoint getAP(int i)
Get attachment point i on this vertex.
Definition: Vertex.java:1007
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 (a.k.a.
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:128
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:86
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.