$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 {
1148 frgParams.setCuttingRules(cuttingRules);
1149 frgParams.setScaffoldingPolicy(scaffoldingPolicy);
1150 frgParams.setLinearAngleLimit(linearAngleLimit);
1151 frgParams.setEmbedRingsInTemplate(embedRingsInTemplates);
1152 frgParams.setEmbeddedRingsContract(ringTmplContract);
1153 return makeGraphFromFragmentationOfMol(mol, frgParams, fragSpace, monitor);
1154 }
1155
1156//------------------------------------------------------------------------------
1157
1165 public static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol,
1166 FragmenterParameters frgParams) throws DENOPTIMException
1167 {
1168 FragmentSpace fragSpace = null;
1169 if (frgParams.containsParameters(ParametersType.FS_PARAMS))
1170 {
1171 fragSpace = ((FragmentSpaceParameters) frgParams.getParameters(
1172 ParametersType.FS_PARAMS)).getFragmentSpace();
1173 } else {
1174 fragSpace = new FragmentSpace();
1175 }
1176 return makeGraphFromFragmentationOfMol(mol, frgParams, fragSpace, null);
1177 }
1178
1179//------------------------------------------------------------------------------
1180
1202 public static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol,
1203 FragmenterParameters frgParams, FragmentSpace fragSpace, Monitor monitor)
1204 throws DENOPTIMException
1205 {
1206 double linearAngleLimit = frgParams.getLinearAngleLimit();
1207 boolean embedRingsInTemplates = frgParams.embedRingsInTemplate();
1208 ContractLevel ringTmplContract = frgParams.getEmbeddedRingsContract();
1209 ScaffoldingPolicy scaffoldingPolicy = frgParams.getScaffoldingPolicy();
1210
1211 // We expect only Fragments here.
1212 List<Vertex> fragments = FragmenterTools.fragmentation(mol, frgParams);
1213
1214 for (Vertex v : fragments)
1215 {
1216 Fragment frag = (Fragment) v;
1217
1218 // This is done to set the symmetry relations in each vertex
1219 frag.updateAPs();
1220
1221 // Add linearity-breaking dummy atoms
1222 DummyAtomHandler.addDummiesOnLinearities(frag, linearAngleLimit);
1223 }
1224 if (fragments.size()==0)
1225 {
1226 if (monitor!=null)
1227 {
1229 }
1230 throw new DENOPTIMException("Fragmentation of molecule with "
1231 + mol.getAtomCount() + " atoms produced 0 fragments.");
1232 }
1233
1234 // Define which fragment is the scaffold
1235 Vertex scaffold = null;
1236 switch (scaffoldingPolicy)
1237 {
1238 case ELEMENT:
1239 {
1240 for (Vertex v : fragments)
1241 {
1242 if (v instanceof Fragment)
1243 {
1244 boolean setAsScaffold = false;
1245 IAtomContainer iac = v.getIAtomContainer();
1246 for (IAtom atm : iac.atoms())
1247 {
1248 if (scaffoldingPolicy.label.equals(
1250 {
1251 setAsScaffold = true;
1252 break;
1253 }
1254 }
1255 if (setAsScaffold)
1256 {
1257 scaffold = v;
1258 break;
1259 }
1260 }
1261 }
1262 break;
1263 }
1264
1265 default:
1266 case LARGEST_FRAGMENT:
1267 {
1268 try {
1269 scaffold = fragments.stream()
1270 .max(Comparator.comparing(
1272 .get();
1273 } catch (Exception e)
1274 {
1275 if (monitor!=null)
1276 {
1278 }
1279 throw new DENOPTIMException("Cannot get largest fragment "
1280 + "among " + fragments.size() + " fragments.", e);
1281 }
1282 break;
1283 }
1284 }
1285 if (scaffold==null)
1286 {
1287 if (monitor!=null)
1288 {
1290 }
1291 throw new DENOPTIMException("No fragment matches criteria to be "
1292 + "identified as the "
1293 + BBType.SCAFFOLD.toString().toLowerCase() + ".");
1294 }
1295 scaffold.setVertexId(0);
1297
1298 // Build the graph
1299 DGraph graph = new DGraph();
1300 graph.addVertex(scaffold);
1301 AtomicInteger vId = new AtomicInteger(1);
1302 for (int i=1; i<fragments.size(); i++)
1303 {
1304 appendVertexesToGraphFollowingEdges(graph, vId, fragments);
1305 }
1306
1307 // Set symmetry relations: these depend on which scaffold we have chosen
1308 graph.detectSymVertexSets();
1309
1310 // Identify capping groups, i.e., fragments that reflect the capping
1311 // groups found in the fragment space, if any.
1312 if (fragSpace!=null && fragSpace.getCappingMap()!=null)
1313 {
1314 for (Vertex v : graph.getVertexList())
1315 {
1316 if (v.getAttachmentPoints().size()!=1 || v.isRCV())
1317 continue;
1318
1319 APClass srcAPC = v.getAP(0).getLinkedAPThroughout().getAPClass();
1320 APClass capAPC = fragSpace.getAPClassOfCappingVertex(srcAPC);
1321 Vertex cap = fragSpace.getCappingVertexWithAPClass(capAPC);
1322 if (cap==null)
1323 continue;
1324
1325 if (!(v instanceof Fragment && cap instanceof Fragment))
1326 continue;
1327
1328 Fragment f = (Fragment) v;
1329 // NB: here we ignore APClasses and Du atoms
1330 if (f.isIsomorphicTo(cap, true))
1331 {
1333 v.getAP(0).setAPClass(capAPC);
1334 }
1335 }
1336 }
1337
1338 if (embedRingsInTemplates)
1339 {
1340 try {
1342 fragSpace, ringTmplContract);
1343 } catch (DENOPTIMException e) {
1344 graph.cleanup();
1345 if (monitor!=null)
1346 {
1348 }
1349 return null;
1350 }
1351 }
1352
1353 return graph;
1354 }
1355
1356//------------------------------------------------------------------------------
1357
1359 AtomicInteger vId, List<Vertex> vertexes) throws DENOPTIMException
1360 {
1361 // We seek for the last and non-RCV vertex added to the graph
1362 Vertex lastlyAdded = null;
1363 for (int i=-1; i>-4; i--)
1364 {
1365 lastlyAdded = graph.getVertexList().get(
1366 graph.getVertexList().size()+i);
1367 if (!lastlyAdded.isRCV())
1368 break;
1369 }
1370 for (AttachmentPoint apI : lastlyAdded.getAttachmentPoints())
1371 {
1372 if (!apI.isAvailable())
1373 continue;
1374
1375 for (int j=0; j<vertexes.size(); j++)
1376 {
1377 Vertex fragJ = vertexes.get(j);
1378
1379 boolean ringClosure = false;
1380 if (graph.containsVertex(fragJ))
1381 {
1382 ringClosure = true;
1383 }
1384 for (AttachmentPoint apJ : fragJ.getAttachmentPoints())
1385 {
1386 if (apI==apJ)
1387 continue;
1388
1389 if (!apI.isAvailable() || !apJ.isAvailable())
1390 continue;
1391
1392 if (apI.getCutId()==apJ.getCutId())
1393 {
1394 if (ringClosure)
1395 {
1398 BondType.ANY));
1400 rcvI.setVertexId(vId.getAndIncrement());
1401 graph.appendVertexOnAP(apI, rcvI.getAP(0));
1402
1406 rcvJ.setVertexId(vId.getAndIncrement());
1407 graph.appendVertexOnAP(apJ, rcvJ.getAP(0));
1408 graph.addRing(rcvI, rcvJ);
1409 } else {
1411 fragJ.setVertexId(vId.getAndIncrement());
1412 graph.appendVertexOnAP(apI, apJ);
1413
1414 // Recursion into the branch of the graph that is
1415 // rooted onto the lastly added vertex
1417 vertexes);
1418 }
1419 }
1420 }
1421 }
1422 }
1423 }
1424
1425//------------------------------------------------------------------------------
1426
1437 public static void outputPopulationDetails(Population population,
1438 String filename, GAParameters settings, boolean printpathNames)
1439 throws DENOPTIMException
1440 {
1441 StringBuilder sb = new StringBuilder(512);
1443 sb.append(NL);
1444
1445 df.setMaximumFractionDigits(settings.getPrecisionLevel());
1446 df.setMinimumFractionDigits(settings.getPrecisionLevel());
1447
1448 // NB: we consider the configured size of the population, not the actual
1449 // size of list representing the population.
1450 String stats = "";
1451 synchronized (population)
1452 {
1453 List<Candidate> popMembers = new ArrayList<Candidate>();
1454 for (int i=0; i<settings.getPopulationSize(); i++)
1455 {
1456 Candidate mol = population.get(i);
1457 popMembers.add(mol);
1458 if (mol != null)
1459 {
1460 String mname = new File(mol.getSDFFile()).getName();
1461 if (mname != null)
1462 sb.append(String.format("%-20s", mname));
1463
1464 sb.append(String.format("%-20s",
1465 mol.getGraph().getGraphId()));
1466 sb.append(String.format("%-30s", mol.getUID()));
1467 sb.append(df.format(mol.getFitness()));
1468
1469 if (printpathNames)
1470 {
1471 sb.append(" ").append(mol.getSDFFile());
1472 }
1473
1474 sb.append(System.getProperty("line.separator"));
1475 }
1476 }
1477
1478 // calculate descriptive statistics for the population
1479 stats = getSummaryStatistics(population, settings);
1480
1481 if (settings.savePopFile())
1482 {
1483 File dest = new File(filename.replaceAll("\\.txt$", ".sdf"));
1484 DenoptimIO.writeCandidatesToFile(dest, popMembers, false);
1485 }
1486 }
1487 if (stats.trim().length() > 0)
1488 sb.append(stats);
1489 DenoptimIO.writeData(filename, sb.toString(), false);
1490
1491 sb.setLength(0);
1492 }
1493
1494//------------------------------------------------------------------------------
1495
1496 private static String getSummaryStatistics(Population popln,
1497 GAParameters settings)
1498 {
1499 double[] fitness = getFitnesses(popln);
1500 double sdev = StatUtils.stddev(fitness, true);
1501 String res = "";
1502 df.setMaximumFractionDigits(settings.getPrecisionLevel());
1503
1504 StringBuilder sb = new StringBuilder(128);
1505 sb.append(NL+NL+"#####POPULATION SUMMARY#####"+NL);
1506 int n = popln.size();
1507 sb.append(String.format("%-30s", "SIZE:"));
1508 sb.append(String.format("%12s", n));
1509 sb.append(NL);
1510 double f;
1511 f = StatUtils.max(fitness);
1512 sb.append(String.format("%-30s", "MAX:")).append(df.format(f));
1513 sb.append(NL);
1514 f = StatUtils.min(fitness);
1515 sb.append(String.format("%-30s", "MIN:")).append(df.format(f));
1516 sb.append(NL);
1517 f = StatUtils.mean(fitness);
1518 sb.append(String.format("%-30s", "MEAN:")).append(df.format(f));
1519 sb.append(NL);
1520 f = StatUtils.median(fitness);
1521 sb.append(String.format("%-30s", "MEDIAN:")).append(df.format(f));
1522 sb.append(NL);
1523 f = StatUtils.stddev(fitness, true);
1524 sb.append(String.format("%-30s", "STDDEV:")).append(df.format(f));
1525 sb.append(NL);
1526 if (sdev > 0.0001)
1527 {
1528 f = StatUtils.skewness(fitness, true);
1529 sb.append(String.format("%-30s", "SKEW:")).append(df.format(f));
1530 sb.append(NL);
1531 } else {
1532 sb.append(String.format("%-30s", "SKEW:")).append(" NaN (sdev too small)");
1533 sb.append(NL);
1534 }
1535
1536 res = sb.toString();
1537 sb.setLength(0);
1538
1539 return res;
1540 }
1541
1542//------------------------------------------------------------------------------
1543
1554 List<Candidate> eligibleParents, int number, GAParameters settings)
1555 {
1556 Candidate[] mates = new Candidate[number];
1557 switch (settings.getSelectionStrategyType())
1558 {
1559 case 1:
1560 mates = SelectionHelper.performTournamentSelection(eligibleParents,
1561 number, settings);
1562 break;
1563 case 2:
1564 mates = SelectionHelper.performRWS(eligibleParents, number, settings);
1565 break;
1566 case 3:
1567 mates = SelectionHelper.performSUS(eligibleParents, number, settings);
1568 break;
1569 case 4:
1570 mates = SelectionHelper.performRandomSelection(eligibleParents, number,
1571 settings);
1572 break;
1573 }
1574
1575 if (settings.recordMateSelection())
1576 {
1577 String matesStr="";
1578 for (int i=0; i < mates.length; i++)
1579 {
1580 if (i>0)
1581 matesStr = matesStr + settings.NL;
1582 matesStr = matesStr + mates[i].getUID();
1583 }
1584 try
1585 {
1586 DenoptimIO.writeData(settings.getMonitorFile()+".mates",
1587 matesStr, true);
1588 } catch (DENOPTIMException e)
1589 {
1590 // TODO Auto-generated catch block
1591 e.printStackTrace();
1592 }
1593 }
1594
1595 return mates;
1596 }
1597
1598//------------------------------------------------------------------------------
1599
1604 Randomizer randomizer)
1605 {
1606 List<Vertex> candidates = new ArrayList<Vertex>(
1607 g.getVertexList());
1608 candidates.removeIf(v ->
1609 v.getBuildingBlockType() == BBType.SCAFFOLD
1610 || v.getBuildingBlockType() == BBType.CAP);
1611 return randomizer.randomlyChooseOne(candidates);
1612 }
1613
1614//------------------------------------------------------------------------------
1615
1631 protected static XoverSite performFBCC(
1632 List<Candidate> eligibleParents, Population population,
1633 int[] choiceOfParents, int choiceOfXOverSites, GAParameters settings)
1634 {
1635 Candidate parentA = null;
1636 if (choiceOfParents==null)
1637 parentA = selectBasedOnFitness(eligibleParents, 1, settings)[0];
1638 else
1639 parentA = eligibleParents.get(choiceOfParents[0]);
1640
1641 if (parentA == null)
1642 return null;
1643
1646 {
1647 fsParams = (FragmentSpaceParameters)settings.getParameters(
1649 }
1650 FragmentSpace fragSpace = fsParams.getFragmentSpace();
1651 List<Candidate> matesCompatibleWithFirst = population.getXoverPartners(
1652 parentA, eligibleParents, fragSpace);
1653 if (matesCompatibleWithFirst.size() == 0)
1654 return null;
1655
1656 Candidate parentB = null;
1657 if (choiceOfParents==null)
1658 {
1659 parentB = selectBasedOnFitness(matesCompatibleWithFirst, 1,
1660 settings)[0];
1661 } else {
1662 parentB = eligibleParents.get(choiceOfParents[1]);
1663 }
1664 if (parentB == null)
1665 return null;
1666
1667 XoverSite result = null;
1668 if (choiceOfXOverSites<0)
1669 {
1670 result = settings.getRandomizer().randomlyChooseOne(
1671 population.getXoverSites(parentA, parentB));
1672 } else {
1673 result = population.getXoverSites(parentA, parentB).get(
1674 choiceOfXOverSites);
1675 }
1676 return result;
1677 }
1678
1679//------------------------------------------------------------------------------
1680
1681 public static String getPathNameToGenerationFolder(int genID,
1682 GAParameters settings)
1683 {
1684 StringBuilder sb = new StringBuilder(32);
1685
1686 int ndigits = String.valueOf(settings.getNumberOfGenerations()).length();
1687
1688 sb.append(settings.getDataDirectory()).append(FSEP).append(
1690 .append(GeneralUtils.getPaddedString(ndigits, genID));
1691
1692 return sb.toString();
1693 }
1694
1695//------------------------------------------------------------------------------
1696
1697 public static String getPathNameToGenerationDetailsFile(int genID,
1698 GAParameters settings)
1699 {
1700 StringBuilder sb = new StringBuilder(32);
1701
1702 int ndigits = String.valueOf(settings.getNumberOfGenerations()).length();
1703
1704 sb.append(settings.getDataDirectory()).append(FSEP)
1706 .append(GeneralUtils.getPaddedString(ndigits, genID))
1707 .append(FSEP)
1709 .append(GeneralUtils.getPaddedString(ndigits, genID))
1710 .append(".txt");
1711
1712 return sb.toString();
1713 }
1714
1715//------------------------------------------------------------------------------
1716
1718 {
1719 StringBuilder sb = new StringBuilder(32);
1720 sb.append(settings.getDataDirectory()).append(FSEP).append("Final");
1721 return sb.toString();
1722 }
1723
1724//------------------------------------------------------------------------------
1725
1727 GAParameters settings)
1728 {
1729 StringBuilder sb = new StringBuilder(32);
1730 sb.append(settings.getDataDirectory()).append(FSEP).append("Final")
1731 .append(FSEP).append("Final.txt");
1732 return sb.toString();
1733 }
1734
1735//------------------------------------------------------------------------------
1736
1747 protected static void outputFinalResults(Population popln,
1748 GAParameters settings) throws DENOPTIMException
1749 {
1750 String dirName = EAUtils.getPathNameToFinalPopulationFolder(settings);
1751 denoptim.files.FileUtils.createDirectory(dirName);
1752 File fileDir = new File(dirName);
1753
1754 boolean intermediateCandidatesAreOnDisk =
1755 ((FitnessParameters) settings.getParameters(
1756 ParametersType.FIT_PARAMS)).writeCandidatesOnDisk();
1757
1758 for (int i=0; i<popln.size(); i++)
1759 {
1760 Candidate c = popln.get(i);
1761 String sdfile = c.getSDFFile();
1762 String imgfile = c.getImageFile();
1763
1764 try {
1765 if (intermediateCandidatesAreOnDisk && sdfile!=null)
1766 {
1767 FileUtils.copyFileToDirectory(new File(sdfile), fileDir);
1768 } else {
1769 File candFile = new File(fileDir, c.getName()
1771 c.setSDFFile(candFile.getAbsolutePath());
1772 DenoptimIO.writeCandidateToFile(candFile, c, false);
1773 }
1774 } catch (IOException ioe) {
1775 throw new DENOPTIMException("Failed to copy file '"
1776 + sdfile + "' to '" + fileDir + "' for candidate "
1777 + c.getName(), ioe);
1778 }
1779 if (imgfile != null && intermediateCandidatesAreOnDisk)
1780 {
1781 try {
1782 FileUtils.copyFileToDirectory(new File(imgfile), fileDir);
1783 } catch (IOException ioe) {
1784 throw new DENOPTIMException("Failed to copy file '"
1785 + imgfile + "' to '" + fileDir + "' for candidate "
1786 + c.getName(), ioe);
1787 }
1788 }
1789 }
1792 settings, true);
1793 }
1794
1795//------------------------------------------------------------------------------
1796
1805 protected static void getPopulationFromFile(String filename,
1806 Population population, SizeControlledSet uniqueIDsSet,
1807 String genDir, GAParameters settings)
1808 throws DENOPTIMException, IOException
1809 {
1810 List<Candidate> candidates = DenoptimIO.readCandidates(
1811 new File(filename), true);
1812 if (candidates.size() == 0)
1813 {
1814 String msg = "Found 0 candidates in file " + filename;
1815 settings.getLogger().log(Level.SEVERE, msg);
1816 throw new DENOPTIMException(msg);
1817 }
1818
1819 for (Candidate candidate : candidates)
1820 {
1821 if (uniqueIDsSet.addNewUniqueEntry(candidate.getUID()))
1822 {
1824 int gctr = GraphUtils.getUniqueGraphIndex();
1825
1826 String molName = "M" + GeneralUtils.getPaddedString(8, ctr);
1827 candidate.setName(molName);
1828 candidate.getGraph().setGraphId(gctr);
1829 candidate.getGraph().setLocalMsg("INITIAL_POPULATION");
1830 String sdfPathName = genDir + System.getProperty("file.separator")
1832 candidate.setSDFFile(sdfPathName);
1833 candidate.setImageFile(null);
1834
1835 // Write the candidate to file as if it had been processed by fitness provider
1836 DenoptimIO.writeCandidateToFile(new File(sdfPathName),
1837 candidate, false);
1838
1839 population.add(candidate);
1840 } else {
1841 settings.getLogger().log(Level.WARNING, "Candidate from intial "
1842 + "population file '" + filename
1843 + "' is rejected because its identifier is "
1844 + "already listed among the previously visited "
1845 + "identifiers.");
1846 }
1847 }
1848
1849 if (population.isEmpty())
1850 {
1851 String msg = "Population is still empty after having processes "
1852 + candidates.size() + " candidates from file " + filename;
1853 settings.getLogger().log(Level.SEVERE, msg);
1854 throw new DENOPTIMException(msg);
1855 }
1856
1857 setVertexCounterValue(population);
1858 }
1859
1860//------------------------------------------------------------------------------
1861
1862 protected static void writeUID(String outfile, HashSet<String> lstInchi,
1863 boolean append) throws DENOPTIMException
1864 {
1865 StringBuilder sb = new StringBuilder(256);
1866 Iterator<String> iter = lstInchi.iterator();
1867
1868 boolean first = true;
1869 while(iter.hasNext())
1870 {
1871 if (first)
1872 {
1873 sb.append(iter.next());
1874 first = false;
1875 }
1876 else
1877 {
1878 sb.append(NL).append(iter.next());
1879 }
1880 }
1881
1882 DenoptimIO.writeData(outfile, sb.toString(), append);
1883 sb.setLength(0);
1884 }
1885
1886//------------------------------------------------------------------------------
1887
1895 protected static void setVertexCounterValue(Population population)
1896 throws DENOPTIMException
1897 {
1898 long val = Long.MIN_VALUE;
1899 for (Candidate popln1 : population)
1900 {
1901 DGraph g = popln1.getGraph();
1902 val = Math.max(val, g.getMaxVertexId());
1903 }
1905 }
1906
1907//------------------------------------------------------------------------------
1908
1916 protected static DGraph buildGraph(GAParameters settings)
1917 throws DENOPTIMException
1918 {
1920 if (settings.containsParameters(ParametersType.FS_PARAMS))
1921 {
1922 fsParams = (FragmentSpaceParameters)settings.getParameters(
1924 }
1925 FragmentSpace fragSpace = fsParams.getFragmentSpace();
1926
1927 DGraph graph = new DGraph();
1929
1930 // building a molecule starts by selecting a random scaffold
1931 Vertex scafVertex = fragSpace.makeRandomScaffold();
1932
1933 // add the scaffold as a vertex
1934 graph.addVertex(scafVertex);
1935 graph.setLocalMsg("NEW");
1936
1937 if (scafVertex instanceof Template
1938 && !((Template) scafVertex).getContractLevel().equals(
1940 {
1941 Monitor mnt = new Monitor();
1942 mnt.name = "IntraTemplateBuild";
1943 List<Vertex> initialMutableSites = graph.getMutableSites(
1944 settings.getExcludedMutationTypes());
1945 for (Vertex mutableSite : initialMutableSites)
1946 {
1947 // This accounts for the possibility that a mutation changes a
1948 // branch of the initial graph or deletes vertexes.
1949 if (!graph.containsOrEmbedsVertex(mutableSite))
1950 continue;
1951
1952 // TODO: need to discriminate between EmptyVertexes that
1953 // represent placeholders and those that represent property carriers
1954 // The first should always be mutated (as it happens now), but
1955 // the latter should be kept intact.
1956 // Possibly this is a case for subclassing the EmptyVertex.
1957
1958 if (!GraphOperations.performMutation(mutableSite, mnt,
1959 settings))
1960 {
1963 return null;
1964 }
1965 }
1966 }
1967
1968 // get settings //TODO: this should happen inside RunTimeParameters
1970 if (settings.containsParameters(ParametersType.RC_PARAMS))
1971 {
1972 rcParams = (RingClosureParameters)settings.getParameters(
1974 }
1975//TODO this works only for scaffolds at the moment. make the preference for
1976// fragments that lead to known closable chains operate also when fragments are
1977// the "turning point".
1980 scafVertex.getBuildingBlockId()));
1981
1982 if (scafVertex.hasFreeAP())
1983 {
1984 GraphOperations.extendGraph(scafVertex, true, false, settings);
1985 }
1986
1987 if (!(scafVertex instanceof Template)
1988 && graph.getVertexCount() == 0)
1989 {
1990 return null;
1991 }
1992
1993 graph.addCappingGroups(fragSpace);
1994 return graph;
1995 }
1996
1997//------------------------------------------------------------------------------
1998
2011 protected static boolean setupRings(Object[] res, DGraph molGraph,
2012 GAParameters settings) throws DENOPTIMException
2013 {
2014 // get settings //TODO: this should happen inside RunTimeParameters
2016 if (settings.containsParameters(ParametersType.RC_PARAMS))
2017 {
2018 rcParams = (RingClosureParameters)settings.getParameters(
2020 }
2022 if (settings.containsParameters(ParametersType.FS_PARAMS))
2023 {
2024 fsParams = (FragmentSpaceParameters)settings.getParameters(
2026 }
2027 FragmentSpace fragSpace = fsParams.getFragmentSpace();
2028
2029 if (!fragSpace.useAPclassBasedApproach())
2030 return true;
2031
2032 if (!rcParams.allowRingClosures())
2033 return true;
2034
2035 // get a atoms/bonds molecular representation (no 3D needed)
2036 ThreeDimTreeBuilder t3d = new ThreeDimTreeBuilder(settings.getLogger(),
2037 settings.getRandomizer());
2038 t3d.setAlignBBsIn3D(false);
2039 IAtomContainer mol = t3d.convertGraphTo3DAtomContainer(molGraph,true);
2040
2041 // Set rotatability property as property of IBond
2042 String rotoSpaceFile = "";
2043 if (settings.containsParameters(ParametersType.FS_PARAMS))
2044 {
2045 rotoSpaceFile = ((FragmentSpaceParameters) settings.getParameters(
2046 ParametersType.FS_PARAMS)).getRotSpaceDefFile();
2047 }
2048 RotationalSpaceUtils.defineRotatableBonds(mol, rotoSpaceFile, true,
2049 true, settings.getLogger());
2050
2051 // get the set of possible RCA combinations = ring closures
2052 CyclicGraphHandler cgh = new CyclicGraphHandler(rcParams,fragSpace);
2053
2054 //TODO: remove hard-coded variable that exclude considering all
2055 // combination of rings
2056 boolean onlyRandomCombOfRings = true;
2057
2058 if (onlyRandomCombOfRings)
2059 {
2060 List<Ring> combsOfRings = cgh.getRandomCombinationOfRings(
2061 mol, molGraph, rcParams.getMaxRingClosures());
2062 if (combsOfRings.size() > 0)
2063 {
2064 for (Ring ring : combsOfRings)
2065 {
2066 // Consider the crowding probability
2067 double shot = settings.getRandomizer().nextDouble();
2068 int crowdOnH = EAUtils.getCrowdedness(
2069 ring.getHeadVertex().getEdgeToParent().getSrcAP(),
2070 true);
2071 int crowdOnT = EAUtils.getCrowdedness(
2072 ring.getTailVertex().getEdgeToParent().getSrcAP(),
2073 true);
2074 double crowdProbH = EAUtils.getCrowdingProbability(crowdOnH,
2075 settings);
2076 double crowdProbT = EAUtils.getCrowdingProbability(crowdOnT,
2077 settings);
2078
2079 if (shot < crowdProbH && shot < crowdProbT)
2080 {
2081 molGraph.addRing(ring);
2082 }
2083 }
2084 }
2085 }
2086 else
2087 {
2088 ArrayList<List<Ring>> allCombsOfRings =
2089 cgh.getPossibleCombinationOfRings(mol, molGraph);
2090
2091 // Keep closable chains that are relevant for chelate formation
2092 if (rcParams.buildChelatesMode())
2093 {
2094 ArrayList<List<Ring>> toRemove = new ArrayList<>();
2095 for (List<Ring> setRings : allCombsOfRings)
2096 {
2097 if (!cgh.checkChelatesGraph(molGraph,setRings))
2098 {
2099 toRemove.add(setRings);
2100 }
2101 }
2102
2103 allCombsOfRings.removeAll(toRemove);
2104 if (allCombsOfRings.isEmpty())
2105 {
2106 String msg = "Setup Rings: no combination of rings.";
2107 settings.getLogger().log(Level.INFO, msg);
2108 return false;
2109 }
2110 }
2111
2112 // Select a combination, if any still available
2113 int sz = allCombsOfRings.size();
2114 if (sz > 0)
2115 {
2116 List<Ring> selected = new ArrayList<>();
2117 if (sz == 1)
2118 {
2119 selected = allCombsOfRings.get(0);
2120 }
2121 else
2122 {
2123 int selId = settings.getRandomizer().nextInt(sz);
2124 selected = allCombsOfRings.get(selId);
2125 }
2126
2127 // append new rings to existing list of rings in graph
2128 for (Ring ring : selected)
2129 {
2130 molGraph.addRing(ring);
2131 }
2132 }
2133 }
2134
2135 // Update the IAtomContainer representation
2136 //DENOPTIMMoleculeUtils.removeUsedRCA(mol,molGraph);
2137 // Done already at t3d.convertGraphTo3DAtomContainer
2138 if (res!=null)
2139 {
2140 res[2] = mol;
2141 }
2142 // Update the SMILES representation
2143 if (res!=null)
2144 {
2145 String molsmiles = MoleculeUtils.getSMILESForMolecule(mol,
2146 settings.getLogger());
2147 if (molsmiles == null)
2148 {
2149 String msg = "Evaluation of graph: SMILES is null! "
2150 + molGraph.toString();
2151 settings.getLogger().log(Level.INFO, msg);
2152 molsmiles = "FAIL: NO SMILES GENERATED";
2153 }
2154 res[1] = molsmiles;
2155 }
2156
2157 // Update the INCHI key representation
2158 if (res!=null)
2159 {
2160 String inchikey = MoleculeUtils.getInChIKeyForMolecule(mol,
2161 settings.getLogger());
2162 if (inchikey == null)
2163 {
2164 String msg = "Evaluation of graph: INCHI is null!";
2165 settings.getLogger().log(Level.INFO, msg);
2166 inchikey = "UNDEFINED";
2167 }
2168 res[0] = inchikey;
2169 }
2170
2171 return true;
2172 }
2173
2174//------------------------------------------------------------------------------
2175
2183 protected static boolean containsMolecule(Population mols, String molcode)
2184 {
2185 if(mols.isEmpty())
2186 return false;
2187
2188 for (Candidate mol : mols)
2189 {
2190 if (mol.getUID().compareToIgnoreCase(molcode) == 0)
2191 {
2192 return true;
2193 }
2194 }
2195 return false;
2196 }
2197
2198//------------------------------------------------------------------------------
2199
2206 protected static double[] getFitnesses(Population mols)
2207 {
2208 int k = mols.size();
2209 double[] arr = new double[k];
2210
2211 for (int i=0; i<k; i++)
2212 {
2213 arr[i] = mols.get(i).getFitness();
2214 }
2215 return arr;
2216 }
2217
2218//------------------------------------------------------------------------------
2219
2227 protected static double getPopulationSD(Population molPopulation)
2228 {
2229 double[] fitvals = getFitnesses(molPopulation);
2230 return StatUtils.stddev(fitvals, true);
2231 }
2232
2233//------------------------------------------------------------------------------
2234
2247 public static double getGrowthProbabilityAtLevel(int level, int scheme,
2248 double lambda, double sigmaOne, double sigmaTwo)
2249 {
2250 return getProbability(level, scheme, lambda, sigmaOne, sigmaTwo);
2251 }
2252
2253//------------------------------------------------------------------------------
2254
2267 public static double getMolSizeProbability(DGraph graph,
2268 GAParameters settings)
2269 {
2270 if (!settings.useMolSizeBasedProb())
2271 return 1.0;
2272 int scheme = settings.getMolGrowthProbabilityScheme();
2273 double lambda =settings.getMolGrowthMultiplier();
2274 double sigmaOne = settings.getMolGrowthFactorSteepSigma();
2275 double sigmaTwo = settings.getMolGrowthFactorMiddleSigma();
2276 return getMolSizeProbability(graph, scheme, lambda, sigmaOne, sigmaTwo);
2277 }
2278
2279//------------------------------------------------------------------------------
2280
2293 public static double getMolSizeProbability(DGraph graph,
2294 int scheme, double lambda, double sigmaOne, double sigmaTwo)
2295 {
2296 return getProbability(graph.getHeavyAtomsCount(), scheme, lambda,
2297 sigmaOne, sigmaTwo);
2298 }
2299
2300//------------------------------------------------------------------------------
2301
2312 public static double getProbability(double value,
2313 int scheme, double lambda, double sigmaOne, double sigmaTwo)
2314 {
2315 double prob = 1.0;
2316 if (scheme == 0)
2317 {
2318 double f = Math.exp(-1.0 * value * lambda);
2319 prob = 1 - ((1-f)/(1+f));
2320 }
2321 else if (scheme == 1)
2322 {
2323 prob = 1.0 - Math.tanh(lambda * value);
2324 }
2325 else if (scheme == 2)
2326 {
2327 prob = 1.0-1.0/(1.0 + Math.exp(-sigmaOne * (value - sigmaTwo)));
2328 }
2329 else if (scheme == 3)
2330 {
2331 prob = 1.0;
2332 }
2333 return prob;
2334 }
2335
2336//------------------------------------------------------------------------------
2337
2344 public static double getGrowthByLevelProbability(int level,
2345 GAParameters settings)
2346 {
2347 if (!settings.useLevelBasedProb())
2348 return 1.0;
2349 int scheme = settings.getGrowthProbabilityScheme();
2350 double lambda =settings.getGrowthMultiplier();
2351 double sigmaOne = settings.getGrowthFactorSteepSigma();
2352 double sigmaTwo = settings.getGrowthFactorMiddleSigma();
2353 return getGrowthProbabilityAtLevel(level, scheme, lambda, sigmaOne,
2354 sigmaTwo);
2355 }
2356
2357//------------------------------------------------------------------------------
2358
2368 GAParameters settings)
2369 {
2370 int scheme = settings.getCrowdingProbabilityScheme();
2371 double lambda =settings.getCrowdingMultiplier();
2372 double sigmaOne = settings.getCrowdingFactorSteepSigma();
2373 double sigmaTwo = settings.getCrowdingFactorMiddleSigma();
2374 return getCrowdingProbability(ap, scheme, lambda, sigmaOne, sigmaTwo);
2375 }
2376
2377//------------------------------------------------------------------------------
2378
2392 public static double getCrowdingProbability(int crowdedness,
2393 GAParameters settings)
2394 {
2395 int scheme = settings.getCrowdingProbabilityScheme();
2396 double lambda =settings.getCrowdingMultiplier();
2397 double sigmaOne = settings.getCrowdingFactorSteepSigma();
2398 double sigmaTwo = settings.getCrowdingFactorMiddleSigma();
2399 return getCrowdingProbabilityForCrowdedness(crowdedness, scheme, lambda,
2400 sigmaOne, sigmaTwo);
2401 }
2402
2403//------------------------------------------------------------------------------
2404
2412 public static int getCrowdedness(AttachmentPoint ap)
2413 {
2414 return getCrowdedness(ap,false);
2415 }
2416
2417//------------------------------------------------------------------------------
2418
2428 public static int getCrowdedness(AttachmentPoint ap,
2429 boolean ignoreFreeRCVs)
2430 {
2431 if (ap.getOwner() instanceof EmptyVertex)
2432 {
2433 return 0;
2434 }
2435 int crowdness = 0;
2436 DGraph g = ap.getOwner().getGraphOwner();
2438 {
2439 if (oap.getAtomPositionNumber() == ap.getAtomPositionNumber()
2440 && !oap.isAvailableThroughout()
2441 && oap.getLinkedAP().getOwner()
2442 .getBuildingBlockType() != BBType.CAP)
2443 {
2444 if (ignoreFreeRCVs && oap.getLinkedAP().getOwner().isRCV())
2445 {
2446 if (g.getUsedRCVertices().contains(oap.getLinkedAP().getOwner()))
2447 crowdness = crowdness + 1;
2448 } else {
2449 crowdness = crowdness + 1;
2450 }
2451 }
2452 }
2453 return crowdness;
2454 }
2455
2456//------------------------------------------------------------------------------
2457
2470 public static double getCrowdingProbability(AttachmentPoint ap,
2471 int scheme,
2472 double lambda, double sigmaOne, double sigmaTwo)
2473 {
2474 //Applies only to molecular fragments
2475 if (ap.getOwner() instanceof Fragment == false)
2476 {
2477 return 1.0;
2478 }
2479 int crowdness = getCrowdedness(ap);
2480 return getCrowdingProbabilityForCrowdedness(crowdness, scheme, lambda,
2481 sigmaOne, sigmaTwo);
2482 }
2483
2484//------------------------------------------------------------------------------
2485
2495 public static double getCrowdingProbabilityForCrowdedness(int crowdedness,
2496 int scheme,
2497 double lambda, double sigmaOne, double sigmaTwo)
2498 {
2499 return getProbability(crowdedness, scheme, lambda, sigmaOne, sigmaTwo);
2500 }
2501
2502//------------------------------------------------------------------------------
2503
2512 protected static boolean foundForbiddenEnd(DGraph molGraph,
2513 FragmentSpaceParameters fsParams)
2514 {
2515 List<Vertex> vertices = molGraph.getVertexList();
2516 Set<APClass> classOfForbEnds = fsParams.getFragmentSpace()
2518 for (Vertex vtx : vertices)
2519 {
2520 List<AttachmentPoint> daps = vtx.getAttachmentPoints();
2521 for (AttachmentPoint dp : daps)
2522 {
2523 if (dp.isAvailable())
2524 {
2525 APClass apClass = dp.getAPClass();
2526 if (classOfForbEnds.contains(apClass))
2527 {
2528 String msg = "Forbidden free AP for Vertex: "
2529 + vtx.getVertexId()
2530 + " MolId: " + (vtx.getBuildingBlockId() + 1)
2531 + " Ftype: " + vtx.getBuildingBlockType()
2532 + "\n"+ molGraph+" \n "
2533 + " AP class: " + apClass;
2534 fsParams.getLogger().log(Level.WARNING, msg);
2535 return true;
2536 }
2537 }
2538 }
2539 }
2540 return false;
2541 }
2542
2543//------------------------------------------------------------------------------
2544
2545 protected static void readUID(String infile, HashSet<String> lstInchi)
2546 throws DENOPTIMException
2547 {
2548 ArrayList<String> lst = DenoptimIO.readList(infile);
2549 for (String str:lst)
2550 lstInchi.add(str);
2551 lst.clear();
2552 }
2553
2554//------------------------------------------------------------------------------
2555
2581 //NB: we return a List to retain ordering of the items, but the list must
2582 // not contain redundancies, i.e., lists of AP pairs that are made of the
2583 // same set of AP pairs.
2584 public static List<List<RelatedAPPair>> searchRingFusionSites(
2585 DGraph graph, GAParameters gaParams) throws DENOPTIMException
2586 {
2588 if (gaParams.containsParameters(ParametersType.RC_PARAMS))
2589 {
2590 rcParams = (RingClosureParameters)gaParams.getParameters(
2592 }
2594 if (gaParams.containsParameters(ParametersType.FS_PARAMS))
2595 {
2596 fsParams = (FragmentSpaceParameters)gaParams.getParameters(
2598 }
2599 FragmentSpace fragSpace = fsParams.getFragmentSpace();
2600 Randomizer rng = gaParams.getRandomizer();
2601 boolean projectOnSymmetricAPs = rng.nextBoolean(
2602 gaParams.getSymmetryProbability());
2603 // NB: imposeSymmetryOnAPsOfClass is evaluated inside the
2604 // method searchRingFusionSites
2605 Logger logger = gaParams.getLogger();
2606 return searchRingFusionSites(graph, fragSpace, rcParams,
2607 projectOnSymmetricAPs, logger, rng);
2608 }
2609
2610//------------------------------------------------------------------------------
2611
2637 //NB: we return a List to retain ordering of the items, but the list must
2638 // not contain redundancies, i.e., lists of AP pairs that are made of the
2639 // same set of AP pairs.
2640 public static List<List<RelatedAPPair>> searchRingFusionSites(
2641 DGraph graph, FragmentSpace fragSpace,
2642 RingClosureParameters rcParams, boolean projectOnSymmetricAPs,
2643 Logger logger, Randomizer rng) throws DENOPTIMException
2644 {
2645 // Prepare the empty collector of combinations
2646 List<List<RelatedAPPair>> result = new ArrayList<List<RelatedAPPair>>();
2647
2648 // Most of the work is done on a clone to prevent any modification of the
2649 // 3D molecular representation of the graph, which is here rebuilt in
2650 // a crude way because we only need the connectivity.
2651 DGraph tmpGraph = graph.clone();
2652
2653 // Keep track of which vertexes come from the original graph. We need
2654 // to distinguish them from the capping groups we add here.
2655 Set<Long> originalVertexIDs = new HashSet<Long>();
2656 tmpGraph.getVertexList().stream()
2657 .forEach(v -> originalVertexIDs.add(v.getVertexId()));
2658
2659 // We add capping groups to facilitate the search for substructures
2660 // otherwise we have to write SMARTS that match systems with potentially
2661 // unsaturated valences, and that is a mess.
2662 // Here we change both graph and molecular representation, but it all
2663 // happens on the tmp copy, so the original graph and mol representation
2664 // remain intact. Also, note that the order of atoms does not have a
2665 // role because we only use the position of the atom in the list of atoms
2666 // within the tmp system, and then we use the reference to the
2667 // AP to project the information back into the original system.
2668 tmpGraph.addCappingGroups(fragSpace);
2669
2670 // Get a molecular representation
2671 ThreeDimTreeBuilder t3d = new ThreeDimTreeBuilder(logger, rng);
2672 t3d.setAlignBBsIn3D(false); //3D not needed
2673 IAtomContainer mol = t3d.convertGraphTo3DAtomContainer(tmpGraph, true);
2674
2675 // Search for potential half-ring environments, i.e., sets of atoms
2676 // that belongs to a cyclic system and could hold a chord that would
2677 // define the fused ring.
2678 Map<String, String> smarts = new HashMap<String, String>();
2679 for (BridgeHeadFindingRule rule : rcParams.getBridgeHeadFindingRules())
2680 {
2681 smarts.put(rule.getName(), rule.getSMARTS());
2682 }
2683
2684 ManySMARTSQuery msq = new ManySMARTSQuery(mol, smarts);
2685 if (msq.hasProblems())
2686 {
2687 throw new DENOPTIMException(msq.getMessage());
2688 }
2689 Map<SymmetricSetWithMode,List<RelatedAPPair>> symmRelatedBridgeHeadAPs =
2690 new HashMap<SymmetricSetWithMode,List<RelatedAPPair>>();
2691 List<RelatedAPPair> symBridgeHeadAPs = new ArrayList<RelatedAPPair>();
2692 List<RelatedAPPair> asymBridgeHeadAPs = new ArrayList<RelatedAPPair>();
2693 for (BridgeHeadFindingRule rule : rcParams.getBridgeHeadFindingRules())
2694 {
2695 if (msq.getNumMatchesOfQuery(rule.getName()) == 0)
2696 {
2697 continue;
2698 }
2699
2700 // Get bridge-head atoms
2701 Mappings halfRingAtms = msq.getMatchesOfSMARTS(rule.getName());
2702 // We use a string to facilitate detection of pairs of ids
2703 // irrespectively on the order of ids, i.e., 1-2 vs. 2-1.
2704 Set<String> doneIdPairs = new HashSet<String>();
2705 for (int[] idSubstructure : halfRingAtms)
2706 {
2707 if (idSubstructure.length<2)
2708 {
2709 throw new Error("SMARTS for matching half-ring pattern '"
2710 + rule.getName()
2711 + "' has identified " + idSubstructure.length
2712 + " atoms "
2713 + "instead of at least 2. Modify rule to make it "
2714 + "find 2 or more atoms.");
2715 }
2716
2717 // Potential bridge-head atoms
2718 int[] ids = new int[] {
2719 idSubstructure[rule.getBridgeHeadPositions()[0]],
2720 idSubstructure[rule.getBridgeHeadPositions()[1]]};
2721
2722 IAtom bhA = mol.getAtom(ids[0]);
2723 IAtom bhB = mol.getAtom(ids[1]);
2724
2725 // Avoid duplicate pairs with inverted AP identity
2726 String idPairIdentifier = "";
2727 if (ids[0]<ids[1])
2728 idPairIdentifier = ids[0]+"_"+ids[1];
2729 else
2730 idPairIdentifier = ids[1]+"_"+ids[0];
2731 if (doneIdPairs.contains(idPairIdentifier))
2732 continue;
2733 doneIdPairs.add(idPairIdentifier);
2734
2735 // Bridge-head atoms must have attachment points
2736 if (bhA.getProperty(DENOPTIMConstants.ATMPROPAPS)==null
2737 || bhB.getProperty(DENOPTIMConstants.ATMPROPAPS)==null)
2738 continue;
2739 if (bhA.getProperty(DENOPTIMConstants.ATMPROPVERTEXID)==null
2740 || bhB.getProperty(DENOPTIMConstants.ATMPROPVERTEXID)==null)
2741 throw new IllegalStateException("Atoms in 3d molecular "
2742 + "models of graph objects must have the "
2743 + DENOPTIMConstants.ATMPROPVERTEXID + " property.");
2744
2745 long vrtxIdA = (Long)
2746 bhA.getProperty(DENOPTIMConstants.ATMPROPVERTEXID);
2747 long vrtxIdB = (Long)
2748 bhB.getProperty(DENOPTIMConstants.ATMPROPVERTEXID);
2749
2750 // Each AP on each side can be used
2751 @SuppressWarnings("unchecked")
2752 List<AttachmentPoint> apsOnA = (List<AttachmentPoint>)
2753 bhA.getProperty(DENOPTIMConstants.ATMPROPAPS);
2754 @SuppressWarnings("unchecked")
2755 List<AttachmentPoint> apsOnB = (List<AttachmentPoint>)
2756 bhB.getProperty(DENOPTIMConstants.ATMPROPAPS);
2757 for (int iAPA=0; iAPA<apsOnA.size(); iAPA++)
2758 {
2759 AttachmentPoint copyOfApA = apsOnA.get(iAPA);
2760
2761 // for extreme debug only
2762 /*
2763 System.out.println(rule.getName()+" "+idPairIdentifier+" "
2764 +MoleculeUtils.getAtomRef(bhA, mol)+"-"
2765 +MoleculeUtils.getAtomRef(bhB, mol)+" "
2766 +copyOfApA.getIndexInOwner()
2767 +" in "+copyOfApA.getOwner());
2768 */
2769
2770 if (!canBeUsedForRingFusion(copyOfApA, originalVertexIDs,
2771 fragSpace))
2772 continue;
2773 for (int iAPB=0; iAPB<apsOnB.size(); iAPB++)
2774 {
2775 AttachmentPoint copyOfApB = apsOnB.get(iAPB);
2776
2777 // for extreme debug only
2778 /*
2779 System.out.println(" "+idPairIdentifier+" "
2780 +MoleculeUtils.getAtomRef(bhA, mol)+"-"
2781 +MoleculeUtils.getAtomRef(bhB, mol)+" "
2782 +copyOfApA.getIndexInOwner()
2783 +" in "+copyOfApA.getOwner()
2784 + "--- "
2785 +copyOfApB.getIndexInOwner()
2786 +" in "+copyOfApB.getOwner());
2787 */
2788
2789 if (!canBeUsedForRingFusion(copyOfApB, originalVertexIDs,
2790 fragSpace))
2791 continue;
2792
2793 // Now take the references to the actual APs
2794 AttachmentPoint apA = tmpGraph.getVertexWithId(vrtxIdA)
2795 .getAPWithId(copyOfApA.getID());
2796 AttachmentPoint apB = tmpGraph.getVertexWithId(vrtxIdB)
2797 .getAPWithId(copyOfApB.getID());
2798 if (apA==null || apB==null)
2799 continue;
2800
2801 // Now we have identified a pair of APs suitable to ring fusion
2802 RelatedAPPair pair = new RelatedAPPair(apA, apB, rule,
2803 rule.getName());
2804
2805 //Record symmetric relations
2806 SymmetricAPs symInA = apA.getOwner().getSymmetricAPs(apA);
2807 SymmetricAPs symInB = apB.getOwner().getSymmetricAPs(apB);
2808 if (symInA.size()!=0 && symInB.size()!=0)
2809 {
2810 if (symInA==symInB)
2811 {
2812 storePairsSymmetricRelations(pair, symInA,
2813 symmRelatedBridgeHeadAPs);
2814 } else {
2815 storePairsSymmetricRelations(pair, symInA,
2816 symmRelatedBridgeHeadAPs);
2817 storePairsSymmetricRelations(pair, symInB,
2818 symmRelatedBridgeHeadAPs);
2819 }
2820 symBridgeHeadAPs.add(pair);
2821 } else {
2822 asymBridgeHeadAPs.add(pair);
2823 }
2824 }
2825 }
2826 }
2827 }
2828 if (asymBridgeHeadAPs.size()==0 && symBridgeHeadAPs.size()==0)
2829 {
2830 return result;
2831 }
2832
2833 // Collect potential set of pairs of APs that can be used to create
2834 // fused ring systems accounting for symmetric AP relations.
2835 List<List<RelatedAPPair>> candidateBridgeHeadAPPairs =
2836 new ArrayList<List<RelatedAPPair>>();
2837 if (symmRelatedBridgeHeadAPs.size()>0)
2838 {
2839 for (SymmetricSetWithMode key : symmRelatedBridgeHeadAPs.keySet())
2840 {
2841 List<RelatedAPPair> chosenSymSet =
2842 symmRelatedBridgeHeadAPs.get(key);
2843
2844 @SuppressWarnings("unchecked")
2845 SymmetricSet<AttachmentPoint> symmRelatedAPs =
2846 (SymmetricSet<AttachmentPoint>) key.getItems();
2847 boolean apcImposedSymm = fragSpace.imposeSymmetryOnAPsOfClass(
2848 symmRelatedAPs.get(0).getAPClass());
2849
2850 if (projectOnSymmetricAPs || apcImposedSymm)
2851 {
2852 // We try to get the biggest combination (k is the size)
2853 // but we do limit to avoid combinatorial explosion.
2854 for (int k=Math.min(chosenSymSet.size(), 6); k>0; k--)
2855 {
2856 // Generate combinations that use non-overlapping pairs of APs
2857 List<List<RelatedAPPair>> combs = combineRelatedAPPair(
2858 chosenSymSet, k, 50);
2859 //TODO: make limit of combinations tuneable?
2860
2861 if (combs.size()>0)
2862 {
2863 // We keep only combinations that are not already
2864 // among previously known ones
2865 for (List<RelatedAPPair> comb : combs)
2866 {
2867 boolean isNew = true;
2868 for (List<RelatedAPPair> knownComb :
2869 candidateBridgeHeadAPPairs)
2870 {
2871 if (knownComb.containsAll(comb)
2872 && comb.containsAll(knownComb))
2873 {
2874 isNew = false;
2875 break;
2876 }
2877 }
2878 if (isNew)
2879 {
2880 candidateBridgeHeadAPPairs.add(comb);
2881 for (RelatedAPPair pair : comb)
2882 symBridgeHeadAPs.remove(pair);
2883 }
2884 }
2885 break;
2886 }
2887 }
2888 }
2889 }
2890 // Add left over pairs, if any.
2891 for (RelatedAPPair pair : symBridgeHeadAPs)
2892 {
2893 List<RelatedAPPair> single = new ArrayList<RelatedAPPair>();
2894 single.add(pair);
2895 candidateBridgeHeadAPPairs.add(single);
2896 }
2897 }
2898 for (RelatedAPPair pair : asymBridgeHeadAPs)
2899 {
2900 List<RelatedAPPair> single = new ArrayList<RelatedAPPair>();
2901 single.add(pair);
2902 candidateBridgeHeadAPPairs.add(single);
2903 }
2904
2905 // Project ring fusions into the actual graph (considering symmetry)
2906 for (List<RelatedAPPair> combOnTmpGraph : candidateBridgeHeadAPPairs)
2907 {
2908 List<RelatedAPPair> combOnOriginalGraph =
2909 new ArrayList<RelatedAPPair>();
2910 for (RelatedAPPair pairOnTmpGraph : combOnTmpGraph)
2911 {
2912 Vertex headVertexOnGraph = graph.getVertexAtPosition(
2913 tmpGraph.indexOf(pairOnTmpGraph.apA.getOwner()));
2914 int apHeadID = pairOnTmpGraph.apA.getIndexInOwner();
2915 List<Vertex> symHeadVrts = graph.getSymVerticesForVertex(
2916 headVertexOnGraph);
2917 if (symHeadVrts.size()==0)
2918 symHeadVrts.add(headVertexOnGraph);
2919
2920 Vertex tailVertexOnGraph = graph.getVertexAtPosition(
2921 tmpGraph.indexOf(pairOnTmpGraph.apB.getOwner()));
2922 int apTailID = pairOnTmpGraph.apB.getIndexInOwner();
2923 List<Vertex> symTailVrts = graph.getSymVerticesForVertex(
2924 tailVertexOnGraph);
2925 if (symTailVrts.size()==0)
2926 symTailVrts.add(tailVertexOnGraph);
2927
2928 int numPairs = Math.min(symHeadVrts.size(), symTailVrts.size());
2929 for (int iPair=0; iPair<numPairs; iPair++)
2930 {
2931 RelatedAPPair pairOnOriginalGraph = new RelatedAPPair(
2932 symHeadVrts.get(iPair).getAP(apHeadID),
2933 symTailVrts.get(iPair).getAP(apTailID),
2934 pairOnTmpGraph.property,
2935 pairOnTmpGraph.propID);
2936 combOnOriginalGraph.add(pairOnOriginalGraph);
2937 }
2938 }
2939 result.add(combOnOriginalGraph);
2940 }
2941 return result;
2942 }
2943
2944//------------------------------------------------------------------------------
2945
2946 private static List<List<RelatedAPPair>> combineRelatedAPPair(
2947 List<RelatedAPPair> pool, int k, int limit)
2948 {
2949 List<RelatedAPPair> tmp = new ArrayList<RelatedAPPair>();
2950 List<List<RelatedAPPair>> allCombs = new ArrayList<List<RelatedAPPair>>();
2951 combineRelatedAPPairUtil(pool, 0, k, tmp, allCombs, limit);
2952 return allCombs;
2953 }
2954
2955//------------------------------------------------------------------------------
2956
2957 private static void combineRelatedAPPairUtil(List<RelatedAPPair> pool,
2958 int left, int k,
2959 List<RelatedAPPair> tmp,
2960 List<List<RelatedAPPair>> allCombs, int limit)
2961 {
2962 // PRevent combinatorial explosion: stop if the number of combinations
2963 // grown above the limit
2964 if (allCombs.size()>=limit)
2965 return;
2966
2967 // For last iteration: save answer
2968 if (k == 0)
2969 {
2970 if (!apPairsAreOverlapping(tmp))
2971 {
2972 List<RelatedAPPair> oneComb = new ArrayList<RelatedAPPair>(tmp);
2973 allCombs.add(oneComb);
2974 }
2975 return;
2976 }
2977 // In normal iteration, do recursion
2978 for (int i=left; i<pool.size(); ++i)
2979 {
2980 RelatedAPPair next = pool.get(i);
2981 if (shareAPs(next, tmp))
2982 {
2983 continue;
2984 }
2985 tmp.add(next);
2986 combineRelatedAPPairUtil(pool, i + 1, k-1, tmp, allCombs, limit);
2987 tmp.remove(tmp.size() - 1);
2988 }
2989 }
2990
2991//------------------------------------------------------------------------------
2992
2994 SymmetricAPs symAPs,
2995 Map<SymmetricSetWithMode,List<RelatedAPPair>> storage)
2996 {
2997 SymmetricSetWithMode key = new SymmetricSetWithMode(symAPs, pair.propID);
2998 if (storage.containsKey(key))
2999 {
3000 storage.get(key).add(pair);
3001 } else {
3002 List<RelatedAPPair> lst = new ArrayList<RelatedAPPair>();
3003 lst.add(pair);
3004 storage.put(key, lst);
3005 }
3006 }
3007
3008//------------------------------------------------------------------------------
3009
3018 public static Boolean apPairsAreOverlapping(Iterable<RelatedAPPair> pairs)
3019 {
3020 Set<AttachmentPoint> aps = new HashSet<AttachmentPoint>();
3021
3022 for (RelatedAPPair pair : pairs)
3023 {
3024 if (aps.contains(pair.apA) || aps.contains(pair.apB))
3025 {
3026 return true;
3027 }
3028 aps.add(pair.apA);
3029 aps.add(pair.apB);
3030 }
3031 return false;
3032 }
3033
3034//------------------------------------------------------------------------------
3035
3044 public static Boolean shareAPs(RelatedAPPair pairA,
3045 Iterable<RelatedAPPair> lstB)
3046 {
3047 Set<AttachmentPoint> aps = new HashSet<AttachmentPoint>();
3048 for (RelatedAPPair pairB : lstB)
3049 {
3050 aps.add(pairB.apA);
3051 aps.add(pairB.apB);
3052 }
3053 return aps.contains(pairA.apA) || aps.contains(pairA.apB);
3054 }
3055
3056//------------------------------------------------------------------------------
3057
3080 private static boolean canBeUsedForRingFusion(AttachmentPoint ap,
3081 Set<Long> originalVertexIDs, FragmentSpace fs)
3082 {
3083 if (ap.isAvailableThroughout()
3084 || !originalVertexIDs.contains(
3086 {
3087 if (fs.getRCCompatibilityMatrix().containsKey(ap.getAPClass()))
3088 return true;
3089 }
3090 return false;
3091 }
3092
3093//------------------------------------------------------------------------------
3094
3107 public static List<Vertex> getUsableAromaticBridges(
3108 String elInIncomingFrag, int[] allowedLengths,
3109 FragmentSpace fragSpace)
3110 {
3111 List<Vertex> usableBridgesOriginals =
3112 fragSpace.getVerticesWithAPClassStartingWith(elInIncomingFrag);
3113 List<Vertex> usableBridges = new ArrayList<Vertex>();
3114 final String rootAPC = elInIncomingFrag;
3115 for (Vertex bridge : usableBridgesOriginals)
3116 {
3117 IAtomContainer iacFrag = bridge.getIAtomContainer();
3118 List<Integer> atomIDs = new ArrayList<Integer>();
3119 bridge.getAttachmentPoints()
3120 .stream()
3121 .filter(ap -> ap.getAPClass().getRule().startsWith(
3122 rootAPC))
3123 .forEach(ap -> atomIDs.add(ap.getAtomPositionNumber()));
3124 ShortestPaths sp = new ShortestPaths(iacFrag, iacFrag.getAtom
3125 (atomIDs.get(0)));
3126 List<IAtom> path = new ArrayList<IAtom>(Arrays.asList(
3127 sp.atomsTo(atomIDs.get(1))));
3128 if (IntStream.of(allowedLengths).anyMatch(x -> x == path.size()))
3129 {
3130 Vertex clone = bridge.clone();
3132 path.size());
3133 usableBridges.add(clone);
3134 }
3135 }
3136 return usableBridges;
3137 }
3138
3139//------------------------------------------------------------------------------
3140
3151 public static List<Vertex> getUsableAliphaticBridges(APClass apcA,
3152 APClass apcB, int[] allowedLengths, FragmentSpace fragSpace)
3153 {
3154 List<Vertex> usableBridges = new ArrayList<Vertex>();
3155
3156 List<APClass> compatApClassesA = fragSpace.getCompatibleAPClasses(apcA);
3157 List<APClass> compatApClassesB = fragSpace.getCompatibleAPClasses(apcB);
3158 for (APClass compatA : compatApClassesA)
3159 {
3160 for (APClass compatB : compatApClassesB)
3161 {
3162 boolean sameAPC = compatA.equals(compatB);
3163 Map<APClass,Integer> apFingerprint =
3164 new HashMap<APClass,Integer>();
3165 if (sameAPC)
3166 {
3167 apFingerprint.put(compatA,2);
3168 } else {
3169 apFingerprint.put(compatA,1);
3170 apFingerprint.put(compatB,1);
3171 }
3172 for (Vertex bridge : fragSpace.getVerticesWithAPFingerprint(
3173 apFingerprint))
3174 {
3175 IAtomContainer iacFrag = bridge.getIAtomContainer();
3176
3177 // Identify APs that can be used for each side
3178 List<AttachmentPoint> apsForA = new ArrayList<AttachmentPoint>();
3179 List<AttachmentPoint> apsForB = new ArrayList<AttachmentPoint>();
3180 for (AttachmentPoint apOnBridge : bridge.getAttachmentPoints())
3181 {
3182 if (compatA.equals(apOnBridge.getAPClass()))
3183 apsForA.add(apOnBridge);
3184 if (compatB.equals(apOnBridge.getAPClass()))
3185 apsForB.add(apOnBridge);
3186 }
3187
3188 // Find combinations of usable APs
3189 for (AttachmentPoint apForA : apsForA)
3190 {
3191 ShortestPaths sp = new ShortestPaths(iacFrag,
3192 iacFrag.getAtom(apForA.getAtomPositionNumber()));
3193 for (AttachmentPoint apForB : apsForB)
3194 {
3195 if (apForA.equals(apForB))
3196 continue;
3197 // Retains only combinations of allowed length
3198 List<IAtom> path = new ArrayList<IAtom>(
3199 Arrays.asList(sp.atomsTo(
3200 apForB.getAtomPositionNumber())));
3201 if (IntStream.of(allowedLengths).anyMatch(
3202 x -> x == path.size()))
3203 {
3204 Vertex clone = bridge.clone();
3205 clone.setProperty(
3207 path.size());
3208 clone.setProperty(
3210 apForA.getIndexInOwner());
3211 clone.setProperty(
3213 apForB.getIndexInOwner());
3214 usableBridges.add(clone);
3215 }
3216 }
3217 }
3218 }
3219 }
3220 }
3221 return usableBridges;
3222 }
3223
3224//------------------------------------------------------------------------------
3225
3226}
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 List< Vertex > fragmentation(IAtomContainer mol, FragmenterParameters settings)
Performs fragmentation according to the given settings.
static Vertex getRCVForAP(AttachmentPoint ap, APClass rcvApClass)
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:3044
static void outputFinalResults(Population popln, GAParameters settings)
Saves the final results to disk.
Definition: EAUtils.java:1747
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:2344
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:2392
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:1358
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:1553
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:2011
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:3080
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:1805
static void writeUID(String outfile, HashSet< String > lstInchi, boolean append)
Definition: EAUtils.java:1862
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:2247
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:2312
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:3151
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:1631
static String getPathNameToFinalPopulationFolder(GAParameters settings)
Definition: EAUtils.java:1717
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:2367
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:2512
static List< List< RelatedAPPair > > searchRingFusionSites(DGraph graph, GAParameters gaParams)
Definition: EAUtils.java:2584
static void setVertexCounterValue(Population population)
Set the Vertex counter value according to the largest value found in the given population.
Definition: EAUtils.java:1895
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:1916
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 DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol, FragmenterParameters frgParams)
Converts a molecule into a DGraph by fragmentation and re-assembling of the fragments.
Definition: EAUtils.java:1165
static DGraph makeGraphFromFragmentationOfMol(IAtomContainer mol, FragmenterParameters frgParams, FragmentSpace fragSpace, Monitor monitor)
Converts a molecule into a DGraph by fragmentation and re-assembling of the fragments.
Definition: EAUtils.java:1202
static double[] getFitnesses(Population mols)
Get the fitness values for the list of molecules.
Definition: EAUtils.java:2206
static String getSummaryStatistics(Population popln, GAParameters settings)
Definition: EAUtils.java:1496
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:2293
static DecimalFormat initialiseFormatter()
Definition: EAUtils.java:115
static int getCrowdedness(AttachmentPoint ap)
Calculate the current crowdedness of the given attachment point.
Definition: EAUtils.java:2412
static int getCrowdedness(AttachmentPoint ap, boolean ignoreFreeRCVs)
Calculate the current crowdedness of the given attachment point.
Definition: EAUtils.java:2428
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:2946
static void combineRelatedAPPairUtil(List< RelatedAPPair > pool, int left, int k, List< RelatedAPPair > tmp, List< List< RelatedAPPair > > allCombs, int limit)
Definition: EAUtils.java:2957
static void outputPopulationDetails(Population population, String filename, GAParameters settings, boolean printpathNames)
Write out summary for the current GA population.
Definition: EAUtils.java:1437
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:3107
static Vertex selectNonScaffoldNonCapVertex(DGraph g, Randomizer randomizer)
Chose randomly a vertex that is neither scaffold or capping group.
Definition: EAUtils.java:1603
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:2495
static String getPathNameToGenerationFolder(int genID, GAParameters settings)
Definition: EAUtils.java:1681
static double getPopulationSD(Population molPopulation)
Check if fitness values have significant standard deviation.
Definition: EAUtils.java:2227
static String getPathNameToFinalPopulationDetailsFile(GAParameters settings)
Definition: EAUtils.java:1726
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:2470
static boolean containsMolecule(Population mols, String molcode)
Check if the population contains the specified InChi code.
Definition: EAUtils.java:2183
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:2640
static void storePairsSymmetricRelations(RelatedAPPair pair, SymmetricAPs symAPs, Map< SymmetricSetWithMode, List< RelatedAPPair > > storage)
Definition: EAUtils.java:2993
static void readUID(String infile, HashSet< String > lstInchi)
Definition: EAUtils.java:2545
static final String FSEP
Definition: EAUtils.java:133
static String getPathNameToGenerationDetailsFile(int genID, GAParameters settings)
Definition: EAUtils.java:1697
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:2267
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:3018
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:104
void setCandidateClosableChains(ArrayList< ClosableChain > closableChains)
Definition: DGraph.java:935
void addVertex(Vertex vertex)
Appends a vertex to this graph without creating any edge.
Definition: DGraph.java:1391
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:5316
void getChildrenTree(Vertex vertex, List< Vertex > children)
Gets all the children of the current vertex recursively.
Definition: DGraph.java:3421
String getLocalMsg()
Definition: DGraph.java:289
void setGraphId(int id)
Definition: DGraph.java:266
ArrayList< Vertex > getFreeRCVertices()
Search for unused ring closing vertices: vertices that contain only a RingClosingAttractor and are no...
Definition: DGraph.java:1258
Object[] checkConsistency(RunTimeParameters settings)
Peeks into this graph to derive a preliminary chemical representation with SMILES and InChIKey.
Definition: DGraph.java:6053
List< Vertex > getVertexList()
Returns the list of vertexes without entering Templates.
Definition: DGraph.java:973
DGraph clone()
Returns almost "deep-copy" of this graph.
Definition: DGraph.java:3836
void renumberGraphVertices()
Reassign vertex IDs to all vertices of this graph.
Definition: DGraph.java:5983
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:3179
DGraph getOutermostGraphOwner()
Definition: DGraph.java:7613
void addCappingGroups(FragmentSpace fragSpace)
Add a capping groups on free unused attachment points.
Definition: DGraph.java:4819
void cleanup()
Wipes the data in this graph.
Definition: DGraph.java:4018
Candidate getCandidateOwner()
Returns the reference of the candidate item that is defined by this graph.
Definition: DGraph.java:259
ArrayList< Vertex > getUsedRCVertices()
Search for used ring closing vertices: vertices that contain only a RingClosingAttractor and are part...
Definition: DGraph.java:1281
int getHeavyAtomsCount()
Calculate the number of atoms from the graph representation.
Definition: DGraph.java:4603
List< Vertex > getMutableSites()
A list of mutation sites from within this graph.
Definition: DGraph.java:7262
void setLocalMsg(String msg)
Definition: DGraph.java:281
boolean detectSymVertexSets()
Detects and groups symmetric sets of Vertexes in the graph based on unique identification and path en...
Definition: DGraph.java:370
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.
void setEmbeddedRingsContract(ContractLevel embeddedRingsContract)
void setCuttingRules(List< CuttingRule > cuttingRules)
Assigns the cutting rules loaded from the input.
void setLinearAngleLimit(double linearAngleLimit)
Sets the upper limit for an angle before it is treated as "flat" angle, i.e., close enough to 180 DEG...
void setEmbedRingsInTemplate(boolean embedRingsInTemplate)
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.
String label
Label defining additional details, such as which label to search for in case of elemental symbol-base...
A chosen method for generation of new Candidates.
Definition: EAUtils.java:128
Possible chemical bond types an edge can represent.
Definition: Edge.java:305
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.