$darkmode
DENOPTIM
EAUtilsTest.java
Go to the documentation of this file.
1/*
2 * DENOPTIM
3 * Copyright (C) 2022 Marco Foscato <marco.foscato@uib.no>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package denoptim.ga;
20
21import static org.junit.jupiter.api.Assertions.assertEquals;
22import static org.junit.jupiter.api.Assertions.assertFalse;
23import static org.junit.jupiter.api.Assertions.assertNotNull;
24import static org.junit.jupiter.api.Assertions.assertTrue;
25
26import java.io.File;
27import java.util.ArrayList;
28import java.util.Arrays;
29import java.util.HashMap;
30import java.util.HashSet;
31import java.util.Iterator;
32import java.util.List;
33import java.util.Map;
34import java.util.Set;
35import java.util.logging.Logger;
36import java.util.stream.Collectors;
37
38import javax.vecmath.Point3d;
39
40import org.junit.jupiter.api.Test;
41import org.junit.jupiter.api.io.TempDir;
42import org.openscience.cdk.Atom;
43import org.openscience.cdk.interfaces.IAtom;
44import org.openscience.cdk.interfaces.IAtomContainer;
45import org.openscience.cdk.interfaces.IBond;
46import org.openscience.cdk.interfaces.IChemObjectBuilder;
47import org.openscience.cdk.layout.StructureDiagramGenerator;
48import org.openscience.cdk.silent.Bond;
49import org.openscience.cdk.silent.SilentChemObjectBuilder;
50import org.openscience.cdk.smiles.SmilesParser;
51
52import denoptim.constants.DENOPTIMConstants;
53import denoptim.exception.DENOPTIMException;
54import denoptim.fragmenter.ScaffoldingPolicy;
55import denoptim.fragspace.FragmentSpace;
56import denoptim.fragspace.FragmentSpaceParameters;
57import denoptim.ga.EAUtils.CandidateSource;
58import denoptim.graph.APClass;
59import denoptim.graph.AttachmentPoint;
60import denoptim.graph.Candidate;
61import denoptim.graph.DGraph;
62import denoptim.graph.DGraphTest;
63import denoptim.graph.Edge.BondType;
64import denoptim.graph.EmptyVertex;
65import denoptim.graph.Fragment;
66import denoptim.graph.GraphPattern;
67import denoptim.graph.RelatedAPPair;
68import denoptim.graph.SymmetricVertexes;
69import denoptim.graph.Template;
70import denoptim.graph.Template.ContractLevel;
71import denoptim.graph.Vertex;
72import denoptim.graph.Vertex.BBType;
73import denoptim.graph.rings.RingClosureParameters;
74import denoptim.io.DenoptimIO;
75import denoptim.logging.Monitor;
76import denoptim.programs.denovo.GAParameters;
77import denoptim.programs.fragmenter.CuttingRule;
78import denoptim.utils.MoleculeUtils;
79import denoptim.utils.Randomizer;
80
87public class EAUtilsTest
88{
89
90 private static APClass APCA, APCB, APCC;
91 private static String a="A", b="B", c="C";
92
93 private static final String SEP = System.getProperty("file.separator");
94 private static final String NL = System.getProperty("line.separator");
95
99 private IChemObjectBuilder builder = SilentChemObjectBuilder.getInstance();
100
101 @TempDir
102 static File tempDir;
103
104//------------------------------------------------------------------------------
105
107 {
111
112 HashMap<APClass,ArrayList<APClass>> cpMap =
113 new HashMap<APClass,ArrayList<APClass>>();
114 ArrayList<APClass> lstA = new ArrayList<APClass>();
115 lstA.add(APCA);
116 cpMap.put(APCA, lstA);
117 ArrayList<APClass> lstB = new ArrayList<APClass>();
118 lstB.add(APCB);
119 lstB.add(APCC);
120 cpMap.put(APCB, lstB);
121 ArrayList<APClass> lstC = new ArrayList<APClass>();
122 lstC.add(APCB);
123 lstC.add(APCC);
124 cpMap.put(APCC, lstC);
125
126 /* Compatibility matrix
127 *
128 * | A | B | C |
129 * -------------------------
130 * A | T | | |
131 * -------------------------
132 * B | | T | T |
133 * -------------------------
134 * C | | T | T |
135 * -------------------------
136 */
137
138 HashMap<APClass,APClass> capMap = new HashMap<APClass,APClass>();
139 HashSet<APClass> forbEnds = new HashSet<APClass>();
140
142 FragmentSpace fs = new FragmentSpace(fsp,
143 new ArrayList<Vertex>(),
144 new ArrayList<Vertex>(),
145 new ArrayList<Vertex>(),
146 cpMap, capMap, forbEnds, cpMap);
148
149 EmptyVertex v1 = new EmptyVertex();
151 v1.addAP(APCB);
152 v1.addAP(APCB);
154
155 EmptyVertex v2 = new EmptyVertex();
157 v2.addAP(APCC);
158 v2.addAP(APCC);
160
161 EmptyVertex rcv = new EmptyVertex();
163 rcv.addAP(APCC);
164 rcv.setAsRCV(true);
166
167 DGraph graphForTemplate = new DGraph();
169 BBType.FRAGMENT, fs);
170 graphForTemplate.addVertex(vg1);
171 for (int i=1; i<6; i++)
172 {
174 BBType.FRAGMENT, fs);
175 Vertex vgi_1 = graphForTemplate.getVertexAtPosition(i-1);
176 graphForTemplate.appendVertexOnAP(vgi_1.getAP(1), vgi.getAP(0));
177 }
179 BBType.FRAGMENT, fs);
180 graphForTemplate.appendVertexOnAP(
181 graphForTemplate.getVertexAtPosition(5).getAP(1),rcv1.getAP(0));
183 BBType.FRAGMENT, fs);
184 graphForTemplate.appendVertexOnAP(
185 graphForTemplate.getVertexAtPosition(0).getAP(0),rcv2.getAP(0));
186 graphForTemplate.addRing(rcv1, rcv2);
187
188 Template template = new Template(BBType.SCAFFOLD);
189 template.setInnerGraph(graphForTemplate);
190 template.setContractLevel(ContractLevel.FIXED_STRUCT);
192 fs.getScaffoldLibrary());
193
194 return fsp;
195 }
196
197//------------------------------------------------------------------------------
198
199 @Test
200 public void testBuildGraphFromTemplateScaffold() throws Exception
201 {
203 GAParameters gaParams = new GAParameters();
204 gaParams.setParameters(fsp);
205 DGraph g = EAUtils.buildGraph(gaParams);
206
207 if (g == null)
208 assertTrue(false,"faild construction of graph");
209
211
212 //NB: we want to not allow access to the inner graph from outside the
213 // template, but this means we cannot easily explore the inner graph.
214 // Looking at the mutation sites is a dirty trick to get a look inside
215 // this template, that has contract level "free" (meaning that the
216 // content of the template can change).
217
218 boolean foundChange = false;
219 for (Vertex v : t.getMutationSites())
220 {
221 if (v.getBuildingBlockId() != 0)
222 foundChange = true;
223 }
224 assertTrue(foundChange,"The initial inner graph has changed.");
225 }
226
227//------------------------------------------------------------------------------
228
229 @Test
230 public void testAvoidRedundantXOver() throws Exception
231 {
232 DGraph g1 = new DGraph();
233 EmptyVertex s = new EmptyVertex();
234 s.addAP();
235 s.addAP();
237
238 EmptyVertex v = new EmptyVertex();
239 v.addAP();
241
242 g1.addVertex(s);
243 g1.appendVertexOnAP(s.getAP(0), v.getAP(0));
244
245 Candidate c1 = new Candidate(g1);
246
247 DGraph g2 = g1.clone();
248 Candidate c2 = new Candidate(g2);
249
251 GAParameters gaParams = new GAParameters();
252 gaParams.setParameters(fsp);
253
254 ArrayList<Candidate> eligibleParents = new ArrayList<Candidate>();
255 eligibleParents.add(c1);
256 eligibleParents.add(c2);
257 Population population = new Population(gaParams);
258 population.add(c1);
259 population.add(c2);
260 Monitor mnt = new Monitor();
261
262 Candidate offspring = EAUtils.buildCandidateByXOver(eligibleParents,
263 population, mnt, gaParams);
264
265 assertTrue(offspring==null, "Redundat xover is not done");
266 }
267
268//------------------------------------------------------------------------------
269
270 @Test
271 public void testBuildByXOver_SubGraph() throws Exception
272 {
274 Population population = new Population(gaparams);
275
276 /*
277 * -(A)v0(A)-(A)v1(A)-(A)v2(A)-(A)v3(B)-(B)v4(B)-(B)v5(B)-
278 */
280 Candidate cA = new Candidate("CA",gA);
281 cA.setFitness(1.23);
282 population.add(cA);
283
284 /*
285 * v0(B)-(B)v1(A)-(A)v2(B)-(B)v3(A)-(A)v4(B)-(B)v5
286 */
288 Candidate cE = new Candidate("CE",gE);
289 cE.setFitness(2.34);
290 population.add(cE);
291
292 ArrayList<Candidate> eligibleParents = new ArrayList<Candidate>();
293 eligibleParents.add(cA);
294 eligibleParents.add(cE);
295
296 Monitor mnt = new Monitor();
297
298 Candidate offspring0 = EAUtils.buildCandidateByXOver(eligibleParents,
299 population, mnt, new int[]{0,1}, 3, 0, gaparams);
300
301 Candidate offspring1 = EAUtils.buildCandidateByXOver(eligibleParents,
302 population, mnt, new int[]{0,1}, 3, 1, gaparams);
303
304 DGraph g0 = offspring0.getGraph();
305 assertEquals(4,g0.getVertexCount());
306 assertEquals(3,g0.getEdgeCount());
307 int maxLength = -1;
308 for (Vertex v : g0.getVertexList())
309 {
310 ArrayList<Vertex> childTree = new ArrayList<Vertex>();
311 g0.getChildrenTree(v, childTree);
312 if (childTree.size()>maxLength)
313 {
314 maxLength = childTree.size();
315 }
316 }
317 assertEquals(3,maxLength);
318
319 DGraph g1 = offspring1.getGraph();
320 assertEquals(8,g1.getVertexCount());
321 assertEquals(7,g1.getEdgeCount());
322 maxLength = -1;
323 for (Vertex v : g1.getVertexList())
324 {
325 ArrayList<Vertex> childTree = new ArrayList<Vertex>();
326 g1.getChildrenTree(v, childTree);
327 if (childTree.size()>maxLength)
328 {
329 maxLength = childTree.size();
330 }
331 }
332 assertEquals(7,maxLength);
333 }
334
335//------------------------------------------------------------------------------
336
347 @Test
348 public void testBuildByXOver_Embedded_Free() throws Exception
349 {
351 gaparams.maxXoverEndPointsCombinations = 100;
352 gaparams.maxXoverEndPointsPermutations = 100;
353 gaparams.maxAPMappingCombinations = 100;
354 gaparams.maxCompatibleVrtxPairs = 100;
355 Population population = new Population(gaparams);
356
358 DGraph gA = pair[0];
359 DGraph gB = pair[1];
360 ((Template)gA.getVertexAtPosition(1)).setContractLevel(
362 ((Template)gB.getVertexAtPosition(1)).setContractLevel(
364
365 Candidate cA = new Candidate("CA",gA);
366 population.add(cA);
367
368 Candidate cB = new Candidate("CB",gB);
369 population.add(cB);
370
371 ArrayList<Candidate> eligibleParents = new ArrayList<Candidate>();
372 eligibleParents.add(cA);
373 eligibleParents.add(cB);
374
375 Monitor mnt = new Monitor();
376
377 Candidate offspring0 = EAUtils.buildCandidateByXOver(eligibleParents,
378 population, mnt, new int[]{0,1}, 8, 0, gaparams);
379
380 Candidate offspring1 = EAUtils.buildCandidateByXOver(eligibleParents,
381 population, mnt, new int[]{0,1}, 8, 1, gaparams);
382
383 DGraph g0xo = offspring0.getGraph();
384 DGraph g1xo = offspring1.getGraph();
385
387 DGraph expected0 = expectedPair[0];
388 DGraph expected1 = expectedPair[1];
389 ((Template)expected0.getVertexAtPosition(1)).setContractLevel(
391 ((Template)expected1.getVertexAtPosition(1)).setContractLevel(
393
394 assertTrue(expected0.sameAs(g0xo, new StringBuilder()));
395 assertTrue(expected1.sameAs(g1xo, new StringBuilder()));
396 }
397
398//------------------------------------------------------------------------------
399
410 @Test
411 public void testBuildByXOver_Embedded_FreeBackwards() throws Exception
412 {
414 Population population = new Population(gaparams);
415
417 DGraph gA = pair[0];
418 DGraph gB = pair[1];
419 ((Template)gA.getVertexAtPosition(1)).setContractLevel(
421 ((Template)gB.getVertexAtPosition(1)).setContractLevel(
423
424 Candidate cA = new Candidate("CA",gA);
425 population.add(cA);
426
427 Candidate cB = new Candidate("CB",gB);
428 population.add(cB);
429
430 ArrayList<Candidate> eligibleParents = new ArrayList<Candidate>();
431 eligibleParents.add(cA);
432 eligibleParents.add(cB);
433
434 Monitor mnt = new Monitor();
435
436 Candidate offspring0 = EAUtils.buildCandidateByXOver(eligibleParents,
437 population, mnt, new int[]{0,1}, 17, 0, gaparams);
438
439 Candidate offspring1 = EAUtils.buildCandidateByXOver(eligibleParents,
440 population, mnt, new int[]{0,1}, 17, 1, gaparams);
441
442 DGraph g0xo = offspring0.getGraph();
443 DGraph g1xo = offspring1.getGraph();
444
446 DGraph expected0 = expectedPair[0];
447 DGraph expected1 = expectedPair[1];
448 ((Template)expected0.getVertexAtPosition(1)).setContractLevel(
450 ((Template)expected1.getVertexAtPosition(1)).setContractLevel(
452
453 assertTrue(expected0.sameAs(g0xo, new StringBuilder()));
454 assertTrue(expected1.sameAs(g1xo, new StringBuilder()));
455 }
456
457//------------------------------------------------------------------------------
458
459 @Test
460 public void testBuildByXOver_Embedded_FixedStructure() throws Exception
461 {
463 gaparams.maxXoverEndPointsCombinations = 100;
464 gaparams.maxXoverEndPointsPermutations = 100;
465 gaparams.maxAPMappingCombinations = 100;
466 gaparams.maxCompatibleVrtxPairs = 100;
467 Population population = new Population(gaparams);
468
470 DGraph gA = pair[0];
471 DGraph gB = pair[1];
472 Template embeddedTmplA = (Template) gA.getVertexAtPosition(1);
474 DGraph embeddedGraphA = embeddedTmplA.getInnerGraph();
475 Template embeddedTmplB = (Template) gB.getVertexAtPosition(1);
477 DGraph embeddedGraphB = embeddedTmplB.getInnerGraph();
478
479 // Make vertexes unique so, even though they are empty, they will be
480 // seen as non equal and crossover will be seen as non-redundant.
481 String propName = "uniquefier";
482 int i=0;
483 for (Vertex v : embeddedGraphA.getVertexList())
484 {
485 v.setUniquefyingProperty(propName);
486 v.setProperty(propName, i);
487 i++;
488 }
489
490 Candidate cA = new Candidate("CA",gA);
491 population.add(cA);
492 Candidate cB = new Candidate("CB",gB);
493 population.add(cB);
494 ArrayList<Candidate> eligibleParents = new ArrayList<Candidate>();
495 eligibleParents.add(cA);
496 eligibleParents.add(cB);
497
498 Monitor mnt = new Monitor();
499 boolean embeddedGraphHasBeenAlteredA = false;
500 boolean embeddedGraphHasBeenAlteredB = false;
501 for (int ixo=0; ixo<11; ixo++)
502 {
503 Candidate offspring0 = null;
504 Candidate offspring1 = null;
505 try
506 {
507 offspring0 = EAUtils.buildCandidateByXOver(eligibleParents,
508 population, mnt, new int[]{0,1}, ixo, 0, gaparams);
509 offspring1 = EAUtils.buildCandidateByXOver(eligibleParents,
510 population, mnt, new int[]{0,1}, ixo, 1, gaparams);
511 } catch (IndexOutOfBoundsException e)
512 {
513 if (e.getMessage().contains("Index 10 out of bounds"))
514 {
515 // All good! We intentionally triggered this exception to
516 // verify that the list of xover points has the right size.
517 break;
518 }
519 throw e;
520 }
521
522 DGraph g0xo = offspring0.getGraph();
523 DGraph g1xo = offspring1.getGraph();
524 Template t0 = null;
525 Template t1 = null;
526 for (Vertex v : g0xo.getVertexList())
527 {
528 if (v instanceof Template)
529 {
530 t0 = (Template) v;
531 break;
532 }
533 }
534 for (Vertex v : g1xo.getVertexList())
535 {
536 if (v instanceof Template)
537 {
538 t1 = (Template) v;
539 break;
540 }
541 }
542 assertNotNull(t0);
543 assertNotNull(t1);
544
545 DGraph embeddedGraph0 = t0.getInnerGraph();
546 DGraph embeddedGraph1 = t1.getInnerGraph();
547
548 // Ensure there has been a change
549 if (!embeddedGraphA.isIsomorphicTo(embeddedGraph0)
550 && !embeddedGraphA.isIsomorphicTo(embeddedGraph1))
551 {
552 embeddedGraphHasBeenAlteredA = true;
553 }
554 if (!embeddedGraphB.isIsomorphicTo(embeddedGraph0)
555 && !embeddedGraphB.isIsomorphicTo(embeddedGraph1))
556 {
557 embeddedGraphHasBeenAlteredB = true;
558 }
559
560 // Ensure consistency with "fixed-structure" contract
561 assertTrue(embeddedGraphA.isIsostructuralTo(embeddedGraph0)
562 || embeddedGraphB.isIsostructuralTo(embeddedGraph0));
563 assertTrue(embeddedGraphA.isIsostructuralTo(embeddedGraph1)
564 || embeddedGraphB.isIsostructuralTo(embeddedGraph1));
565 }
566 assertTrue(embeddedGraphHasBeenAlteredA);
567 assertTrue(embeddedGraphHasBeenAlteredB);
568 }
569
570//------------------------------------------------------------------------------
571
572 @Test
573 public void testCandidateGenerationMethod() throws Exception
574 {
575 int ix = 0, im=0, ic=0, tot=1000;
576 double wx = 2, wm = 0.6, wc=0.05;
577 double wtot = wx + wm + wc;
578 Randomizer rng = new Randomizer();
579 for (int i=0; i<tot; i++)
580 {
582 wx, wm, wc, rng);
583 switch (mode)
584 {
585 case CROSSOVER:
586 ix++;
587 break;
588 case MUTATION:
589 im++;
590 break;
591 case CONSTRUCTION:
592 ic++;
593 break;
594 default:
595 assertTrue(false,"Unexpected generation mode "+mode);
596 break;
597 }
598 }
599 double x = ((double)ix) / tot;
600 double m = ((double)im) / tot;
601 double c = ((double)ic) / tot;
602
603 double thld = 0.05;
604
605 assertTrue(Math.abs(x-(wx/wtot)) < thld, "#Xover cases are off!");
606 assertTrue(Math.abs(m-(wm/wtot)) < thld, "#Mutation cases are off!");
607 assertTrue(Math.abs(c-(wc/wtot)) < thld, "#Built cases are off!");
608 }
609
610//------------------------------------------------------------------------------
611
612 @Test
613 public void testCandidateGenerationMethodReproducibility() throws Exception
614 {
615 int tot = 100000;
616 long seed = 1234567;
617 long otherSeed = 987654321;
618 double wx = 2, wm = 0.6, wc=0.05;
619
620 Randomizer rng = new Randomizer(seed);
621 List<CandidateSource> resultsA = new ArrayList<CandidateSource>();
622 for (int i=0; i<tot; i++)
623 {
624 resultsA.add(EAUtils.pickNewCandidateGenerationMode(wx,wm,wc,rng));
625 }
626
627 Randomizer rng2 = new Randomizer(otherSeed);
628 List<CandidateSource> resultsB = new ArrayList<CandidateSource>();
629 for (int i=0; i<tot; i++)
630 {
631 resultsB.add(EAUtils.pickNewCandidateGenerationMode(wx,wm,wc,rng2));
632 }
633
634 rng = new Randomizer(seed);
635 List<CandidateSource> resultsC = new ArrayList<CandidateSource>();
636 for (int i=0; i<tot; i++)
637 {
638 resultsC.add(EAUtils.pickNewCandidateGenerationMode(wx,wm,wc,rng));
639 }
640
641 boolean different = false;
642 for (int i=0; i<tot; i++)
643 {
644 if (resultsA.get(i) != resultsB.get(i))
645 {
646 different = true;
647 break;
648 }
649 }
650 assertTrue(different);
651
652 for (int i=0; i<tot; i++)
653 {
654 assertEquals(resultsA.get(i),resultsC.get(i),
655 "Inconsistent sequence of random decisions");
656 }
657 }
658
659//------------------------------------------------------------------------------
660
661 @Test
662 public void testCrowdingProbability() throws Exception
663 {
665 double t = 0.001;
666 double p = 0.0;
668 {
669 p = EAUtils.getCrowdingProbability(ap,3,1.0,1.0,1.0);
670 assertTrue(Math.abs(1.0 - p)<t,
671 "Scheme 3 should return always 1.0 but was "+p);
672 }
674 p = EAUtils.getCrowdingProbability(ap3,0,1.0,10,1.0);
675 assertTrue(Math.abs(1.0 - p)<t, "Scheme 0 on ap3: 1.0 != "+p);
676 p = EAUtils.getCrowdingProbability(ap3,1,1.0,10,1.0);
677 assertTrue(Math.abs(1.0 - p)<t, "Scheme 1 on ap3: 1.0 != "+p);
678 p = EAUtils.getCrowdingProbability(ap3,2,1.0,10,1.0);
679 assertTrue(Math.abs(1.0 - p)<t, "Scheme 2 on ap3: 1.0 != "+p);
680
682 p = EAUtils.getCrowdingProbability(ap2,2,1.0,10,1.0);
683 assertTrue(Math.abs(0.5 - p)<t, "Scheme 2 on ap2");
684 }
685
686//------------------------------------------------------------------------------
687
688 @Test
689 public void testSelectNonScaffoldNonCapVertex() throws Exception
690 {
691 DGraph g = new DGraph();
692 EmptyVertex s = new EmptyVertex();
693 s.addAP();
694 s.addAP();
696
697 EmptyVertex v = new EmptyVertex();
698 v.addAP();
699 v.addAP();
700 v.addAP();
701 v.addAP();
703
704 EmptyVertex c1 = new EmptyVertex();
705 c1.addAP();
707
708 EmptyVertex c2 = new EmptyVertex();
709 c2.addAP();
711
712 EmptyVertex c3 = new EmptyVertex();
713 c3.addAP();
715
716 EmptyVertex c4 = new EmptyVertex();
717 c4.addAP();
719
720 g.addVertex(s);
721 g.appendVertexOnAP(s.getAP(0), v.getAP(0));
722 g.appendVertexOnAP(s.getAP(1), c1.getAP(0));
723 g.appendVertexOnAP(v.getAP(1), c2.getAP(0));
724 g.appendVertexOnAP(v.getAP(2), c3.getAP(0));
725 g.appendVertexOnAP(v.getAP(3), c4.getAP(0));
726
727 Randomizer rng = new Randomizer(1234L);
728 Vertex expected = v;
729 for (int i=0; i<5; i++)
730 {
732 assertEquals(expected, chosen, "Index of the only choosable vertex");
733 }
734 }
735
736//------------------------------------------------------------------------------
737
738 @Test
739 public void testChooseNumberOfSitesToMutate() throws Exception
740 {
741 double[] weights = new double[] {0,0,0,0,1};
742 assertEquals(4,EAUtils.chooseNumberOfSitesToMutate(weights,1.0));
743 assertEquals(4,EAUtils.chooseNumberOfSitesToMutate(weights,0.00000001));
744
745 weights = new double[] {1,0,0,0,1};
746 assertEquals(4,EAUtils.chooseNumberOfSitesToMutate(weights,1.0));
747 assertEquals(0,EAUtils.chooseNumberOfSitesToMutate(weights,0.00000001));
748
749 weights = new double[] {1,1,1,1,1};
750 assertEquals(4,EAUtils.chooseNumberOfSitesToMutate(weights,1.0));
751 assertEquals(4,EAUtils.chooseNumberOfSitesToMutate(weights,0.800001));
752 assertEquals(3,EAUtils.chooseNumberOfSitesToMutate(weights,0.799999));
753 assertEquals(3,EAUtils.chooseNumberOfSitesToMutate(weights,0.600001));
754 assertEquals(2,EAUtils.chooseNumberOfSitesToMutate(weights,0.599999));
755 assertEquals(2,EAUtils.chooseNumberOfSitesToMutate(weights,0.400001));
756 assertEquals(1,EAUtils.chooseNumberOfSitesToMutate(weights,0.399999));
757 assertEquals(1,EAUtils.chooseNumberOfSitesToMutate(weights,0.200001));
758 assertEquals(0,EAUtils.chooseNumberOfSitesToMutate(weights,0.199999));
759 assertEquals(0,EAUtils.chooseNumberOfSitesToMutate(weights,0.000001));
760 }
761
762//------------------------------------------------------------------------------
763
764 @Test
765 public void testMakeGraphFromFragmentationOfMol() throws Exception
766 {
767 // We use a hard-coded molecule to ensure the 3D geometry is fixed
768 assertTrue(tempDir.isDirectory(),"Should be a directory ");
769 String structureFile = tempDir.getAbsolutePath() + SEP + "mol.sdf";
770 DenoptimIO.writeData(structureFile,
771 "" + NL
772 + " OpenBabel03302310043D" + NL
773 + "" + NL
774 + " 33 35 0 0 0 0 0 0 0 0999 V2000" + NL
775 + " -1.5455 1.4965 3.4529 O 0 0 0 0 0 0 0 0 0 0 0 0" + NL
776 + " -1.1783 1.0876 2.3182 C 0 0 0 0 0 0 0 0 0 0 0 0" + NL
777 + " -1.8597 -0.0221 1.6796 N 0 0 0 0 0 0 0 0 0 0 0 0" + NL
778 + " -3.0535 -0.6083 2.2978 C 0 0 0 0 0 0 0 0 0 0 0 0" + NL
779 + " 0.0153 1.7383 1.6547 C 0 0 0 0 0 0 0 0 0 0 0 0" + NL
780 + " -0.1038 1.5947 0.1342 C 0 0 1 0 0 0 0 0 0 0 0 0" + NL
781 + " 0.9646 2.2439 -0.5585 O 0 0 0 0 0 0 0 0 0 0 0 0" + NL
782 + " 2.0315 1.3700 -0.8940 C 0 0 2 0 0 0 0 0 0 0 0 0" + NL
783 + " 3.0842 2.1330 -1.6910 C 0 0 0 0 0 0 0 0 0 0 0 0" + NL
784 + " 3.5659 3.1894 -0.9391 F 0 0 0 0 0 0 0 0 0 0 0 0" + NL
785 + " 4.1344 1.2898 -2.0067 F 0 0 0 0 0 0 0 0 0 0 0 0" + NL
786 + " 2.5295 2.6237 -2.8597 F 0 0 0 0 0 0 0 0 0 0 0 0" + NL
787 + " 1.5529 0.2692 -1.6691 O 0 0 0 0 0 0 0 0 0 0 0 0" + NL
788 + " 0.4699 -0.4528 -1.1881 C 0 0 0 0 0 0 0 0 0 0 0 0" + NL
789 + " -0.3192 0.1414 -0.2151 C 0 0 0 0 0 0 0 0 0 0 0 0" + NL
790 + " -1.2683 -0.6053 0.4932 C 0 0 0 0 0 0 0 0 0 0 0 0" + NL
791 + " -1.5222 -1.9320 0.0906 C 0 0 0 0 0 0 0 0 0 0 0 0" + NL
792 + " -0.8092 -2.5038 -0.9766 C 0 0 0 0 0 0 0 0 0 0 0 0" + NL
793 + " -1.1169 -3.8201 -1.3518 O 0 0 0 0 0 0 0 0 0 0 0 0" + NL
794 + " -0.4725 -4.5263 -2.4070 C 0 0 0 0 0 0 0 0 0 0 0 0" + NL
795 + " 0.2040 -1.7556 -1.6127 C 0 0 0 0 0 0 0 0 0 0 0 0" + NL
796 + " -3.7666 -0.9444 1.5155 H 0 0 0 0 0 0 0 0 0 0 0 0" + NL
797 + " -3.5865 0.1389 2.9228 H 0 0 0 0 0 0 0 0 0 0 0 0" + NL
798 + " -2.7606 -1.4709 2.9321 H 0 0 0 0 0 0 0 0 0 0 0 0" + NL
799 + " 0.9449 1.2474 2.0144 H 0 0 0 0 0 0 0 0 0 0 0 0" + NL
800 + " 0.0550 2.8163 1.9227 H 0 0 0 0 0 0 0 0 0 0 0 0" + NL
801 + " -1.0337 2.1265 -0.1667 H 0 0 0 0 0 0 0 0 0 0 0 0" + NL
802 + " 2.5075 0.9860 0.0372 H 0 0 0 0 0 0 0 0 0 0 0 0" + NL
803 + " -2.2462 -2.5403 0.6157 H 0 0 0 0 0 0 0 0 0 0 0 0" + NL
804 + " -0.6162 -3.9902 -3.3689 H 0 0 0 0 0 0 0 0 0 0 0 0" + NL
805 + " -0.9204 -5.5374 -2.4930 H 0 0 0 0 0 0 0 0 0 0 0 0" + NL
806 + " 0.6107 -4.6349 -2.1878 H 0 0 0 0 0 0 0 0 0 0 0 0" + NL
807 + " 0.8117 -2.1861 -2.3969 H 0 0 0 0 0 0 0 0 0 0 0 0" + NL
808 + " 1 2 2 0 0 0 0" + NL
809 + " 2 3 1 0 0 0 0" + NL
810 + " 2 5 1 0 0 0 0" + NL
811 + " 3 4 1 0 0 0 0" + NL
812 + " 4 22 1 0 0 0 0" + NL
813 + " 4 23 1 0 0 0 0" + NL
814 + " 4 24 1 0 0 0 0" + NL
815 + " 5 6 1 0 0 0 0" + NL
816 + " 5 25 1 0 0 0 0" + NL
817 + " 5 26 1 0 0 0 0" + NL
818 + " 6 7 1 0 0 0 0" + NL
819 + " 6 27 1 6 0 0 0" + NL
820 + " 7 8 1 0 0 0 0" + NL
821 + " 8 9 1 0 0 0 0" + NL
822 + " 8 13 1 0 0 0 0" + NL
823 + " 8 28 1 1 0 0 0" + NL
824 + " 9 10 1 0 0 0 0" + NL
825 + " 9 11 1 0 0 0 0" + NL
826 + " 9 12 1 0 0 0 0" + NL
827 + " 13 14 1 0 0 0 0" + NL
828 + " 14 15 2 0 0 0 0" + NL
829 + " 15 16 1 0 0 0 0" + NL
830 + " 15 6 1 0 0 0 0" + NL
831 + " 16 17 2 0 0 0 0" + NL
832 + " 16 3 1 0 0 0 0" + NL
833 + " 17 18 1 0 0 0 0" + NL
834 + " 17 29 1 0 0 0 0" + NL
835 + " 18 19 1 0 0 0 0" + NL
836 + " 18 21 2 0 0 0 0" + NL
837 + " 19 20 1 0 0 0 0" + NL
838 + " 20 30 1 0 0 0 0" + NL
839 + " 20 31 1 0 0 0 0" + NL
840 + " 20 32 1 0 0 0 0" + NL
841 + " 21 14 1 0 0 0 0" + NL
842 + " 21 33 1 0 0 0 0" + NL
843 + "M END" + NL
844 + "$$$$", false);
845 IAtomContainer mol = DenoptimIO.readSDFFile(structureFile).get(0);
846 GAParameters settings = new GAParameters();
847
848 List<CuttingRule> cuttingRules = new ArrayList<CuttingRule>();
849 cuttingRules.add(new CuttingRule("cC", "[c]", "[C]", "~", 0,
850 new ArrayList<String>()));
851 cuttingRules.add(new CuttingRule("cN", "[c]", "[#7]", "~", 1,
852 new ArrayList<String>()));
853 cuttingRules.add(new CuttingRule("cO", "[c]", "[#8]", "~", 2,
854 new ArrayList<String>()));
855 cuttingRules.add(new CuttingRule("OC", "[O]", "[C]", "-", 3,
856 new ArrayList<String>()));
857 cuttingRules.add(new CuttingRule("CF", "[C]", "[F]", "-", 4,
858 new ArrayList<String>()));
859 cuttingRules.add(new CuttingRule("NC", "[N]", "[C]", "-", 5,
860 new ArrayList<String>()));
861
863 cuttingRules, settings.getLogger(),
865
866 assertEquals(16, graph.getVertexCount());
867 assertEquals(15, graph.getEdgeCount());
868 assertEquals(2, graph.getRingCount());
869 assertEquals(0, graph.getVertexList()
870 .stream()
871 .filter(v -> v instanceof Template)
872 .count());
873
874 DGraph graphWithTemplate = graph.embedPatternsInTemplates(
876
877 assertEquals(7, graphWithTemplate.getVertexCount());
878 assertEquals(6, graphWithTemplate.getEdgeCount());
879 assertEquals(0, graphWithTemplate.getRingCount());
880 List<Vertex> templates = graphWithTemplate.getVertexList()
881 .stream()
882 .filter(v -> v instanceof Template)
883 .collect(Collectors.toList());
884 assertEquals(1, templates.size());
885 Template tmpl = (Template) templates.get(0);
886 assertEquals(BBType.SCAFFOLD, tmpl.getBuildingBlockType());
887 assertEquals(ContractLevel.FIXED, tmpl.getContractLevel());
888 assertEquals(2, tmpl.getInnerGraph().getRingCount());
889 }
890
891//------------------------------------------------------------------------------
892
893 @Test
895 throws Exception
896 {
897 SmilesParser p = new SmilesParser(builder);
898 IAtomContainer mol = p.parseSmiles("c1ccccc1OCN(CC)(C)[Ru](N)(N)C#O");
899
900 GAParameters settings = new GAParameters();
901
902 List<CuttingRule> cuttingRules = new ArrayList<CuttingRule>();
903 cuttingRules.add(new CuttingRule("C-O", "[#6]", "[#8]", "-", 2,
904 new ArrayList<String>()));
905 cuttingRules.add(new CuttingRule("N-C", "[#7]", "[#6]", "-", 5,
906 new ArrayList<String>()));
907 cuttingRules.add(new CuttingRule("Ru-Any", "[Ru]", "[$([*])]", "~", 5,
908 new ArrayList<String>()));
909
911 cuttingRules, settings.getLogger(),
913
914 assertEquals(10, graph1.getVertexCount());
915 assertEquals(9, graph1.getEdgeCount());
916 assertEquals(0, graph1.getRingCount());
917 List<Vertex> scaffolds = graph1.getVertexList()
918 .stream()
919 .filter(v -> BBType.SCAFFOLD == v.getBuildingBlockType())
920 .collect(Collectors.toList());
921 assertEquals(1, scaffolds.size());
922 Vertex scaffold = scaffolds.get(0);
923 IAtomContainer iacScaffold = scaffold.getIAtomContainer();
924 assertEquals(6, iacScaffold.getAtomCount());
925
927 policy.label = "Ru";
928
930 cuttingRules, settings.getLogger(), policy);
931
932 assertEquals(10, graph2.getVertexCount());
933 assertEquals(9, graph2.getEdgeCount());
934 assertEquals(0, graph2.getRingCount());
935 scaffolds = graph2.getVertexList()
936 .stream()
937 .filter(v -> BBType.SCAFFOLD == v.getBuildingBlockType())
938 .collect(Collectors.toList());
939 assertEquals(1, scaffolds.size());
940 scaffold = scaffolds.get(0);
941 iacScaffold = scaffold.getIAtomContainer();
942 assertEquals(1, iacScaffold.getAtomCount());
943 assertEquals("Ru", iacScaffold.getAtom(0).getSymbol());
944 }
945
946//------------------------------------------------------------------------------
947
948 @Test
949 public void testMakeGraphFromFragmentationOfMol_Symmetry() throws Exception
950 {
951 SmilesParser p = new SmilesParser(builder);
952 IAtomContainer mol = p.parseSmiles(
953 "Oc1cc(O)cc(O)c1CN(CC)(CC)[Ru](N)(Nc1c(F)cc(F)cc1(Cl))C#O");
954
955 GAParameters settings = new GAParameters();
956
957 List<CuttingRule> cuttingRules = new ArrayList<CuttingRule>();
958 cuttingRules.add(new CuttingRule("C-F", "[#6]", "[#9]", "-", 1,
959 new ArrayList<String>()));
960 cuttingRules.add(new CuttingRule("C-O", "[#6]", "[#8]", "-", 2,
961 new ArrayList<String>()));
962 cuttingRules.add(new CuttingRule("N-C", "[#7]", "[#6]", "-", 5,
963 new ArrayList<String>()));
964 cuttingRules.add(new CuttingRule("Ru-Any", "[Ru]", "[$([*])]", "~", 5,
965 new ArrayList<String>()));
966
968 cuttingRules, settings.getLogger(),
970
971 assertEquals(14, graph1.getVertexCount());
972 assertEquals(13, graph1.getEdgeCount());
973 assertEquals(0, graph1.getRingCount());
974 assertEquals(4, graph1.getSymmetricSetCount());
975 boolean foundO = false;
976 boolean foundF = false;
977 Iterator<SymmetricVertexes> iter = graph1.getSymSetsIterator();
978 while (iter.hasNext())
979 {
980 SymmetricVertexes ss = iter.next();
981 String el = ss.get(0).getIAtomContainer().getAtom(0).getSymbol();
982 if ("O".equals(el))
983 foundO = true;
984 else if ("F".equals(el))
985 foundF = true;
986 }
987 assertTrue(foundO);
988 assertTrue(foundF);
989
991 policy.label = "Cl";
992
994 cuttingRules, settings.getLogger(), policy);
995
996 assertEquals(14, graph2.getVertexCount());
997 assertEquals(13, graph2.getEdgeCount());
998 assertEquals(0, graph2.getRingCount());
999 assertEquals(4, graph2.getSymmetricSetCount());
1000 foundO = false;
1001 foundF = false;
1002 iter = graph2.getSymSetsIterator();
1003 while (iter.hasNext())
1004 {
1005 SymmetricVertexes ss = iter.next();
1006 String el = ss.get(0).getIAtomContainer().getAtom(0).getSymbol();
1007 if ("O".equals(el))
1008 foundO = true;
1009 else if ("F".equals(el))
1010 foundF = true;
1011 }
1012 assertTrue(foundO);
1013 assertTrue(foundF);
1014
1015
1016 policy = ScaffoldingPolicy.ELEMENT;
1017 policy.label = "F";
1018
1020 cuttingRules, settings.getLogger(), policy);
1021
1022 assertEquals(14, graph3.getVertexCount());
1023 assertEquals(13, graph3.getEdgeCount());
1024 assertEquals(0, graph3.getRingCount());
1025 assertEquals(3, graph3.getSymmetricSetCount());
1026 foundO = false;
1027 foundF = false;
1028 iter = graph3.getSymSetsIterator();
1029 while (iter.hasNext())
1030 {
1031 SymmetricVertexes ss = iter.next();
1032 String el = ss.get(0).getIAtomContainer().getAtom(0).getSymbol();
1033 if ("O".equals(el))
1034 foundO = true;
1035 else if ("F".equals(el))
1036 foundF = true;
1037 }
1038 assertTrue(foundO);
1039 assertFalse(foundF);
1040 }
1041
1042//------------------------------------------------------------------------------
1043
1044 @Test
1046 throws Exception
1047 {
1048 SmilesParser p = new SmilesParser(builder);
1049 IAtomContainer mol = p.parseSmiles("C#C-C#C-C#N");
1050
1051 // 2D is enough to get linearities. No need to waste time getting 3D
1052 StructureDiagramGenerator sdg = new StructureDiagramGenerator();
1053 sdg.generateCoordinates(mol);
1054
1055 GAParameters settings = new GAParameters();
1056
1057 List<CuttingRule> cuttingRules = new ArrayList<CuttingRule>();
1058 cuttingRules.add(new CuttingRule("C-C", "[#6]", "[#6]", "-", 2,
1059 new ArrayList<String>()));
1060 cuttingRules.add(new CuttingRule("C-X", "[#6]", "[#9,#17,#35,#53]", "~",
1061 3, new ArrayList<String>()));
1062
1063 // Must add du on linearities
1065 cuttingRules, settings.getLogger(),
1067
1068 assertEquals(3, graph.getVertexCount());
1069 assertEquals(2, graph.getEdgeCount());
1070 assertEquals(0, graph.getRingCount());
1071 int duAtmCount = 0;
1072 for (Vertex v : graph.getVertexList())
1073 {
1074 for (IAtom a : v.getIAtomContainer().atoms())
1075 {
1078 duAtmCount++;
1079 }
1080
1081 }
1082 assertEquals(4, duAtmCount);
1083
1084 // Without linearities
1085 IAtomContainer molNonLinear = p.parseSmiles("C(Cl)(F)Br");
1086 sdg.generateCoordinates(molNonLinear);
1087
1088 DGraph graph1 = EAUtils.makeGraphFromFragmentationOfMol(molNonLinear,
1089 cuttingRules, settings.getLogger(),
1091
1092 assertEquals(4, graph1.getVertexCount());
1093 assertEquals(3, graph1.getEdgeCount());
1094 assertEquals(0, graph1.getRingCount());
1095 duAtmCount = 0;
1096 for (Vertex v : graph1.getVertexList())
1097 {
1098 for (IAtom a : v.getIAtomContainer().atoms())
1099 {
1102 duAtmCount++;
1103 }
1104
1105 }
1106 assertEquals(0, duAtmCount);
1107
1108 // there are linearities but we do not want Du on linearities
1110 cuttingRules, settings.getLogger(),
1112 // By default we do not add Du on linearities
1113
1114 assertEquals(3, graph2.getVertexCount());
1115 assertEquals(2, graph2.getEdgeCount());
1116 assertEquals(0, graph2.getRingCount());
1117 duAtmCount = 0;
1118 for (Vertex v : graph2.getVertexList())
1119 {
1120 for (IAtom a : v.getIAtomContainer().atoms())
1121 {
1124 duAtmCount++;
1125 }
1126
1127 }
1128 assertEquals(0, duAtmCount);
1129 }
1130
1131//------------------------------------------------------------------------------
1132
1141 @Test
1143 {
1144 SmilesParser p = new SmilesParser(builder);
1145 IAtomContainer mol = p.parseSmiles(
1146 "P123C(OC[SiH2]O1)(OC[SiH2]O2)OC[SiH2]O3");
1147 GAParameters settings = new GAParameters();
1148
1149 List<CuttingRule> cuttingRules = new ArrayList<CuttingRule>();
1150 cuttingRules.add(new CuttingRule("PC-O", "[$(CP)]", "[O]", "-", -1,
1151 new ArrayList<String>()));
1152 cuttingRules.add(new CuttingRule("C-O", "[C]", "[O]", "-", 0,
1153 new ArrayList<String>()));
1154 cuttingRules.add(new CuttingRule("C-Si", "[C]", "[Si]", "-", 1,
1155 new ArrayList<String>()));
1156 cuttingRules.add(new CuttingRule("Si-O", "[Si]", "[O]", "-", 2,
1157 new ArrayList<String>()));
1158 cuttingRules.add(new CuttingRule("P-C", "[P]", "[C]", "-", 3,
1159 new ArrayList<String>()));
1160 cuttingRules.add(new CuttingRule("P-O", "[P]", "[O]", "-", 4,
1161 new ArrayList<String>()));
1162
1164 scaffoldOnP.label = "P";
1166 cuttingRules, settings.getLogger(),
1167 scaffoldOnP, 170);
1168
1169 assertEquals(6, graph.getSymmetricSetCount());
1170 List<List<Integer>> expected = new ArrayList<List<Integer>>();
1171 expected.add(Arrays.asList(3, 9, 15));
1172 expected.add(Arrays.asList(5, 11, 17));
1173 expected.add(Arrays.asList(7, 13, 19));
1174 expected.add(Arrays.asList(4, 10, 16));
1175 expected.add(Arrays.asList(2, 8, 14));
1176 expected.add(Arrays.asList(6, 12, 18));
1177 for (List<Integer> vrtxIDs : expected)
1178 {
1180 graph.getVertexWithId(vrtxIDs.get(0)));
1181 assertFalse(sv0.isEmpty());
1182 for (int i=1; i<vrtxIDs.size(); i++)
1183 {
1185 graph.getVertexWithId(vrtxIDs.get(i)));
1186 assertTrue(sv0 == svI);
1187 }
1188 }
1189
1190 IAtomContainer mol2 = p.parseSmiles(
1191 "C1C(C(C(F)(F)(F))(C(F)(F)(F)))OCCC1((N(C([H])([H])C3=C"
1192 + "(C(=C(C(=C3[H])[H])[F])[F]))(C([H])([H])C3=C(C(=C(C"
1193 + "(=C3[H])[H])[F])[F]))))");
1194
1195 cuttingRules = new ArrayList<CuttingRule>();
1196 cuttingRules.add(new CuttingRule("C-C", "[#6]", "[#6]", "-!@", -1,
1197 new ArrayList<String>()));
1198 cuttingRules.add(new CuttingRule("C-X", "[#6]", "[#9]", "-", 0,
1199 new ArrayList<String>()));
1200 cuttingRules.add(new CuttingRule("C-N", "[#6]", "[N]", "-", 1,
1201 new ArrayList<String>()));
1202
1204
1206 cuttingRules, settings.getLogger(),
1207 scaffold, 170);
1208
1209 assertEquals(5, graph.getSymmetricSetCount());
1210 expected = new ArrayList<List<Integer>>();
1211 expected.add(Arrays.asList(11, 15));
1212 expected.add(Arrays.asList(2, 6));
1213 expected.add(Arrays.asList(3, 4, 5, 7, 8, 9));
1214 expected.add(Arrays.asList(13, 14, 17, 18));
1215 expected.add(Arrays.asList(12, 16));
1216 for (List<Integer> vrtxIDs : expected)
1217 {
1219 graph.getVertexWithId(vrtxIDs.get(0)));
1220 assertFalse(sv0.isEmpty());
1221 for (int i=1; i<vrtxIDs.size(); i++)
1222 {
1224 graph.getVertexWithId(vrtxIDs.get(i)));
1225 assertTrue(sv0 == svI);
1226 }
1227 }
1228
1229 }
1230
1231
1232//------------------------------------------------------------------------------
1233
1234 @Test
1236 throws Exception
1237 {
1238 SmilesParser p = new SmilesParser(builder);
1239 IAtomContainer mol = p.parseSmiles("Cc1cnc(Cl)cc1O");
1241
1242 // 2D is enough to get linearities. No need to waste time getting 3D
1243 StructureDiagramGenerator sdg = new StructureDiagramGenerator();
1244 sdg.generateCoordinates(mol);
1245
1246 GAParameters settings = new GAParameters();
1247
1248 List<CuttingRule> cuttingRules = new ArrayList<CuttingRule>();
1249 cuttingRules.add(new CuttingRule("sAr", "[c]", "[*]", "-", 2,
1250 new ArrayList<String>()));
1251 cuttingRules.add(new CuttingRule("Ox", "[O]", "[*]", "-", 3,
1252 new ArrayList<String>()));
1253
1254 APClass hyd1 = APClass.make("hyd:1");
1255 APClass sAr0 = APClass.make("sAr:0");
1256 APClass ox0 = APClass.make("Ox:0");
1257 Fragment capH = new Fragment();
1258 capH.addAtom(new Atom("H", new Point3d()));
1259 capH.addAP(0, hyd1, new Point3d(1.0,0,0));
1260
1261 ArrayList<Vertex> cappingGroups = new ArrayList<Vertex>();
1262 cappingGroups.add(capH);
1263
1264 HashMap<APClass, APClass> capMap = new HashMap<APClass, APClass>();
1265 capMap.put(sAr0, hyd1);
1266 capMap.put(ox0, hyd1);
1267
1269 FragmentSpace fragSpace = new FragmentSpace(fsp,
1270 new ArrayList<Vertex>(), //no scaffolds
1271 new ArrayList<Vertex>(), //no fragments
1272 cappingGroups, //H as capping
1273 new HashMap<APClass,ArrayList<APClass>>(),
1274 capMap,
1275 new HashSet<APClass>(),
1276 new HashMap<APClass,ArrayList<APClass>>());
1277 fragSpace.setAPclassBasedApproach(true);
1278
1279 settings.setParameters(fsp);
1280
1281 // Without a fragment space we do not identify capping groups
1283 cuttingRules, settings.getLogger(),
1285 assertEquals(7, graph.getVertexCount());
1286 graph.removeCappingGroups();
1287 assertEquals(7, graph.getVertexCount());
1288
1290 cuttingRules, settings.getLogger(),
1291 ScaffoldingPolicy.LARGEST_FRAGMENT, 170, fragSpace);
1292 assertEquals(7, graph.getVertexCount());
1293 //In case you want to take a look ar the results
1294 // DenoptimIO.writeGraphToSDF(new File("/tmp/graph.sdf"), graph, false,
1295 // true, settings.getLogger(), settings.getRandomizer());
1296 graph.removeCappingGroups();
1297 assertEquals(4, graph.getVertexCount());
1298 }
1299
1300//------------------------------------------------------------------------------
1301
1302 @Test
1303 public void testSearchForApPairsSuitableToRingFusion() throws Exception
1304 {
1305 APClass apcA = APClass.make("apcA:1");
1306 APClass apcB = APClass.make("apcB:1");
1307 APClass apcC = APClass.make("apcC:1");
1308 APClass apcD = APClass.make("apcD:1");
1309 APClass apcE = APClass.make("apcE:1");
1310 APClass apcF = APClass.make("apcF:1");
1311 APClass apcG = APClass.make("apcG:1");
1312 APClass apcNotFusable = APClass.make("apcNotFusable:0");
1313 APClass apcFusedBridge = APClass.make("apcFusedBridge:0");
1314 APClass hyd = APClass.make("hyd:1");
1315
1316 // Utilities
1317 Logger logger = Logger.getLogger("DummyLogger");
1318 Randomizer rng = new Randomizer();
1319
1320 // Make a fragment space that saturates all valences
1321 HashMap<APClass,APClass> capMap = new HashMap<APClass,APClass>();
1322 capMap.put(apcA,hyd);
1323 capMap.put(apcB,hyd);
1324 capMap.put(apcC,hyd);
1325 capMap.put(apcD,hyd);
1326 capMap.put(apcE,hyd);
1327 capMap.put(apcF,hyd);
1328 capMap.put(apcG,hyd);
1329 capMap.put(apcNotFusable,hyd);
1330
1331 ArrayList<Vertex> cappingGroups = new ArrayList<Vertex>();
1332 Fragment capH = new Fragment();
1333 capH.addAtom(new Atom("H", new Point3d()));
1334 capH.addAP(0, new Point3d(1.0, 0, 0), hyd);
1335 cappingGroups.add(capH);
1336
1337 // Allows some ring closures via APClass compatibility
1338 HashMap<APClass,ArrayList<APClass>> rcCMap =
1339 new HashMap<APClass,ArrayList<APClass>>();
1340 rcCMap.put(apcA, new ArrayList<APClass>(Arrays.asList(apcFusedBridge)));
1341 rcCMap.put(apcB, new ArrayList<APClass>(Arrays.asList(apcFusedBridge)));
1342 rcCMap.put(apcC, new ArrayList<APClass>(Arrays.asList(apcFusedBridge)));
1343 rcCMap.put(apcD, new ArrayList<APClass>(Arrays.asList(apcFusedBridge)));
1344 rcCMap.put(apcE, new ArrayList<APClass>(Arrays.asList(apcFusedBridge)));
1345 rcCMap.put(apcF, new ArrayList<APClass>(Arrays.asList(apcFusedBridge)));
1346 rcCMap.put(apcG, new ArrayList<APClass>(Arrays.asList(apcFusedBridge)));
1347 // NB: apcNotFusable is intentionally not added to RC-CPMap!
1348
1350 FragmentSpace fragSpace = new FragmentSpace(fsp,
1351 new ArrayList<Vertex>(), //no scaffolds
1352 new ArrayList<Vertex>(), //no fragments
1353 cappingGroups, //H as capping
1354 new HashMap<APClass,ArrayList<APClass>>(),
1355 capMap, new HashSet<APClass>(),
1356 rcCMap);
1357 fragSpace.setAPclassBasedApproach(true);
1358
1360
1361 //
1362 // Case 0: APClass compatibility decides which APs can do ring fusion
1363 //
1364 SmilesParser parser = new SmilesParser(builder);
1365 IAtomContainer mol = parser.parseSmiles("c1ccccc1");
1367 StructureDiagramGenerator sdg = new StructureDiagramGenerator();
1368 sdg.generateCoordinates(mol);
1369 Fragment frag = new Fragment(mol, BBType.FRAGMENT);
1370 replaceHatomWithAP(frag, 2, apcNotFusable);
1371 replaceHatomWithAP(frag, 3, apcNotFusable);
1372 replaceHatomWithAP(frag, 4, apcA);
1373 replaceHatomWithAP(frag, 5, apcA);
1374 DGraph graph = new DGraph();
1375 graph.addVertex(frag);
1376
1377 List<List<RelatedAPPair>> combinations = EAUtils.searchRingFusionSites(
1378 graph, fragSpace, rcParams, false, logger, rng);
1379
1380 assertEquals(1, combinations.size());
1381 assertEquals(1, combinations.get(0).size());
1382 assertEquals(2, combinations.get(0).get(0).apA.getIndexInOwner());
1383 assertEquals(3, combinations.get(0).get(0).apB.getIndexInOwner());
1384
1385
1386 //
1387 // Case 1: one benzene fragment with 6 APs all in same symmetric set,
1388 // but NO request to project on symmetric APs
1389 //
1390 parser = new SmilesParser(builder);
1391 mol = parser.parseSmiles("c1ccccc1");
1393 sdg.generateCoordinates(mol);
1394 frag = new Fragment(mol, BBType.FRAGMENT);
1395 for (int i= 0; i<6; i++)
1396 {
1397 replaceHatomWithAP(frag, i, apcA);
1398 }
1399 graph = new DGraph();
1400 graph.addVertex(frag);
1401
1402 combinations = EAUtils.searchRingFusionSites(
1403 graph, fragSpace, rcParams, false, logger, rng);
1404
1405 assertEquals(6, combinations.size());
1406 Set<AttachmentPoint> involvedAPs = new HashSet<AttachmentPoint>();
1407 for (List<RelatedAPPair> comb : combinations)
1408 {
1409 assertEquals(1, comb.size());
1410 RelatedAPPair pair = comb.get(0);
1411 assertTrue(frag.getAttachmentPoints().contains(pair.apA));
1412 assertTrue(frag.getAttachmentPoints().contains(pair.apB));
1413 assertTrue(graph.getAttachmentPoints().contains(pair.apA));
1414 assertTrue(graph.getAttachmentPoints().contains(pair.apB));
1415 involvedAPs.add(pair.apA);
1416 involvedAPs.add(pair.apB);
1417 }
1418 assertEquals(6, involvedAPs.size());
1419
1420
1421 //
1422 // Case 2: one benzene fragment with 6 APs all in same symmetric set,
1423 // and we do request projection on symmetric APs
1424 //
1425 combinations = EAUtils.searchRingFusionSites(graph, fragSpace, rcParams, true, logger, rng);
1426
1427 // we aim at the maximum symmetry, so we find two combinations that
1428 // each accounts for 3 ring-fusion sites (i.e., pairs of APs that can
1429 // be used simultaneously to create each a fused ring)
1430 assertEquals(2, combinations.size());
1431 involvedAPs = new HashSet<AttachmentPoint>();
1432 for (List<RelatedAPPair> comb : combinations)
1433 {
1434 assertEquals(3, comb.size());
1435 involvedAPs = new HashSet<AttachmentPoint>();
1436 for (RelatedAPPair pair : comb)
1437 {
1438 involvedAPs.add(pair.apA);
1439 involvedAPs.add(pair.apB);
1440 }
1441 // both combination must involve all APs due to symmetry
1442 assertEquals(6, involvedAPs.size());
1443 }
1444
1445
1446 //
1447 // Case 3: Test handling of intra-fragment symmetry (i.e., symmetric APs)
1448 // but NO request to project on symmetric APs
1449 //
1450// This is the vertex we work with (NB: A, B, C are APClasses)
1451//
1452// B A H C
1453// 3--4 11--10
1454// / \ / \
1455// A 2 5---6 9 C
1456// \ / \ /
1457// 1--0 7--8
1458// B A H C
1459//
1460 mol = parser.parseSmiles("c1ccccc1c1ccccc1");
1462 sdg.generateCoordinates(mol);
1463 frag = new Fragment(mol, BBType.FRAGMENT);
1464 replaceHatomWithAP(frag, 0, apcA);
1465 replaceHatomWithAP(frag, 1, apcB);
1466 replaceHatomWithAP(frag, 2, apcA);
1467 replaceHatomWithAP(frag, 3, apcB);
1468 replaceHatomWithAP(frag, 4, apcA);
1469 replaceHatomWithAP(frag, 8, apcC);
1470 replaceHatomWithAP(frag, 9, apcC);
1471 replaceHatomWithAP(frag, 10, apcC);
1472 frag.setVertexId(321);
1473 graph = new DGraph();
1474 graph.addVertex(frag);
1475
1476 combinations = EAUtils.searchRingFusionSites(graph, fragSpace, rcParams, false, logger, rng);
1477
1478 assertEquals(6, combinations.size());
1479 int[] apUsageCounts = new int[8];
1480 for (List<RelatedAPPair> comb : combinations)
1481 {
1482 assertEquals(1, comb.size());
1483 for (RelatedAPPair pair : comb)
1484 {
1485 apUsageCounts[pair.apA.getIndexInOwner()] =
1486 apUsageCounts[pair.apA.getIndexInOwner()] + 1;
1487 apUsageCounts[pair.apB.getIndexInOwner()] =
1488 apUsageCounts[pair.apB.getIndexInOwner()] + 1;
1489 }
1490 }
1491 assertEquals(1, apUsageCounts[0]);
1492 assertEquals(2, apUsageCounts[1]);
1493 assertEquals(2, apUsageCounts[2]);
1494 assertEquals(2, apUsageCounts[3]);
1495 assertEquals(1, apUsageCounts[4]);
1496 assertEquals(1, apUsageCounts[5]);
1497 assertEquals(2, apUsageCounts[6]);
1498 assertEquals(1, apUsageCounts[7]);
1499
1500
1501 //
1502 // Case 4: as above but we do request to project on symmetric APs
1503 //
1504// This is the vertex we work with (NB: A, B, C are APClasses)
1505//
1506// B A H C
1507// 3--4 11--10
1508// / \ / \
1509// A 2 5---6 9 C
1510// \ / \ /
1511// 1--0 7--8
1512// B A H C
1513//
1514 combinations = EAUtils.searchRingFusionSites(graph, fragSpace, rcParams, true, logger, rng);
1515
1516 assertEquals(5, combinations.size());
1517 apUsageCounts = new int[8];
1518 int[] sizesCount = new int[4];
1519 for (List<RelatedAPPair> comb : combinations)
1520 {
1521 sizesCount[comb.size()] = sizesCount[comb.size()] +1;
1522 for (RelatedAPPair pair : comb)
1523 {
1524 apUsageCounts[pair.apA.getIndexInOwner()] =
1525 apUsageCounts[pair.apA.getIndexInOwner()] + 1;
1526 apUsageCounts[pair.apB.getIndexInOwner()] =
1527 apUsageCounts[pair.apB.getIndexInOwner()] + 1;
1528 }
1529 }
1530 assertEquals(2, apUsageCounts[0]);
1531 assertEquals(3, apUsageCounts[1]);
1532 assertEquals(2, apUsageCounts[2]);
1533 assertEquals(3, apUsageCounts[3]);
1534 assertEquals(2, apUsageCounts[4]);
1535 assertEquals(1, apUsageCounts[5]);
1536 assertEquals(2, apUsageCounts[6]);
1537 assertEquals(1, apUsageCounts[7]);
1538 assertEquals(0, sizesCount[0]);
1539 assertEquals(2, sizesCount[1]);
1540 assertEquals(3, sizesCount[2]);
1541 assertEquals(0, sizesCount[3]);
1542
1543
1544 //
1545 // Case 5: mix symmetric and asymmetric and do request to project on symmetric APs
1546 //
1547// This is the vertex we work with (NB: A, B, C are APClasses)
1548//
1549// B A C D
1550// 3--4 12--11
1551// / \ / \
1552// A 2 5--6--7 10 E
1553// \ / \ /
1554// 1--0 8--9
1555// B A G F
1556//
1557 mol = parser.parseSmiles("c1ccccc1Oc1ccccc1");
1559 sdg.generateCoordinates(mol);
1560 frag = new Fragment(mol, BBType.FRAGMENT);
1561 replaceHatomWithAP(frag, 0, apcA);
1562 replaceHatomWithAP(frag, 1, apcB);
1563 replaceHatomWithAP(frag, 2, apcA);
1564 replaceHatomWithAP(frag, 3, apcB);
1565 replaceHatomWithAP(frag, 4, apcA);
1566 replaceHatomWithAP(frag, 8, apcG);
1567 replaceHatomWithAP(frag, 9, apcF);
1568 replaceHatomWithAP(frag, 10, apcE);
1569 replaceHatomWithAP(frag, 11, apcD);
1570 replaceHatomWithAP(frag, 12, apcC);
1571 frag.setVertexId(321);
1572 graph = new DGraph();
1573 graph.addVertex(frag);
1574 combinations = EAUtils.searchRingFusionSites(graph, fragSpace, rcParams, true, logger, rng);
1575
1576 assertEquals(7, combinations.size());
1577 apUsageCounts = new int[11];
1578 sizesCount = new int[4];
1579 for (List<RelatedAPPair> comb : combinations)
1580 {
1581 sizesCount[comb.size()] = sizesCount[comb.size()] +1;
1582 for (RelatedAPPair pair : comb)
1583 {
1584 apUsageCounts[pair.apA.getIndexInOwner()] =
1585 apUsageCounts[pair.apA.getIndexInOwner()] + 1;
1586 apUsageCounts[pair.apB.getIndexInOwner()] =
1587 apUsageCounts[pair.apB.getIndexInOwner()] + 1;
1588 }
1589 }
1590 assertEquals(2, apUsageCounts[0]);
1591 assertEquals(3, apUsageCounts[1]);
1592 assertEquals(2, apUsageCounts[2]);
1593 assertEquals(3, apUsageCounts[3]);
1594 assertEquals(2, apUsageCounts[4]);
1595 assertEquals(1, apUsageCounts[5]);
1596 assertEquals(2, apUsageCounts[6]);
1597 assertEquals(2, apUsageCounts[7]);
1598 assertEquals(2, apUsageCounts[8]);
1599 assertEquals(1, apUsageCounts[9]);
1600 assertEquals(0, apUsageCounts[10]);
1601 assertEquals(0, sizesCount[0]);
1602 assertEquals(4, sizesCount[1]);
1603 assertEquals(3, sizesCount[2]);
1604 assertEquals(0, sizesCount[3]);
1605
1606
1607 //
1608 // Case 6: mix different types of ring fusion sites, some 4el, other 2el
1609 // NO request to project on symmetric APs
1610 //
1611// This is the vertex we work with (NB: A, B, C are APClasses)
1612//
1613// B A C C
1614// 3--4 11--10
1615// / \ / \
1616// A 2 5---6 9 C
1617// \ / \ /
1618// 1--0 7--8
1619// B A C C
1620//
1621 mol = parser.parseSmiles("c1ccccc1c1ccccc1");
1623 sdg.generateCoordinates(mol);
1624 frag = new Fragment(mol, BBType.FRAGMENT);
1625 replaceHatomWithAP(frag, 0, apcA);
1626 replaceHatomWithAP(frag, 1, apcB);
1627 replaceHatomWithAP(frag, 2, apcA);
1628 replaceHatomWithAP(frag, 3, apcB);
1629 replaceHatomWithAP(frag, 4, apcA);
1630 replaceHatomWithAP(frag, 7, apcC);
1631 replaceHatomWithAP(frag, 8, apcC);
1632 replaceHatomWithAP(frag, 9, apcC);
1633 replaceHatomWithAP(frag, 10, apcC);
1634 replaceHatomWithAP(frag, 11, apcC);
1635 frag.setVertexId(321);
1636 graph = new DGraph();
1637 graph.addVertex(frag);
1638 combinations = EAUtils.searchRingFusionSites(graph, fragSpace, rcParams, false, logger, rng);
1639
1640 assertEquals(12, combinations.size());
1641 apUsageCounts = new int[10];
1642 sizesCount = new int[4];
1643 for (List<RelatedAPPair> comb : combinations)
1644 {
1645 sizesCount[comb.size()] = sizesCount[comb.size()] +1;
1646 for (RelatedAPPair pair : comb)
1647 {
1648 apUsageCounts[pair.apA.getIndexInOwner()] =
1649 apUsageCounts[pair.apA.getIndexInOwner()] + 1;
1650 apUsageCounts[pair.apB.getIndexInOwner()] =
1651 apUsageCounts[pair.apB.getIndexInOwner()] + 1;
1652 }
1653 }
1654 assertEquals(3, apUsageCounts[0]);
1655 assertEquals(2, apUsageCounts[1]);
1656 assertEquals(2, apUsageCounts[2]);
1657 assertEquals(2, apUsageCounts[3]);
1658 assertEquals(3, apUsageCounts[4]);
1659 assertEquals(3, apUsageCounts[5]); // AP on atm 7
1660 assertEquals(2, apUsageCounts[6]); // AP on atm 8
1661 assertEquals(2, apUsageCounts[7]); // AP on atm 9
1662 assertEquals(2, apUsageCounts[8]); // AP on atm 10
1663 assertEquals(3, apUsageCounts[9]); // AP on atm 11
1664 assertEquals(0, sizesCount[0]);
1665 assertEquals(12, sizesCount[1]);
1666 assertEquals(0, sizesCount[2]);
1667 assertEquals(0, sizesCount[3]);
1668
1669
1670 //
1671 // Case 7: mix different types of ring fusion sites, some 4el, other 2el
1672 // With request of exploiting symmetry
1673 //
1674 combinations = EAUtils.searchRingFusionSites(
1675 graph, fragSpace, rcParams, true, logger, rng);
1676
1677 assertEquals(8, combinations.size());
1678 apUsageCounts = new int[10];
1679 sizesCount = new int[4];
1680 for (List<RelatedAPPair> comb : combinations)
1681 {
1682 sizesCount[comb.size()] = sizesCount[comb.size()] +1;
1683 for (RelatedAPPair pair : comb)
1684 {
1685 apUsageCounts[pair.apA.getIndexInOwner()] =
1686 apUsageCounts[pair.apA.getIndexInOwner()] + 1;
1687 apUsageCounts[pair.apB.getIndexInOwner()] =
1688 apUsageCounts[pair.apB.getIndexInOwner()] + 1;
1689 }
1690 }
1691 assertEquals(4, apUsageCounts[0]);
1692 assertEquals(3, apUsageCounts[1]);
1693 assertEquals(2, apUsageCounts[2]);
1694 assertEquals(3, apUsageCounts[3]);
1695 assertEquals(4, apUsageCounts[4]);
1696 assertEquals(4, apUsageCounts[5]); // AP on atm 7
1697 assertEquals(3, apUsageCounts[6]); // AP on atm 8
1698 assertEquals(2, apUsageCounts[7]); // AP on atm 9
1699 assertEquals(3, apUsageCounts[8]); // AP on atm 10
1700 assertEquals(4, apUsageCounts[9]); // AP on atm 11
1701 assertEquals(0, sizesCount[0]);
1702 assertEquals(0, sizesCount[1]);
1703 assertEquals(8, sizesCount[2]);
1704 assertEquals(0, sizesCount[3]);
1705
1706
1707 //
1708 // Case 8: detect different types of ring fusion sites
1709 //
1710// This is the vertex we work with (NB: A, B, C are APClasses)
1711//
1712// [1,2] is a 2el2atm site
1713// [2,3] is a 2el2atm site
1714// [9,10] is a 2el2atm site
1715// [3,10] is a 4el4atm site
1716//
1717// A A A A
1718// 2--3 10--9 [9,11] is a 3el3atm site
1719// | \ / \ A
1720// | 4---5 8--11 [11,17] is 4el3atm site
1721// | / \ / \ A
1722// 1--0(O) 6--7 12[N+]--17 A A A A
1723// A A \ / | 20-21 26-27 33--34 38--39
1724// 14--13 | / \ / \ / | / |
1725// A \ | _18--19 22-25 28--31--32 35--37 40
1726// (N)15--16 \ / \ / \ / \ /
1727// A 24-23 30--29 36 41
1728// [6,14] is a 4el3atm site A A A A
1729//
1730//
1731 mol = parser.parseSmiles("o1cccc1c1cc2c(cc1)c[n+]3c(c2)Nc(c3)[Ru]c1ccc(cc1)c1ccc(cc1)[Ru]c1ccc(N1)c1cnN(c1)");
1733 sdg.generateCoordinates(mol);
1734 frag = new Fragment(mol, BBType.FRAGMENT);
1735 replaceHatomWithAP(frag, 1, apcA);
1736 replaceHatomWithAP(frag, 2, apcA);
1737 replaceHatomWithAP(frag, 3, apcA);
1738 replaceHatomWithAP(frag, 6, apcA);
1739 replaceHatomWithAP(frag, 9, apcA);
1740 replaceHatomWithAP(frag, 10, apcA);
1741 replaceHatomWithAP(frag, 11, apcA);
1742 replaceHatomWithAP(frag, 14, apcA);
1743 replaceHatomWithAP(frag, 15, apcA);
1744 replaceHatomWithAP(frag, 17, apcA);
1745 replaceHatomWithAP(frag, 21, apcA);
1746 replaceHatomWithAP(frag, 23, apcA);
1747 replaceHatomWithAP(frag, 26, apcA);
1748 replaceHatomWithAP(frag, 30, apcA);
1749 replaceHatomWithAP(frag, 34, apcA);
1750 replaceHatomWithAP(frag, 36, apcA);
1751 replaceHatomWithAP(frag, 38, apcA);
1752 replaceHatomWithAP(frag, 41, apcA);
1753 frag.setVertexId(321);
1754 graph = new DGraph();
1755 graph.addVertex(frag);
1756
1757 //Just in case you need to look at the mol/fragment/graph
1758 //DenoptimIO.writeSDFFile("/tmp/mol.sdf", mol);
1759 //DenoptimIO.writeVertexToSDF("/tmp/frag.sdf", frag);
1760 //DenoptimIO.writeGraphToSDF(new File("/tmp/graph.sdf"), graph, true, true, logger, rng);
1761
1762 combinations = EAUtils.searchRingFusionSites(
1763 graph, fragSpace, rcParams, false, logger, rng);
1764
1765 assertEquals(17, combinations.size());
1766 apUsageCounts = new int[18];
1767 sizesCount = new int[4];
1768 Map<String,Integer> countTypes = new HashMap<String,Integer>();
1769 for (List<RelatedAPPair> comb : combinations)
1770 {
1771 sizesCount[comb.size()] = sizesCount[comb.size()] +1;
1772 for (RelatedAPPair pair : comb)
1773 {
1774 apUsageCounts[pair.apA.getIndexInOwner()] =
1775 apUsageCounts[pair.apA.getIndexInOwner()] + 1;
1776 apUsageCounts[pair.apB.getIndexInOwner()] =
1777 apUsageCounts[pair.apB.getIndexInOwner()] + 1;
1778 if (countTypes.containsKey(pair.propID))
1779 countTypes.put(pair.propID, countTypes.get(pair.propID)+1);
1780 else
1781 countTypes.put(pair.propID, 1);
1782 }
1783 }
1784 assertEquals(1, apUsageCounts[0]); // AP on atm 1
1785 assertEquals(2, apUsageCounts[1]); // AP on atm 2
1786 assertEquals(3, apUsageCounts[2]); // AP on atm 3
1787 assertEquals(2, apUsageCounts[3]); // AP on atm 6
1788 assertEquals(2, apUsageCounts[4]); // AP on atm 9
1789 assertEquals(2, apUsageCounts[5]); // AP on atm 10
1790 assertEquals(2, apUsageCounts[6]); // AP on atm 11
1791 assertEquals(2, apUsageCounts[7]); // AP on atm 14
1792 assertEquals(1, apUsageCounts[8]); // AP on atm 15
1793 assertEquals(1, apUsageCounts[9]); // AP on atm 17
1794 assertEquals(2, apUsageCounts[10]); // AP on atm 21
1795 assertEquals(2, apUsageCounts[11]); // AP on atm 23
1796 assertEquals(2, apUsageCounts[12]); // AP on atm 26
1797 assertEquals(2, apUsageCounts[13]); // AP on atm 29
1798 assertEquals(2, apUsageCounts[14]); // AP on atm 34
1799 assertEquals(2, apUsageCounts[15]); // AP on atm 36
1800 assertEquals(2, apUsageCounts[16]); // AP on atm 38
1801 assertEquals(2, apUsageCounts[17]); // AP on atm 41
1802 assertEquals(0, sizesCount[0]);
1803 assertEquals(17, sizesCount[1]);
1804 assertEquals(0, sizesCount[2]);
1805 assertEquals(0, sizesCount[3]);
1806 assertEquals(3, countTypes.get("2el2atm")); //WARNING: hard code type name!
1807 assertEquals(2, countTypes.get("3el3atm_6+5")); //WARNING: hard code type name!
1808 assertEquals(2, countTypes.get("3el3atm_6+6")); //WARNING: hard code type name!
1809 assertEquals(4, countTypes.get("4el4atm_6+6")); //WARNING: hard code type name!
1810 assertEquals(2, countTypes.get("4el4atm_6+5")); //WARNING: hard code type name!
1811 assertEquals(4, countTypes.get("4el4atm_5+5")); //WARNING: hard code type name!
1812
1813
1814 //
1815 // Case 9: fusion involves APs located on different vertexes. In this
1816 // example each F# is a vertex.
1817 //
1818 // \-3---2
1819 // A A A / |
1820 // 1--2 1---2 F3 1
1821 // / \ / F1 \ /
1822 // 0 F0 3-|-0 3-|-0
1823 // \ / \ F2 / A
1824 // 5--4 /-0-\
1825 // A
1826 //
1827 parser = new SmilesParser(builder);
1828 IAtomContainer molF0 = parser.parseSmiles("c1ccccc1");
1830 sdg.generateCoordinates(molF0);
1831 Fragment fragF0 = new Fragment(molF0, BBType.FRAGMENT);
1832 replaceHatomWithAP(fragF0, 3, apcA);
1833 replaceHatomWithAP(fragF0, 1, apcA);
1834 replaceHatomWithAP(fragF0, 2, apcA);
1835 fragF0.setVertexId(0);
1836
1837 // NB: conformation will be ignored
1838 IAtomContainer molF1 = parser.parseSmiles("C=CC=C");
1840 sdg.generateCoordinates(molF1);
1841 Fragment fragF1 = new Fragment(molF1, BBType.FRAGMENT);
1842 replaceHatomWithAP(fragF1, 0, apcA);
1843 replaceHatomWithAP(fragF1, 0, apcA);
1844 replaceHatomWithAP(fragF1, 1, apcA);
1845 replaceHatomWithAP(fragF1, 2, apcA);
1846 replaceHatomWithAP(fragF1, 3, apcA); // 4
1847 replaceHatomWithAP(fragF1, 3, apcA);
1848 fragF1.setVertexId(1);
1849
1850 IAtomContainer molF2 = parser.parseSmiles("N");
1852 sdg.generateCoordinates(molF2);
1853 Fragment fragF2 = new Fragment(molF2, BBType.FRAGMENT);
1854 replaceHatomWithAP(fragF2, 0, apcA);
1855 replaceHatomWithAP(fragF2, 0, apcA);
1856 replaceHatomWithAP(fragF2, 0, apcA);
1857 fragF2.setVertexId(2);
1858
1859 IAtomContainer molF3 = parser.parseSmiles("C=CC=C");
1861 sdg.generateCoordinates(molF3);
1862 Fragment fragF3 = new Fragment(molF1, BBType.FRAGMENT);
1863 replaceHatomWithAP(fragF3, 0, apcA);
1864 replaceHatomWithAP(fragF3, 0, apcA);
1865 replaceHatomWithAP(fragF3, 3, apcA);
1866 fragF3.setVertexId(3);
1867
1868 Vertex rcvOnF1a = FragmentSpace.getPolarizedRCV(true);
1869 Vertex rcvOnF2 = FragmentSpace.getPolarizedRCV(false);
1870 Vertex rcvOnF1b = FragmentSpace.getPolarizedRCV(true);
1871 Vertex rcvOnF3 = FragmentSpace.getPolarizedRCV(false);
1872
1873 DGraph graphManyFrags = new DGraph();
1874 graphManyFrags.addVertex(fragF0);
1875 graphManyFrags.appendVertexOnAP(fragF0.getAP(0), fragF1.getAP(0));
1876 graphManyFrags.appendVertexOnAP(fragF1.getAP(4), fragF2.getAP(0));
1877 graphManyFrags.appendVertexOnAP(fragF1.getAP(1), rcvOnF1a.getAP(0));
1878 graphManyFrags.appendVertexOnAP(fragF2.getAP(1), rcvOnF2.getAP(0));
1879 graphManyFrags.appendVertexOnAP(fragF1.getAP(5), fragF3.getAP(0));
1880 graphManyFrags.appendVertexOnAP(fragF1.getAP(3), rcvOnF1b.getAP(0));
1881 graphManyFrags.appendVertexOnAP(fragF3.getAP(2), rcvOnF3.getAP(0));
1882 graphManyFrags.addRing(rcvOnF1a, rcvOnF2);
1883 graphManyFrags.addRing(rcvOnF1b, rcvOnF3);
1884
1885 combinations = EAUtils.searchRingFusionSites(
1886 graphManyFrags, fragSpace, rcParams, false, logger, rng);
1887
1888 assertEquals(4, combinations.size());
1889
1890 Map<Long,Integer> vertexUsageCounts = new HashMap<Long,Integer>();
1891 for (List<RelatedAPPair> comb : combinations)
1892 {
1893 for (RelatedAPPair pair : comb)
1894 {
1895 long vIdA = pair.apA.getOwner().getVertexId();
1896 if (vertexUsageCounts.containsKey(vIdA))
1897 {
1898 vertexUsageCounts.put(vIdA, vertexUsageCounts.get(vIdA)+1);
1899 } else {
1900 vertexUsageCounts.put(vIdA,1);
1901 }
1902 long vIdB = pair.apB.getOwner().getVertexId();
1903 if (vertexUsageCounts.containsKey(vIdB))
1904 {
1905 vertexUsageCounts.put(vIdB, vertexUsageCounts.get(vIdB)+1);
1906 } else {
1907 vertexUsageCounts.put(vIdB,1);
1908 }
1909 }
1910 }
1911 assertTrue(vertexUsageCounts.containsKey(fragF0.getVertexId()));
1912 // NB: the [1,2] counts double because both APs belong to fragF0
1913 assertEquals(4, vertexUsageCounts.get(fragF0.getVertexId()));
1914 assertTrue(vertexUsageCounts.containsKey(fragF1.getVertexId()));
1915 assertEquals(1, vertexUsageCounts.get(fragF1.getVertexId()));
1916 assertTrue(vertexUsageCounts.containsKey(fragF2.getVertexId()));
1917 assertEquals(2, vertexUsageCounts.get(fragF2.getVertexId()));
1918 assertTrue(vertexUsageCounts.containsKey(fragF3.getVertexId()));
1919 assertEquals(1, vertexUsageCounts.get(fragF3.getVertexId()));
1920
1921
1922 //
1923 // Case 10: aliphatic ring fusion sites
1924 //
1925//
1926// A A A A 25
1927// \ / \ / / \
1928// (O)3--4 11-10 13==14(N) 18--19(O) 24
1929// / \ / \ / \ / | |
1930// 2 5---6 9--12 15--17 20 23
1931// \ / \ / \ / \ / \ /
1932// 1--0(S) (N)7--8 16 (N)21 22
1933// / / \ / \ / / \
1934// A A A A A A A A
1936// A A
1937// 41 44 46-47
1938// A A A A 25 / \ / \ / \
1939// \ / \ / / \ 39-40-42-43-45 48 52
1940// (O)3--4 11-10 13==14(N) 18--19(O) 24 / \ / / \
1941// / \ / \ / \ / | |/ 49---50-51-53-54
1942// 2 5---6 9--12 15--17 20 23-26-27 A A | |
1943// \ / \ / \ / \ / \ / | | 56-55
1944// 1--0(S) (N)7--8 16 (N)21 22 29-28-30-31 35-36 A
1945// / / \ / \ / / \ A | | / \
1946// A A A A A A A A 33-32-34 37
1947// A \ /
1948// 38
1949// A
1950//
1951
1952 mol = parser.parseSmiles("S1CCOCC1C1NCC(CC1)C1C=NC(C1)C1CC2C(N1)CC(CC2)"
1953 + "(C1CC(C1)C1CC(C1)C1CCCC1)" // branch with two 4-member rings
1954 + "C1C(C1)C1C(C1)C1CCCC1C1C(C1)C1CCC1"); // branch with 3-member rings
1956 sdg.generateCoordinates(mol);
1957 frag = new Fragment(mol, BBType.FRAGMENT);
1958 replaceHatomWithAP(frag, 4, apcA);
1959 replaceHatomWithAP(frag, 4, apcA);
1960 replaceHatomWithAP(frag, 7, apcA);
1961 replaceHatomWithAP(frag, 8, apcA);
1962 replaceHatomWithAP(frag, 8, apcA);
1963 replaceHatomWithAP(frag, 11, apcA);
1964 replaceHatomWithAP(frag, 11, apcA);
1965 replaceHatomWithAP(frag, 16, apcA);
1966 replaceHatomWithAP(frag, 16, apcA);
1967 replaceHatomWithAP(frag, 21, apcA);
1968 replaceHatomWithAP(frag, 22, apcA);
1969 replaceHatomWithAP(frag, 22, apcA);
1970 replaceHatomWithAP(frag, 29, apcA);
1971 replaceHatomWithAP(frag, 33, apcA);
1972 replaceHatomWithAP(frag, 38, apcA);
1973 replaceHatomWithAP(frag, 41, apcA);
1974 replaceHatomWithAP(frag, 44, apcA);
1975 replaceHatomWithAP(frag, 49, apcA);
1976 replaceHatomWithAP(frag, 50, apcA);
1977 replaceHatomWithAP(frag, 56, apcA);
1978 frag.setVertexId(321);
1979 graph = new DGraph();
1980 graph.addVertex(frag);
1981
1982 combinations = EAUtils.searchRingFusionSites(
1983 graph, fragSpace, rcParams, false, logger, rng);
1984
1985 assertEquals(27, combinations.size());
1986 apUsageCounts = new int[20];
1987 countTypes = new HashMap<String,Integer>();
1988 for (List<RelatedAPPair> comb : combinations)
1989 {
1990 for (RelatedAPPair pair : comb)
1991 {
1992 apUsageCounts[pair.apA.getIndexInOwner()] =
1993 apUsageCounts[pair.apA.getIndexInOwner()] + 1;
1994 apUsageCounts[pair.apB.getIndexInOwner()] =
1995 apUsageCounts[pair.apB.getIndexInOwner()] + 1;
1996 if (countTypes.containsKey(pair.propID))
1997 countTypes.put(pair.propID, countTypes.get(pair.propID)+1);
1998 else
1999 countTypes.put(pair.propID, 1);
2000 }
2001 }
2002
2003 assertEquals(3, apUsageCounts[0]); // AP on atm 4
2004 assertEquals(3, apUsageCounts[1]); // AP on atm 4
2005 assertEquals(6, apUsageCounts[2]); // AP on atm 7
2006 assertEquals(3, apUsageCounts[3]); // AP on atm 8
2007 assertEquals(3, apUsageCounts[4]); // AP on atm 8
2008 assertEquals(3, apUsageCounts[5]); // AP on atm 11
2009 assertEquals(3, apUsageCounts[6]); // AP on atm 11
2010 assertEquals(3, apUsageCounts[7]); // AP on atm 16
2011 assertEquals(3, apUsageCounts[8]); // AP on atm 16
2012 assertEquals(4, apUsageCounts[9]); // AP on atm 21
2013 assertEquals(3, apUsageCounts[10]); // AP on atm 22
2014 assertEquals(3, apUsageCounts[11]); // AP on atm 22
2015 assertEquals(3, apUsageCounts[12]); // AP on atm 29
2016 assertEquals(2, apUsageCounts[13]); // AP on atm 33
2017 assertEquals(1, apUsageCounts[14]); // AP on atm 38
2018 assertEquals(3, apUsageCounts[15]); // AP on atm 41
2019 assertEquals(2, apUsageCounts[16]); // AP on atm 44
2020 assertEquals(1, apUsageCounts[17]); // AP on atm 49 [49,50] is not a match because it is not -@
2021 assertEquals(1, apUsageCounts[18]); // AP on atm 50
2022 assertEquals(1, apUsageCounts[19]); // AP on atm 56
2023 assertEquals(2, countTypes.get("aliph2atm")); //WARNING: hard code type name!
2024 assertEquals(4, countTypes.get("aliph3atm")); //WARNING: hard code type name!
2025 assertEquals(6, countTypes.get("aliph4atm_6+6")); //WARNING: hard code type name!
2026 assertEquals(4, countTypes.get("aliph4atm_6+5")); //WARNING: hard code type name!
2027 assertEquals(2, countTypes.get("aliph4atm_6+4")); //WARNING: hard code type name!
2028 assertEquals(2, countTypes.get("aliph4atm_6+3")); //WARNING: hard code type name!
2029 assertEquals(2, countTypes.get("aliph4atm_5+5")); //WARNING: hard code type name!
2030 assertEquals(1, countTypes.get("aliph4atm_5+4")); //WARNING: hard code type name!
2031 assertEquals(1, countTypes.get("aliph4atm_5+3")); //WARNING: hard code type name!
2032 assertEquals(1, countTypes.get("aliph4atm_4+4")); //WARNING: hard code type name!
2033 assertEquals(1, countTypes.get("aliph4atm_4+3")); //WARNING: hard code type name!
2034 assertEquals(1, countTypes.get("aliph4atm_3+3")); //WARNING: hard code type name!
2035 assertFalse(countTypes.containsKey("2el2atm")); //WARNING: hard code type name!
2036 assertFalse(countTypes.containsKey("3el3atm_6+5")); //WARNING: hard code type name!
2037 assertFalse(countTypes.containsKey("4el4atm_6+6")); //WARNING: hard code type name!
2038 assertFalse(countTypes.containsKey("4el4atm_6+5")); //WARNING: hard code type name!
2039 assertFalse(countTypes.containsKey("4el4atm_5+5")); //WARNING: hard code type name!
2040
2041
2042 //
2043 // Case 11: avoid combinatorial explosion
2044 // We trigger combinatorial explosion by enabling symmetry in a system
2045 // with many symmetric APs.
2046 //
2047 mol = parser.parseSmiles("C1CCCCCCCCC1");
2049 sdg.generateCoordinates(mol);
2050 frag = new Fragment(mol, BBType.FRAGMENT);
2051 replaceHatomWithAP(frag, 0, apcA);
2052 replaceHatomWithAP(frag, 1, apcA);
2053 replaceHatomWithAP(frag, 2, apcA);
2054 replaceHatomWithAP(frag, 3, apcA);
2055 replaceHatomWithAP(frag, 4, apcA);
2056 replaceHatomWithAP(frag, 5, apcA);
2057 replaceHatomWithAP(frag, 6, apcA);
2058 replaceHatomWithAP(frag, 7, apcA);
2059 replaceHatomWithAP(frag, 8, apcA);
2060 replaceHatomWithAP(frag, 9, apcA);
2061 replaceHatomWithAP(frag, 0, apcA);
2062 replaceHatomWithAP(frag, 1, apcA);
2063 replaceHatomWithAP(frag, 2, apcA);
2064 replaceHatomWithAP(frag, 3, apcA);
2065 replaceHatomWithAP(frag, 4, apcA);
2066 replaceHatomWithAP(frag, 5, apcA);
2067 replaceHatomWithAP(frag, 6, apcA);
2068 replaceHatomWithAP(frag, 7, apcA);
2069 replaceHatomWithAP(frag, 8, apcA);
2070 replaceHatomWithAP(frag, 9, apcA);
2071 frag.setVertexId(321);
2072 graph = new DGraph();
2073 graph.addVertex(frag);
2074
2075 combinations = EAUtils.searchRingFusionSites(
2076 graph, fragSpace, rcParams, true, logger, rng);
2077
2078 // NB: given by the hard-coded limit to the number of combinations
2079 assertEquals(136, combinations.size());
2080 // NB: given by the hard-coded limit to the max number of ring
2081 // fusions on a single vertex.
2082 assertEquals(6, combinations.get(0).size());
2083
2084
2085 //
2086 // Case 12: detect 5el sites
2087 //
2088 //
2089 // 15--v16
2090 // | |
2091 // 14 11
2092 // \ / \
2093 // 10 12
2094 // | |
2095 // 0 9 13
2096 // / \ / \ /
2097 // 5 1 8
2098 // | | |
2099 // 4 2 7
2100 // \ / \ /
2101 // 3 6
2102 //
2103 //
2104 // 0 5 9 13
2105 mol = parser.parseSmiles("c1c2c(ccc1)ccc3c2c(c1cc3)cNc1");
2107 sdg.generateCoordinates(mol);
2108 frag = new Fragment(mol, BBType.FRAGMENT);
2109 replaceHatomWithAP(frag, 0, apcA);
2110 replaceHatomWithAP(frag, 3, apcA);
2111 replaceHatomWithAP(frag, 6, apcA);
2112 replaceHatomWithAP(frag, 13, apcA);
2113 replaceHatomWithAP(frag, 14, apcA);
2114 replaceHatomWithAP(frag, 16, apcA);
2115 frag.setVertexId(321);
2116 graph = new DGraph();
2117 graph.addVertex(frag);
2118
2119 combinations = EAUtils.searchRingFusionSites(
2120 graph, fragSpace, rcParams, false, logger, rng);
2121
2122 assertEquals(2, combinations.size());
2123 apUsageCounts = new int[6];
2124 sizesCount = new int[3];
2125 countTypes = new HashMap<String,Integer>();
2126 for (List<RelatedAPPair> comb : combinations)
2127 {
2128 sizesCount[comb.size()] = sizesCount[comb.size()] +1;
2129 for (RelatedAPPair pair : comb)
2130 {
2131 apUsageCounts[pair.apA.getIndexInOwner()] =
2132 apUsageCounts[pair.apA.getIndexInOwner()] + 1;
2133 apUsageCounts[pair.apB.getIndexInOwner()] =
2134 apUsageCounts[pair.apB.getIndexInOwner()] + 1;
2135 if (countTypes.containsKey(pair.propID))
2136 countTypes.put(pair.propID, countTypes.get(pair.propID)+1);
2137 else
2138 countTypes.put(pair.propID, 1);
2139 }
2140 }
2141 assertEquals(1, apUsageCounts[0]); // AP on atm 1
2142 assertEquals(1, apUsageCounts[1]); // AP on atm 3
2143 assertEquals(1, apUsageCounts[2]); // AP on atm 6
2144 assertEquals(0, apUsageCounts[3]); // AP on atm 13
2145 assertEquals(1, apUsageCounts[4]); // AP on atm 14
2146 assertEquals(0, apUsageCounts[5]); // AP on atm 16
2147 assertEquals(0, sizesCount[0]);
2148 assertEquals(2, sizesCount[1]);
2149 assertEquals(0, sizesCount[2]);
2150 assertEquals(1, countTypes.get("3el3atm_6+6")); //WARNING: hard code type name!
2151 assertEquals(1, countTypes.get("5el5atm_6+6+6")); //WARNING: hard code type name!
2152
2153
2154 //
2155 // Case 13: ignore constrained 5el sites
2156 //
2157 // 15
2158 // / \
2159 // 14 16
2160 // | |
2161 // 13 11
2162 // A \ / \
2163 // 10 12
2164 // A | /
2165 // 0 9 /
2166 // / \ / \ /
2167 // 5 1 8
2168 // | | |
2169 // 4 2 7
2170 // \ / \ /
2171 // 3 6
2172 //
2173 // 0 5 9 12
2174 mol = parser.parseSmiles("c1c2c(ccc1)ccc3c2c(c1N3)cccc1");
2176 sdg.generateCoordinates(mol);
2177 frag = new Fragment(mol, BBType.FRAGMENT);
2178 replaceHatomWithAP(frag, 0, apcA);
2179 replaceHatomWithAP(frag, 3, apcA);
2180 replaceHatomWithAP(frag, 6, apcA);
2181 replaceHatomWithAP(frag, 12, apcA);
2182 replaceHatomWithAP(frag, 13, apcA);
2183 replaceHatomWithAP(frag, 15, apcA);
2184 frag.setVertexId(321);
2185 graph = new DGraph();
2186 graph.addVertex(frag);
2187
2188 combinations = EAUtils.searchRingFusionSites(
2189 graph, fragSpace, rcParams, false, logger, rng);
2190
2191 assertEquals(1, combinations.size());
2192 assertEquals(1, combinations.get(0).size());
2193 //WARNING: hard code type name!
2194 assertEquals("3el3atm_6+6", combinations.get(0).get(0).propID);
2195
2196
2197 //
2198 // Case 12: detect 5el sites
2199 //
2200 // A
2201 // 13---14
2202 // | |
2203 // 12 10
2204 // A \ / \
2205 // 11 9
2206 // A | |
2207 // 0 6 8 A
2208 // / \ / \ /
2209 // 5 1 7
2210 // | |
2211 // 4 2
2212 // \ /
2213 // 3
2214 //
2215 //
2216 // 0 5
2217 mol = parser.parseSmiles("c1c(cccc1)c1cccc2c1cNc2");
2219 sdg.generateCoordinates(mol);
2220 frag = new Fragment(mol, BBType.FRAGMENT);
2221 replaceHatomWithAP(frag, 0, apcA);
2222 replaceHatomWithAP(frag, 8, apcA);
2223 replaceHatomWithAP(frag, 12, apcA);
2224 replaceHatomWithAP(frag, 14, apcA);
2225 frag.setVertexId(321);
2226 graph = new DGraph();
2227 graph.addVertex(frag);
2228
2229 combinations = EAUtils.searchRingFusionSites(
2230 graph, fragSpace, rcParams, false, logger, rng);
2231
2232 assertEquals(1, combinations.size());
2233 assertEquals(1, combinations.get(0).size());
2234 //WARNING: hard code type name!
2235 assertEquals("5el5atm_6-6*", combinations.get(0).get(0).propID);
2236
2237
2238 //
2239 // Case 13: detect 5el sites
2240 //
2241 //
2242 // 13---12
2243 // | |
2244 // 14 11
2245 // A \ /
2246 // 10
2247 // A |
2248 // 0 9
2249 // / \ / \ A
2250 // 5 1 8
2251 // | | |
2252 // 4 2 7
2253 // \ / \ /
2254 // 3 6
2255 //
2256 //
2257 // 0 5 9
2258 mol = parser.parseSmiles("c1c2c(ccc1)cccc2c1cNcc1");
2260 sdg.generateCoordinates(mol);
2261 frag = new Fragment(mol, BBType.FRAGMENT);
2262 replaceHatomWithAP(frag, 0, apcA);
2263 replaceHatomWithAP(frag, 8, apcA);
2264 replaceHatomWithAP(frag, 11, apcA);
2265 frag.setVertexId(321);
2266 graph = new DGraph();
2267 graph.addVertex(frag);
2268
2269 //Just in case you need to look at the mol/fragment/graph
2270 //DenoptimIO.writeSDFFile("/tmp/mol.sdf", mol);
2271 //DenoptimIO.writeVertexToSDF("/tmp/frag.sdf", frag);
2272 //DenoptimIO.writeGraphToSDF(new File("/tmp/graph.sdf"), graph, true, true, logger, rng);
2273
2274 combinations = EAUtils.searchRingFusionSites(
2275 graph, fragSpace, rcParams, false, logger, rng);
2276
2277 assertEquals(2, combinations.size());
2278 boolean found4el = false;
2279 boolean found5el = false;
2280 for (List<RelatedAPPair> comb : combinations)
2281 {
2282 assertEquals(1, combinations.get(0).size());
2283 RelatedAPPair pair = comb.get(0);
2284 if ("4el4atm_6+5".equals(pair.propID))
2285 found4el = true;
2286 if ("5el5atm_66-*".equals(pair.propID))
2287 found5el = true;
2288 }
2289 assertTrue(found4el);
2290 assertTrue(found5el);
2291 }
2292
2293//------------------------------------------------------------------------------
2294
2295 @Test
2296 public void testFusionSiteDetection_ImposeSymmetry() throws Exception
2297 {
2298 APClass apcSymImposed = APClass.make("apcA:1");
2299 APClass apcFree = APClass.make("apcB:1");
2300 APClass apcFusedBridge = APClass.make("apcFusedBridge:0");
2301 APClass hyd = APClass.make("hyd:1");
2302
2303 // Utilities
2304 Logger logger = Logger.getLogger("DummyLogger");
2305 Randomizer rng = new Randomizer();
2306
2307 // Make a fragment space that saturates all valences
2308 HashMap<APClass,APClass> capMap = new HashMap<APClass,APClass>();
2309 capMap.put(apcSymImposed, hyd);
2310 capMap.put(apcFree, hyd);
2311
2312 ArrayList<Vertex> cappingGroups = new ArrayList<Vertex>();
2313 Fragment capH = new Fragment();
2314 capH.addAtom(new Atom("H", new Point3d()));
2315 capH.addAP(0, new Point3d(1.0, 0, 0), hyd);
2316 cappingGroups.add(capH);
2317
2318 // Allows some ring closures via APClass compatibility
2319 HashMap<APClass,ArrayList<APClass>> rcCMap =
2320 new HashMap<APClass,ArrayList<APClass>>();
2321 rcCMap.put(apcSymImposed, new ArrayList<APClass>(Arrays.asList(apcFusedBridge)));
2322 // NB: apcNotFusable is intentionally not added to RC-CPMap!
2323
2325 FragmentSpace fragSpace = new FragmentSpace(fsp,
2326 new ArrayList<Vertex>(), //no scaffolds
2327 new ArrayList<Vertex>(), //no fragments
2328 cappingGroups, //H as capping
2329 new HashMap<APClass,ArrayList<APClass>>(),
2330 capMap, new HashSet<APClass>(),
2331 rcCMap);
2332 fragSpace.setAPclassBasedApproach(true);
2333
2334 /*
2335 HashMap<APClass, Double> symmetryConstraints =
2336 new HashMap<APClass, Double>();
2337 symmetryConstraints.put(apcSymImposed, 1.0);
2338 fragSpace.setSymmConstraints(symmetryConstraints);
2339 */
2340
2342
2343 SmilesParser parser = new SmilesParser(builder);
2344 IAtomContainer mol = parser.parseSmiles("c1ccccc1");
2346 StructureDiagramGenerator sdg = new StructureDiagramGenerator();
2347 sdg.generateCoordinates(mol);
2348 Fragment frag = new Fragment(mol, BBType.FRAGMENT);
2349 replaceHatomWithAP(frag, 0, apcSymImposed);
2350 replaceHatomWithAP(frag, 1, apcSymImposed);
2351 replaceHatomWithAP(frag, 2, apcFree);
2352 replaceHatomWithAP(frag, 3, apcSymImposed);
2353 replaceHatomWithAP(frag, 4, apcSymImposed);
2354 replaceHatomWithAP(frag, 5, apcFree);
2355 DGraph graph = new DGraph();
2356 graph.addVertex(frag);
2357
2358 List<List<RelatedAPPair>> combinations = EAUtils.searchRingFusionSites(
2359 graph, fragSpace, rcParams, false, logger, rng);
2360
2361 // 0:1 and 3:4 taken independently
2362 assertEquals(2, combinations.size());
2363
2364 // Now apply symmetry constraint and do it again
2365
2366 HashMap<APClass, Double> symmetryConstraints =
2367 new HashMap<APClass, Double>();
2368 symmetryConstraints.put(apcSymImposed, 1.0);
2369 fragSpace.setSymmConstraints(symmetryConstraints);
2370
2371 combinations = EAUtils.searchRingFusionSites(
2372 graph, fragSpace, rcParams, false, logger, rng);
2373
2374 // 0:1 and 3:4 are part of the same combination of rings
2375 assertEquals(1, combinations.size());
2376 assertEquals(2, combinations.get(0).size());
2377 }
2378
2379//------------------------------------------------------------------------------
2380
2381 public static void replaceHatomWithAP(Fragment frag, int srcId, APClass apc)
2382 {
2383 boolean done = false;
2384 for (IAtom atm : frag.getConnectedAtomsList(frag.getAtom(srcId)))
2385 {
2386 if ("H".equals(MoleculeUtils.getSymbolOrLabel(atm)))
2387 {
2388 frag.addAP(srcId, MoleculeUtils.getPoint3d(atm), apc);
2389 frag.removeAtom(atm);
2390 done = true;
2391 break;
2392 }
2393 }
2394 if (!done)
2395 throw new IllegalStateException("No H found that could be changed "
2396 + "into an AP.");
2397 }
2398
2399//------------------------------------------------------------------------------
2400
2401 @Test
2402 public void testGetUsableAromaticBridges() throws Exception
2403 {
2404 ArrayList<Vertex> libFrags = new ArrayList<Vertex>();
2405
2406 APClass apcA = APClass.make("apcA:1");
2407 APClass APC2EL = APClass.make("2el:0");
2408 APClass APC4EL = APClass.make("4el:0");
2409
2410 Fragment bridge4elA = new Fragment(4);
2411 IAtom a4elA_0 = new Atom("C", new Point3d());
2412 IAtom a4elA_1 = new Atom("C", new Point3d());
2413 IAtom a4elA_2 = new Atom("C", new Point3d());
2414 IAtom a4elA_3 = new Atom("C", new Point3d());
2415 bridge4elA.addAtom(a4elA_0);
2416 bridge4elA.addAtom(a4elA_1);
2417 bridge4elA.addAtom(a4elA_2);
2418 bridge4elA.addAtom(a4elA_3);
2419 bridge4elA.addBond(new Bond(a4elA_0, a4elA_1, IBond.Order.DOUBLE));
2420 bridge4elA.addBond(new Bond(a4elA_1, a4elA_2, IBond.Order.SINGLE));
2421 bridge4elA.addBond(new Bond(a4elA_2, a4elA_3, IBond.Order.DOUBLE));
2422 bridge4elA.addAP(0, new Point3d(), APC4EL);
2423 bridge4elA.addAP(3, new Point3d(), APC4EL);
2424 bridge4elA.addAP(0, new Point3d(), apcA);
2425 bridge4elA.addAP(1, new Point3d(), apcA);
2426 bridge4elA.addAP(2, new Point3d(), apcA);
2427 bridge4elA.addAP(3, new Point3d(), apcA);
2428 libFrags.add(bridge4elA);
2429
2430 Fragment bridge4elB = new Fragment(5);
2431 IAtom a4elB_0 = new Atom("Si", new Point3d());
2432 IAtom a4elB_1 = new Atom("Si", new Point3d());
2433 IAtom a4elB_2 = new Atom("Si", new Point3d());
2434 IAtom a4elB_3 = new Atom("Si", new Point3d());
2435 bridge4elB.addAtom(a4elB_0);
2436 bridge4elB.addAtom(a4elB_1);
2437 bridge4elB.addAtom(a4elB_2);
2438 bridge4elB.addAtom(a4elB_3);
2439 bridge4elB.addBond(new Bond(a4elB_0, a4elB_1, IBond.Order.DOUBLE));
2440 bridge4elB.addBond(new Bond(a4elB_1, a4elB_2, IBond.Order.SINGLE));
2441 bridge4elB.addBond(new Bond(a4elB_2, a4elB_3, IBond.Order.DOUBLE));
2442 bridge4elB.addAP(0, new Point3d(), APC4EL);
2443 bridge4elB.addAP(3, new Point3d(), APC4EL);
2444 libFrags.add(bridge4elB);
2445
2446 Fragment bridge2elA = new Fragment(6);
2447 IAtom a2elA_0 = new Atom("O", new Point3d());
2448 bridge2elA.addAtom(a2elA_0);
2449 bridge2elA.addAP(0, new Point3d(), APC2EL);
2450 bridge2elA.addAP(0, new Point3d(), APC2EL);
2451 libFrags.add(bridge2elA);
2452
2453 Fragment bridge2elB = new Fragment(7);
2454 IAtom a2elB_0 = new Atom("C", new Point3d());
2455 IAtom a2elB_1 = new Atom("C", new Point3d());
2456 bridge2elB.addAtom(a2elB_0);
2457 bridge2elB.addAtom(a2elB_1);
2458 bridge2elB.addBond(new Bond(a2elB_0, a2elB_1, IBond.Order.DOUBLE));
2459 bridge2elB.addAP(0, new Point3d(), APC2EL);
2460 bridge2elB.addAP(1, new Point3d(), APC2EL);
2461 bridge2elB.addAP(0, new Point3d(), apcA);
2462 bridge2elB.addAP(1, new Point3d(), apcA);
2463 libFrags.add(bridge2elB);
2464
2465 // Only to trigger class-based approach
2466 HashMap<APClass,ArrayList<APClass>> cpMap =
2467 new HashMap<APClass,ArrayList<APClass>>();
2468 cpMap.put(apcA, new ArrayList<APClass>());
2469
2471 FragmentSpace fs = new FragmentSpace(fsp,
2472 new ArrayList<Vertex>(),
2473 libFrags,
2474 new ArrayList<Vertex>(),
2475 cpMap,
2476 new HashMap<APClass,APClass>(),
2477 new HashSet<APClass>(),
2478 new HashMap<APClass,ArrayList<APClass>>());
2479
2480 // Wrong size is enough to find no match
2481 List<Vertex> lst = EAUtils.getUsableAromaticBridges("4el", new int[]{5},
2482 fs);
2483 assertEquals(0, lst.size());
2484
2485 // Wrong number of electrons is enough to find no match
2486 lst = EAUtils.getUsableAromaticBridges("19el", new int[]{4}, fs);
2487 assertEquals(0, lst.size());
2488
2489 // both #el and size need to be good
2490 lst = EAUtils.getUsableAromaticBridges("4el", new int[]{4}, fs);
2491 assertEquals(2, lst.size());
2492
2493 lst = EAUtils.getUsableAromaticBridges("2el", new int[]{1}, fs);
2494 assertEquals(1, lst.size());
2495
2496 lst = EAUtils.getUsableAromaticBridges("2el", new int[]{2}, fs);
2497 assertEquals(1, lst.size());
2498 }
2499
2500//------------------------------------------------------------------------------
2501
2502 @Test
2503 public void testGetUsableAliphaticBridges() throws Exception
2504 {
2505 ArrayList<Vertex> libFrags = new ArrayList<Vertex>();
2506
2507 APClass apcA = APClass.make("A:1");
2508 APClass apcB = APClass.make("B:0");
2509 APClass apcC = APClass.make("C:2");
2510 APClass apcD = APClass.make("D:2");
2511
2512 SmilesParser parser = new SmilesParser(builder);
2513 StructureDiagramGenerator sdg = new StructureDiagramGenerator();
2514
2515 IAtomContainer mol = parser.parseSmiles("CC");
2517 sdg.generateCoordinates(mol);
2518 Fragment frag = new Fragment(mol, BBType.FRAGMENT);
2519 replaceHatomWithAP(frag, 0, apcA);
2520 replaceHatomWithAP(frag, 0, apcB);
2521 replaceHatomWithAP(frag, 1, apcA);
2522 replaceHatomWithAP(frag, 1, apcD);
2523 frag.setBuildingBlockId(0);
2524 libFrags.add(frag);
2525
2526 IAtomContainer mol1 = parser.parseSmiles("CCC");
2528 sdg.generateCoordinates(mol1);
2529 Fragment frag1 = new Fragment(mol1, BBType.FRAGMENT);
2530 replaceHatomWithAP(frag1, 0, apcA);
2531 replaceHatomWithAP(frag1, 2, apcA);
2532 frag1.setBuildingBlockId(1);
2533 libFrags.add(frag1);
2534
2535 IAtomContainer mol2 = parser.parseSmiles("CCCC");
2537 sdg.generateCoordinates(mol2);
2538 Fragment frag2 = new Fragment(mol2, BBType.FRAGMENT);
2539 replaceHatomWithAP(frag2, 0, apcA);
2540 replaceHatomWithAP(frag2, 3, apcA);
2541 frag2.setBuildingBlockId(2);
2542 libFrags.add(frag2);
2543
2544 IAtomContainer mol3 = parser.parseSmiles("CCCCC");
2546 sdg.generateCoordinates(mol3);
2547 Fragment frag3 = new Fragment(mol3, BBType.FRAGMENT);
2548 replaceHatomWithAP(frag3, 0, apcA);
2549 replaceHatomWithAP(frag3, 1, apcA);
2550 replaceHatomWithAP(frag3, 4, apcA);
2551 frag3.setBuildingBlockId(3);
2552 libFrags.add(frag3);
2553
2554 // Only to trigger class-based approach
2555 HashMap<APClass,ArrayList<APClass>> cpMap =
2556 new HashMap<APClass,ArrayList<APClass>>();
2557 cpMap.put(apcB, new ArrayList<APClass>(Arrays.asList(apcA)));
2558 cpMap.put(apcC, new ArrayList<APClass>(Arrays.asList(apcD)));
2559
2561 FragmentSpace fs = new FragmentSpace(fsp,
2562 new ArrayList<Vertex>(),
2563 libFrags,
2564 new ArrayList<Vertex>(),
2565 cpMap,
2566 new HashMap<APClass,APClass>(),
2567 new HashSet<APClass>(),
2568 new HashMap<APClass,ArrayList<APClass>>());
2569
2570 // Same class on both ends
2571 List<Vertex> lst = EAUtils.getUsableAliphaticBridges(apcB, apcB,
2572 new int[]{2}, fs);
2573 assertEquals(4, lst.size());
2574
2575 // Multiple lengths
2576 lst = EAUtils.getUsableAliphaticBridges(apcB, apcB, new int[]{2,4}, fs);
2577 assertEquals(8, lst.size());
2578
2579 // APClass compatibility
2580 lst = EAUtils.getUsableAliphaticBridges(apcB, apcC, new int[]{2,4}, fs);
2581 assertEquals(1, lst.size());
2582 }
2583
2584//------------------------------------------------------------------------------
2585
2586}
General set of constants used in DENOPTIM.
static final String DUMMYATMSYMBOL
Symbol of dummy atom.
Class defining a space of building blocks.
void appendVertexToLibrary(Vertex v, Vertex.BBType bbt, ArrayList< Vertex > library)
Takes a vertex and add it to a given library.
void setAPclassBasedApproach(boolean useAPC)
Set the fragment space to behave according to APClass-based approach.
static Vertex getPolarizedRCV(boolean polarity)
Returns a newly-built vertex that can play the role of a ring-closing vertex even when working with 3...
void setSymmConstraints(HashMap< APClass, Double > map)
ArrayList< Vertex > getScaffoldLibrary()
ArrayList< Vertex > getFragmentLibrary()
Parameters defining the fragment space.
Helper methods for the genetic algorithm.
Definition: EAUtils.java:102
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 int chooseNumberOfSitesToMutate(double[] multiSiteMutationProb, double hit)
Takes a decision on how many sites to mutate on a candidate.
Definition: EAUtils.java:219
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 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:1029
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:3185
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:2368
static List< List< RelatedAPPair > > searchRingFusionSites(DGraph graph, GAParameters gaParams)
Definition: EAUtils.java:2585
static DGraph buildGraph(GAParameters settings)
Graph construction starts with selecting a random core/scaffold.
Definition: EAUtils.java:1917
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:3141
static Vertex selectNonScaffoldNonCapVertex(DGraph g, Randomizer randomizer)
Chose randomly a vertex that is neither scaffold or capping group.
Definition: EAUtils.java:1604
void testMakeGraphFromFragmentationOfMol()
void testCandidateGenerationMethodReproducibility()
FragmentSpaceParameters prepare()
static final String NL
void testSearchForApPairsSuitableToRingFusion()
static void replaceHatomWithAP(Fragment frag, int srcId, APClass apc)
void testFusionSiteDetection_ImposeSymmetry()
void testSelectNonScaffoldNonCapVertex()
void testMakeGraphFromFragmentationOfMol_symmetry()
Test the detection of "some" symmetry.
void testMakeGraphFromFragmentationOfMol_linearities()
void testMakeGraphFromFragmentationOfMol_Symmetry()
IChemObjectBuilder builder
Private builder of atom containers.
void testChooseNumberOfSitesToMutate()
void testBuildGraphFromTemplateScaffold()
void testMakeGraphFromFragmentationOfMol_cappingGroups()
void testMakeGraphFromFragmentationOfMol_ScaffoldingPolicy()
void testBuildByXOver_Embedded_Free()
NB: the graphs from methods getPairOfTestGraphsB() and getPairOfTestGraphsBxo() and getPairOfTestGr...
static final String SEP
void testBuildByXOver_Embedded_FixedStructure()
void testBuildByXOver_Embedded_FreeBackwards()
NB: the graphs from methods getPairOfTestGraphsB() and getPairOfTestGraphsBxo() and getPairOfTestGr...
A collection of candidates.
Definition: Population.java:48
boolean add(Candidate c)
Definition: Population.java:87
static GAParameters prepare()
static DGraph[] getPairOfTestGraphsBxoxo()
Builds a pair of graphs that contain templates with ContractLevel#FREE contract.
static DGraph makeGraphE()
Produced a graph like this:
static DGraph[] getPairOfTestGraphsB()
Builds a pair of graphs that contain templates with ContractLevel#FREE contract.
static DGraph[] getPairOfTestGraphsBxo()
Builds a pair of graphs that contain templates with ContractLevel#FREE contract.
static DGraph makeGraphA()
Produced a graph like this:
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....
A candidate is the combination of a denoptim graph with molecular representation and may include also...
Definition: Candidate.java:40
void setFitness(double fitness)
Definition: Candidate.java:480
Container for the list of vertices and the edges that connect them.
Definition: DGraph.java:104
Vertex getVertexWithId(long vid)
Searches for a vertex with the given identifier.
Definition: DGraph.java:3231
int getSymmetricSetCount()
Returns the number of symmetric sets of vertices.
Definition: DGraph.java:323
ArrayList< AttachmentPoint > getAttachmentPoints()
Returns the list of all attachment points contained in this graph.
Definition: DGraph.java:4620
boolean isIsomorphicTo(DGraph other)
Checks if this graph is "DENOPTIM-isomorphic" to the other one given.
Definition: DGraph.java:4103
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
Iterator< SymmetricVertexes > getSymSetsIterator()
Get an iterator for the sets of symmetrically related vertices.
Definition: DGraph.java:334
Vertex getVertexAtPosition(int pos)
Returns the vertex that is in the given position of the list of vertices belonging to this graph.
Definition: DGraph.java:3163
void appendVertexOnAP(AttachmentPoint srcAP, AttachmentPoint trgAP)
Append a vertex to this graph: adds the new vertex to the list of vertices belonging to the graph,...
Definition: DGraph.java:6476
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 removeCappingGroups(List< Vertex > lstVerts)
Remove capping groups that belong to this graph and are in the given list.
Definition: DGraph.java:4764
boolean sameAs(DGraph other, StringBuilder reason)
Compare this and another graph ignoring the vertex IDs.
Definition: DGraph.java:4315
SymmetricVertexes getSymSetForVertex(Vertex v)
Returns the set of vertexes symmetric to the given one.
Definition: DGraph.java:863
void addRing(Ring ring)
Definition: DGraph.java:1304
boolean isIsostructuralTo(DGraph other)
Checks if this graph is "DENOPTIM-isostructural" to the other one given.
Definition: DGraph.java:4230
Unit test for DENOPTIMGraph.
Definition: DGraphTest.java:72
static DGraph makeTestGraphA()
Build a graph meant to be used in unit tests.
An empty vertex has the behaviors of a vertex, but has no molecular structure.
void addAP()
Adds an attachment point with no APClass or other attribute.
Class representing a continuously connected portion of chemical object holding attachment points.
Definition: Fragment.java:61
List< IAtom > getConnectedAtomsList(IAtom atom)
Definition: Fragment.java:943
void addAP(int atomPositionNumber)
Adds an attachment point with a dummy APClass.
Definition: Fragment.java:343
void addBond(IBond bond)
Definition: Fragment.java:871
List< AttachmentPoint > getAttachmentPoints()
Definition: Fragment.java:1141
void addAtom(IAtom atom)
Definition: Fragment.java:836
IAtom getAtom(int number)
Definition: Fragment.java:843
void removeAtom(IAtom atom)
Definition: Fragment.java:899
A collection of Vertexs that are related by a relation that we call "symmetry", even though this clas...
ContractLevel getContractLevel()
Returns the contract level of this template, i.e., to what extent the content of this template can be...
Definition: Template.java:203
List< Vertex > getMutationSites(List< MutationType > ignoredTypes)
A list of mutation sites from within this vertex.
Definition: Template.java:886
void setContractLevel(ContractLevel contract)
Imposes the given contract to this template.
Definition: Template.java:214
A vertex is a data structure that has an identity and holds a list of AttachmentPoints.
Definition: Vertex.java:61
void setVertexId(long vertexId2)
Definition: Vertex.java:281
Vertex.BBType getBuildingBlockType()
Definition: Vertex.java:318
void setAsRCV(boolean isRCV)
Definition: Vertex.java:274
void setBuildingBlockId(int buildingBlockId)
Definition: Vertex.java:311
void setBuildingBlockType(Vertex.BBType buildingBlockType)
Definition: Vertex.java:325
abstract IAtomContainer getIAtomContainer()
AttachmentPoint getAP(int i)
Get attachment point i on this vertex.
Definition: Vertex.java:1007
static Vertex newVertexFromLibrary(int bbId, Vertex.BBType bbt, FragmentSpace fragSpace)
Builds a new molecular fragment kind of vertex.
Definition: Vertex.java:214
Parameters and setting related to handling ring closures.
Utility methods for input/output.
static ArrayList< IAtomContainer > readSDFFile(String fileName)
Reads a file containing multiple molecules.
static void writeData(String fileName, String data, boolean append)
Write text-like data file.
A collection of counters user to count actions taken by the evolutionary algorithm.
Definition: Monitor.java:37
void setParameters(RunTimeParameters otherParams)
Logger getLogger()
Get the name of the program specific logger.
Parameters for genetic algorithm.
A cutting rule with three SMARTS queries (atom 1, bond, atom2) and options.
Utilities for molecule conversion.
static String getSymbolOrLabel(IAtom atm)
Gets either the elemental symbol (for standard atoms) of the label (for pseudo-atoms).
static void explicitHydrogens(IAtomContainer mol)
Converts all the implicit hydrogens to explicit.
static Point3d getPoint3d(IAtom atm)
Return the 3D coordinates, if present.
Tool to generate random numbers and random decisions.
Definition: Randomizer.java:36
Defines how to define the scaffold vertex of a graph.
A chosen method for generation of new Candidates.
Definition: EAUtils.java:128
Possible chemical bond types an edge can represent.
Definition: Edge.java:305
Enum specifying to what extent the template's inner graph can be changed.
Definition: Template.java:104
FREE
Inner graphs are free to change within the confines of the required AttachmentPoints.
Definition: Template.java:109
FIXED
Inner graphs are effectively equivalent to the Fragment class, as no change in the inner structure is...
Definition: Template.java:116
FIXED_STRUCT
Inner graph keep the same structure, but the identify of vertices can change.
Definition: Template.java:124
The type of building block.
Definition: Vertex.java:86