$darkmode
DENOPTIM
GraphOperationsTest.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.assertTrue;
23
24import java.util.ArrayList;
25import java.util.Arrays;
26import java.util.Collection;
27import java.util.Comparator;
28import java.util.HashMap;
29import java.util.HashSet;
30import java.util.List;
31import java.util.Random;
32import java.util.Set;
33import java.util.function.BiFunction;
34import java.util.stream.Collectors;
35import java.util.stream.IntStream;
36import java.util.stream.Stream;
37
38import javax.vecmath.Point3d;
39
40import org.jgrapht.alg.util.Pair;
41import org.junit.jupiter.api.BeforeAll;
42import org.junit.jupiter.api.Test;
43import org.openscience.cdk.Atom;
44import org.openscience.cdk.DefaultChemObjectBuilder;
45import org.openscience.cdk.PseudoAtom;
46import org.openscience.cdk.interfaces.IAtom;
47import org.openscience.cdk.interfaces.IAtomContainer;
48import org.openscience.cdk.interfaces.IBond;
49import org.openscience.cdk.interfaces.IChemObjectBuilder;
50import org.openscience.cdk.layout.StructureDiagramGenerator;
51import org.openscience.cdk.silent.Bond;
52import org.openscience.cdk.smiles.SmilesParser;
53
54import denoptim.exception.DENOPTIMException;
55import denoptim.fragspace.FragmentSpace;
56import denoptim.fragspace.FragmentSpaceParameters;
57import denoptim.graph.APClass;
58import denoptim.graph.AttachmentPoint;
59import denoptim.graph.DGraph;
60import denoptim.graph.EmptyVertex;
61import denoptim.graph.Fragment;
62import denoptim.graph.GraphPattern;
63import denoptim.graph.Ring;
64import denoptim.graph.SymmetricVertexes;
65import denoptim.graph.Template;
66import denoptim.graph.Template.ContractLevel;
67import denoptim.graph.Vertex;
68import denoptim.graph.Vertex.BBType;
69import denoptim.graph.rings.RingClosingAttractor;
70import denoptim.graph.rings.RingClosureParameters;
71import denoptim.logging.Monitor;
72import denoptim.programs.RunTimeParameters.ParametersType;
73import denoptim.programs.denovo.GAParameters;
74import denoptim.utils.GraphUtils;
75import denoptim.utils.MoleculeUtils;
76import denoptim.utils.Randomizer;
77
84public class GraphOperationsTest {
85
86 private static APClass APCA, APCB, APCC, APCD;
87
88 IChemObjectBuilder chemBuilder = DefaultChemObjectBuilder.getInstance();
89 private final Random rng = new Random();
90 private static APClass DEFAULT_APCLASS;
91
92//------------------------------------------------------------------------------
93
94 @BeforeAll
95 static void setUpClass() {
96 try {
97 DEFAULT_APCLASS = APClass.make("norule:0");
98 } catch (DENOPTIMException e) {
99 e.printStackTrace();
100 }
101 }
102
103//------------------------------------------------------------------------------
104
105 @Test
106 public void testExtractPattern_singleRingSystem() throws Throwable
107 {
108 DGraph g = getThreeCycle();
109
110 List<DGraph> subgraphs = g.extractPattern(GraphPattern.RING);
111
112 assertEquals(1, subgraphs.size());
113 DGraph actual = subgraphs.get(0);
114 DGraph expected = g;
115
116 assertEquals(expected.getVertexCount(), actual.getVertexCount());
117 assertEquals(expected.getEdgeCount(), actual.getEdgeCount());
118 assertEquals(1, actual.getRingCount());
119
120 assertTrue(DGraph.compareGraphNodes(expected.getSourceVertex(),
121 expected, actual.getSourceVertex(), actual));
122 }
123
124//------------------------------------------------------------------------------
125
126 @Test
128 throws Throwable
129 {
130 DGraph g = getThreeCycle();
131 g.removeRing(g.getRings().get(0));
132 List<DGraph> subgraphs = g.extractPattern(GraphPattern.RING);
133
134 assertEquals(0, subgraphs.size());
135 }
136
137//------------------------------------------------------------------------------
138
139 @Test
140 public void testExtractPattern_fusedRings() throws Throwable
141 {
143
144 List<DGraph> subgraphs = testCase.g.extractPattern(GraphPattern.RING);
145
146 assertTrue(testCase.matchesExpected(subgraphs));
147 }
148
149//------------------------------------------------------------------------------
150
172 private ExtractPatternCase getFusedRings() throws Throwable
173 {
174 BiFunction<String, Boolean, Vertex> vertexSupplier =
175 (s, isRCV) -> {
176 int apCount = 0;
177 switch (s) {
178 case "Cl":
179 apCount = 1;
180 break;
181 case "O":
182 apCount = 2;
183 break;
184 case "N":
185 apCount = 3;
186 break;
187 case "C":
188 apCount = 4;
189 break;
190 }
191 return buildFragment(s, apCount, isRCV);
192 };
193
194 /* We label the vertices in order of top left to bottom right. */
195 List<Vertex> vertices = Stream.of(
196 new Pair<>("O", true), new Pair<>("C", false),
197 new Pair<>("Cl", false), new Pair<>("N",false),
198 new Pair<>("C", true), new Pair<>("N", true),
199 new Pair<>("C", true), new Pair<>("O", false),
200 new Pair<>("C", false), new Pair<>("O", true),
201 new Pair<>("C", true), new Pair<>("C", false),
202 new Pair<>("N", true)
203 ).map(p -> vertexSupplier.apply(p.getFirst(), p.getSecond()))
204 .collect(Collectors.toList());
205
206 /* Here we specify the connections between atoms. Previously
207 connected vertices are not connected twice. Chords are not connected. */
208 List<List<Integer>> edges = Arrays.asList(
209 Arrays.asList(1),
210 Arrays.asList(2, 3, 4),
211 Arrays.asList(),
212 Arrays.asList(5, 6),
213 Arrays.asList(),
214 Arrays.asList(),
215 Arrays.asList(7),
216 Arrays.asList(8),
217 Arrays.asList(9, 10),
218 Arrays.asList(),
219 Arrays.asList(11),
220 Arrays.asList(12)
221 );
222
223 DGraph g = null;
224 try
225 {
226 g = buildGraph(vertices, edges);
227 } catch (DENOPTIMException e)
228 {
229 e.printStackTrace();
230 }
232 DGraph.setScaffold(vertices.get(0));
233 addRings(vertices, g);
234 Set<DGraph> expectedSubgraphs = getExpectedSubgraphs(g);
235 return new ExtractPatternCase(g, 2, expectedSubgraphs);
236 }
237
238//------------------------------------------------------------------------------
239
240 private DGraph buildGraph(List<Vertex> vertices,
241 List<List<Integer>> edges)
242 throws DENOPTIMException {
243 DGraph g = new DGraph();
244 g.addVertex(vertices.get(0));
245 for (int i = 0; i < edges.size(); i++) {
246 Vertex srcVertex = vertices.get(i);
247 for (Integer adj : edges.get(i)) {
248 Vertex trgVertex = vertices.get(adj);
249
250 AttachmentPoint srcAP = srcVertex
252 .stream()
253 .filter(ap -> ap.getEdgeUser() == null)
254 .findFirst()
255 .get();
256 AttachmentPoint trgAP = trgVertex
258 .stream()
259 .filter(ap -> ap.getEdgeUser() == null)
260 .findFirst()
261 .get();
262
263 try {
264 g.appendVertexOnAP(srcAP, trgAP);
265 } catch (DENOPTIMException e) {
266 // Should not happen
267 e.printStackTrace();
268 }
269 }
270 }
271 return g;
272 }
273
274//------------------------------------------------------------------------------
275
276 private void addRings(List<Vertex> vertices, DGraph g) {
277 List<List<Vertex>> ringVertices = Stream.of(
278 Arrays.asList(0, 1, 3, 5),
279 Arrays.asList(4, 1, 3, 6),
280 Arrays.asList(6, 3, 5),
281 Arrays.asList(9, 8, 10),
282 Arrays.asList(10, 11, 12))
283 .map(indices -> indices
284 .stream()
285 .map(vertices::get)
286 .collect(Collectors.toList())
287 )
288 .collect(Collectors.toList());
289
290 for (List<Vertex> vs : ringVertices) {
291 Ring r = new Ring();
292 for (Vertex v : vs) {
293 r.addVertex(v);
294 }
295 g.addRing(r);
296 }
297 }
298
299//------------------------------------------------------------------------------
300
301 private Set<DGraph> getExpectedSubgraphs(DGraph graph) {
302 List<Set<Integer>> keepVertices = Stream.of(
303 Stream.of(0, 1, 3, 4, 5, 6),
304 Stream.of(8, 9, 10, 11, 12))
305 .map(indices -> indices.collect(Collectors.toSet()))
306 .collect(Collectors.toList());
307
308 List<DGraph> expectedSubgraphs = new ArrayList<>(2);
309 for (Set<Integer> keepVertex : keepVertices) {
310 DGraph expSubgraph = graph.clone();
311 List<Vertex> vertices = expSubgraph.getVertexList();
312 Set<Vertex> removeVertices = IntStream
313 .range(0, vertices.size())
314 .filter(i -> !keepVertex.contains(i))
315 .mapToObj(vertices::get)
316 .collect(Collectors.toSet());
317
318 for (Vertex removeVertex : removeVertices) {
319 expSubgraph.removeVertex(removeVertex);
320 }
321 expectedSubgraphs.add(expSubgraph);
322 }
323
324 return new HashSet<>(expectedSubgraphs);
325 }
326
327//------------------------------------------------------------------------------
328
329 private Vertex buildFragment(String elementSymbol, int apCount,
330 boolean isRCV)
331 {
332 try
333 {
334 IAtomContainer atomContainer = chemBuilder.newAtomContainer();
335 IAtom oxygen = chemBuilder.newAtom();
336 oxygen.setSymbol(elementSymbol);
337 atomContainer.addAtom(oxygen);
338
339 Fragment v = new Fragment(
340 GraphUtils.getUniqueVertexIndex(), atomContainer,
341 BBType.FRAGMENT, isRCV);
342 for (int i = 0; i < apCount; i++)
343 {
345 }
346 return v;
347 } catch (Throwable t)
348 {
349 return null;
350 }
351 }
352
353//------------------------------------------------------------------------------
354
355 private Point3d getRandomVector()
356 {
357 double precision = 10*10*10*10;
358 return new Point3d(
359 (double) (Math.round(rng.nextDouble() * precision)) / precision,
360 (double) (Math.round(rng.nextDouble() * precision)) / precision,
361 (double) (Math.round(rng.nextDouble() * precision)) / precision
362 );
363 }
364
365//------------------------------------------------------------------------------
366
374 {
375 EmptyVertex v1 = new EmptyVertex(0);
376 EmptyVertex rcv1 = new EmptyVertex(1, new ArrayList<>(),
377 new ArrayList<>(), true);
378 EmptyVertex rcv2 = new EmptyVertex(2, new ArrayList<>(),
379 new ArrayList<>(), true);
380
381 List<EmptyVertex> vertices = Arrays.asList(v1, rcv1, rcv2);
382 for (EmptyVertex v : vertices) {
383 v.setBuildingBlockType(BBType.FRAGMENT);
384 v.addAP();
385 }
386 // Need an additional AP on v1
387 v1.addAP();
388
389 DGraph g = new DGraph();
390 g.addVertex(v1);
391 g.appendVertexOnAP(v1.getAP(0), rcv1.getAP(0));
392 g.appendVertexOnAP(v1.getAP(1), rcv2.getAP(0));
393
394 Ring r = new Ring(new ArrayList<>(
395 Arrays.asList(rcv1, v1, rcv2)));
396 g.addRing(r);
397
399 return g;
400 }
401
402//------------------------------------------------------------------------------
403
404 private static final class ExtractPatternCase
405 {
406 final DGraph g;
407 final int expectedSize;
408 final Set<DGraph> expectedGraphs;
409 final Comparator<DGraph> graphComparator = (gA, gB) ->
410 gA.sameAs(gB, new StringBuilder()) ? 0 : -1;
411
413 Set<DGraph> expectedGraphs) {
414 this.g = g;
415 this.expectedSize = expectedSize;
416 this.expectedGraphs = expectedGraphs;
417 }
418
419 private boolean matchesExpected(Collection<DGraph> actuals) {
420 if (actuals.size() != expectedSize) {
421 return false;
422 }
423
424 Set<DGraph> unmatchedGraphs = new HashSet<>(expectedGraphs);
425 for (DGraph g : actuals)
426 {
427 boolean hasMatch = expectedGraphs
428 .stream()
429 .anyMatch(exp -> graphComparator.compare(g, exp) == 0);
430 if (hasMatch) {
431 unmatchedGraphs = unmatchedGraphs
432 .stream()
433 .filter(exp -> graphComparator.compare(g, exp) != 0)
434 .collect(Collectors.toSet());
435 } else {
436 return false;
437 }
438 }
439
440 // Check that no graphs are missing from actual
441 return unmatchedGraphs.size() == 0;
442 }
443 }
444
445//------------------------------------------------------------------------------
446
447 @Test
448 public void testLocateCompatibleXOverPoints() throws Exception
449 {
450 FragmentSpace fragSpace = prepare();
451 DGraph[] pair = getPairOfTestGraphs();
452 DGraph graphA = pair[0];
453 DGraph graphB = pair[1];
454
455 Template t1 = (Template) graphA.getVertexAtPosition(1);
456 Template t2 = (Template) graphB.getVertexAtPosition(1);
457 // Making some empty vertexes unique to enable swapping (otherwise they
458 // are seen as the same node and excluded from xover sites list)
460 String k = "Uniquefier";
462 v5A.setProperty(k, "123");
465 v3B.setProperty(k, "789");
466
467 // Prepare the input and expected output
468 List<ContractLevel> contracts = new ArrayList<ContractLevel>();
469 contracts.add(ContractLevel.FREE);
470 contracts.add(ContractLevel.FIXED_STRUCT);
471 contracts.add(ContractLevel.FIXED);
472
473 List<Integer> expectedNumberOfSites = new ArrayList<Integer>();
474 expectedNumberOfSites.add(17);
475 expectedNumberOfSites.add(12); // Only two allowed xovers
476 expectedNumberOfSites.add(10); // No crossover inside template
477
478 List<Set<String>> expectedInvariants = new ArrayList<Set<String>>();
479 // This code is generated by this very method. See below.
480 Set<String> invariantFREEContract = new HashSet<String>();
481 invariantFREEContract.add(""+GraphUtils.getLabel(graphA,1)+"_"+GraphUtils.getLabel(graphA,4)+"_"+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,3)+"_"+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,1)+"_"+GraphUtils.getLabel(graphB,5)+"_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
482 invariantFREEContract.add(""+GraphUtils.getLabel(graphA,1)+"_"+GraphUtils.getLabel(graphA,4)+"_"+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,1)+"_"+GraphUtils.getLabel(graphB,5)+"_"+GraphUtils.getLabel(graphB,2)+"_");
483 invariantFREEContract.add(""+GraphUtils.getLabel(graphA,1)+"_"+GraphUtils.getLabel(graphA,4)+"_"+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,3)+"_"+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
484 invariantFREEContract.add(""+GraphUtils.getLabel(graphA,1)+"_"+GraphUtils.getLabel(graphA,4)+"_"+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,2)+"_");
485 invariantFREEContract.add(""+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,3)+"_"+"@@@_"+GraphUtils.getLabel(graphB,1)+"_"+GraphUtils.getLabel(graphB,5)+"_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
486 invariantFREEContract.add(""+GraphUtils.getLabel(graphA,2)+"_"+"@@@_"+GraphUtils.getLabel(graphB,1)+"_"+GraphUtils.getLabel(graphB,5)+"_"+GraphUtils.getLabel(graphB,2)+"_");
487 invariantFREEContract.add(""+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,3)+"_"+"@@@_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
488 invariantFREEContract.add(""+GraphUtils.getLabel(graphA,3)+"_"+"@@@_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
489 invariantFREEContract.add(""+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,1)+"_"+GraphUtils.getLabel(graphB,5)+"_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
490 invariantFREEContract.add(""+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
491 invariantFREEContract.add(""+GraphUtils.getLabel(t1.getInnerGraph(),2)+"_"+GraphUtils.getLabel(t1.getInnerGraph(),3)+"_"+"@@@_"+GraphUtils.getLabel(t2.getInnerGraph(),1)+"_"+GraphUtils.getLabel(t2.getInnerGraph(),2)+"_"+GraphUtils.getLabel(t2.getInnerGraph(),3)+"_");
492 invariantFREEContract.add(""+GraphUtils.getLabel(t1.getInnerGraph(),2)+"_"+"@@@_"+GraphUtils.getLabel(t2.getInnerGraph(),1)+"_"+GraphUtils.getLabel(t2.getInnerGraph(),2)+"_");
493 invariantFREEContract.add(""+GraphUtils.getLabel(t1.getInnerGraph(),2)+"_"+GraphUtils.getLabel(t1.getInnerGraph(),3)+"_"+"@@@_"+GraphUtils.getLabel(t2.getInnerGraph(),2)+"_"+GraphUtils.getLabel(t2.getInnerGraph(),3)+"_");
494 invariantFREEContract.add(""+GraphUtils.getLabel(t1.getInnerGraph(),2)+"_"+"@@@_"+GraphUtils.getLabel(t2.getInnerGraph(),2)+"_");
495 invariantFREEContract.add(""+GraphUtils.getLabel(t1.getInnerGraph(),3)+"_"+"@@@_"+GraphUtils.getLabel(t2.getInnerGraph(),3)+"_");
496 invariantFREEContract.add(""+GraphUtils.getLabel(t1.getInnerGraph(),4)+"_"+GraphUtils.getLabel(t1.getInnerGraph(),5)+"_"+"@@@_"+GraphUtils.getLabel(t2.getInnerGraph(),3)+"_");
497 invariantFREEContract.add(""+GraphUtils.getLabel(t1.getInnerGraph(),5)+"_"+"@@@_"+GraphUtils.getLabel(t2.getInnerGraph(),3)+"_");
498 expectedInvariants.add(invariantFREEContract);
499 Set<String> invariantFIXED_STRUCTContract = new HashSet<String>();
500 invariantFIXED_STRUCTContract.add(""+GraphUtils.getLabel(graphA,1)+"_"+GraphUtils.getLabel(graphA,4)+"_"+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,3)+"_"+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,1)+"_"+GraphUtils.getLabel(graphB,5)+"_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
501 invariantFIXED_STRUCTContract.add(""+GraphUtils.getLabel(graphA,1)+"_"+GraphUtils.getLabel(graphA,4)+"_"+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,1)+"_"+GraphUtils.getLabel(graphB,5)+"_"+GraphUtils.getLabel(graphB,2)+"_");
502 invariantFIXED_STRUCTContract.add(""+GraphUtils.getLabel(graphA,1)+"_"+GraphUtils.getLabel(graphA,4)+"_"+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,3)+"_"+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
503 invariantFIXED_STRUCTContract.add(""+GraphUtils.getLabel(graphA,1)+"_"+GraphUtils.getLabel(graphA,4)+"_"+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,2)+"_");
504 invariantFIXED_STRUCTContract.add(""+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,3)+"_"+"@@@_"+GraphUtils.getLabel(graphB,1)+"_"+GraphUtils.getLabel(graphB,5)+"_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
505 invariantFIXED_STRUCTContract.add(""+GraphUtils.getLabel(graphA,2)+"_"+"@@@_"+GraphUtils.getLabel(graphB,1)+"_"+GraphUtils.getLabel(graphB,5)+"_"+GraphUtils.getLabel(graphB,2)+"_");
506 invariantFIXED_STRUCTContract.add(""+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,3)+"_"+"@@@_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
507 invariantFIXED_STRUCTContract.add(""+GraphUtils.getLabel(graphA,3)+"_"+"@@@_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
508 invariantFIXED_STRUCTContract.add(""+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,1)+"_"+GraphUtils.getLabel(graphB,5)+"_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
509 invariantFIXED_STRUCTContract.add(""+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
510 invariantFIXED_STRUCTContract.add(""+GraphUtils.getLabel(t1.getInnerGraph(),3)+"_"+"@@@_"+GraphUtils.getLabel(t2.getInnerGraph(),3)+"_");
511 invariantFIXED_STRUCTContract.add(""+GraphUtils.getLabel(t1.getInnerGraph(),5)+"_"+"@@@_"+GraphUtils.getLabel(t2.getInnerGraph(),3)+"_");
512 expectedInvariants.add(invariantFIXED_STRUCTContract);
513 Set<String> invariantFIXEDContract = new HashSet<String>();
514 invariantFIXEDContract.add(""+GraphUtils.getLabel(graphA,1)+"_"+GraphUtils.getLabel(graphA,4)+"_"+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,3)+"_"+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,1)+"_"+GraphUtils.getLabel(graphB,5)+"_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
515 invariantFIXEDContract.add(""+GraphUtils.getLabel(graphA,1)+"_"+GraphUtils.getLabel(graphA,4)+"_"+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,1)+"_"+GraphUtils.getLabel(graphB,5)+"_"+GraphUtils.getLabel(graphB,2)+"_");
516 invariantFIXEDContract.add(""+GraphUtils.getLabel(graphA,1)+"_"+GraphUtils.getLabel(graphA,4)+"_"+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,3)+"_"+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
517 invariantFIXEDContract.add(""+GraphUtils.getLabel(graphA,1)+"_"+GraphUtils.getLabel(graphA,4)+"_"+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,2)+"_");
518 invariantFIXEDContract.add(""+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,3)+"_"+"@@@_"+GraphUtils.getLabel(graphB,1)+"_"+GraphUtils.getLabel(graphB,5)+"_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
519 invariantFIXEDContract.add(""+GraphUtils.getLabel(graphA,2)+"_"+"@@@_"+GraphUtils.getLabel(graphB,1)+"_"+GraphUtils.getLabel(graphB,5)+"_"+GraphUtils.getLabel(graphB,2)+"_");
520 invariantFIXEDContract.add(""+GraphUtils.getLabel(graphA,2)+"_"+GraphUtils.getLabel(graphA,3)+"_"+"@@@_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
521 invariantFIXEDContract.add(""+GraphUtils.getLabel(graphA,3)+"_"+"@@@_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
522 invariantFIXEDContract.add(""+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,1)+"_"+GraphUtils.getLabel(graphB,5)+"_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
523 invariantFIXEDContract.add(""+GraphUtils.getLabel(graphA,5)+"_"+"@@@_"+GraphUtils.getLabel(graphB,2)+"_"+GraphUtils.getLabel(graphB,3)+"_"+GraphUtils.getLabel(graphB,4)+"_");
524 expectedInvariants.add(invariantFIXEDContract);
525
526 for (int i=0; i<contracts.size(); i++)
527 {
528 t1.setContractLevel(contracts.get(i));
529 t2.setContractLevel(contracts.get(i));
530
531 List<XoverSite> xoverSites =
533 fragSpace, 100, 100,
534 100000, 10, 250);
535
536 assertEquals(expectedNumberOfSites.get(i), xoverSites.size());
537
538 // NB: this is code that is unlocked only in development phase to
539 // generate the code that defined the expected invariant.
540 // Here, we exploit the fact that every vertex has a unique label as a
541 // property and the combination of sites generates an invariant.
542 // To generate this labels programmatically the following code is used
543 // but only after having checked manually.
544 boolean writeCode = false; //NB: make this true to generate the code!
545 if (writeCode)
546 {
547 String varName = "invariant" + contracts.get(i) + "Contract";
548 System.out.println("Set<String> " + varName + " = new HashSet<String>();");
549 for (XoverSite x : xoverSites)
550 {
551 String s = "\"\"";
552 for (Vertex v : x.getA())
553 {
554 String g = "";
555 if (v.getGraphOwner()==graphA)
556 g = "graphA";
557 else if (v.getGraphOwner()==graphB)
558 g = "graphB";
559 else if (v.getGraphOwner()==t1.getInnerGraph())
560 g = "t1.getInnerGraph()";
561 else if (v.getGraphOwner()==t2.getInnerGraph())
562 g = "t2.getInnerGraph()";
563 else
564 g = "noGraph";
565
566 s = s + "+GraphUtils.getLabel("+g+","+v.getGraphOwner().indexOf(v)+")+\"_\"";
567 }
568 s = s + "+\"@@@_\"";
569 for (Vertex v : x.getB())
570 {
571 String g = "";
572 if (v.getGraphOwner()==graphA)
573 g = "graphA";
574 else if (v.getGraphOwner()==graphB)
575 g = "graphB";
576 else if (v.getGraphOwner()==t1.getInnerGraph())
577 g = "t1.getInnerGraph()";
578 else if (v.getGraphOwner()==t2.getInnerGraph())
579 g = "t2.getInnerGraph()";
580 else
581 g = "noGraph";
582
583 s = s + "+GraphUtils.getLabel("+g+","+v.getGraphOwner().indexOf(v)+")+\"_\"";
584 }
585 System.out.println(varName + ".add("+s+");");
586 }
587 System.out.println("expectedInvariants.add("+varName+");");
588 }
589
590 for (XoverSite site : xoverSites)
591 {
592 String label = "";
593 for (Vertex v : site.getA())
594 {
595 label = label + GraphUtils.getLabel(v.getGraphOwner(),
596 v.getGraphOwner().indexOf(v)) + "_";
597 }
598 label = label + "@@@_";
599 for (Vertex v : site.getB())
600 {
601 label = label + GraphUtils.getLabel(v.getGraphOwner(),
602 v.getGraphOwner().indexOf(v)) + "_";
603 }
604 assertTrue(expectedInvariants.get(i).contains(label),
605 "For contract " + i + " (" + contracts.get(i)
606 + ") - Missing label: "+label);
607 }
608 }
609 }
610
611//------------------------------------------------------------------------------
612
645 private DGraph[] getPairOfTestGraphs() throws Exception
646 {
647 prepare();
648
649 // Prepare special building block: template T1
650 EmptyVertex v0 = new EmptyVertex(0);
651 v0.addAP(APCA);
652 v0.addAP(APCA);
653 v0.setProperty("Label", "tv0");
654
655 EmptyVertex v1 = new EmptyVertex(1);
656 v1.addAP(APCA);
657 v1.addAP(APCA);
658 v1.addAP(APCB);
659 v1.addAP(APCC);
660 v1.setProperty("Label", "tv1");
661
662 EmptyVertex v2 = new EmptyVertex(2);
663 v2.addAP(APCA);
664 v2.addAP(APCC);
665 v2.setProperty("Label", "tv2");
666
667 EmptyVertex v3 = new EmptyVertex(3);
668 v3.addAP(APCA);
669 v3.addAP(APCA);
670 v3.setProperty("Label", "tv3");
671
672 EmptyVertex v4 = new EmptyVertex(4);
673 v4.addAP(APCA);
674 v4.addAP(APCA);
675 v4.setProperty("Label", "tv4");
676
677 EmptyVertex v5 = new EmptyVertex(5);
678 v5.addAP(APCA);
679 v5.addAP(APCA);
680 v5.setProperty("Label", "tv5");
681
682 DGraph g = new DGraph();
683 g.addVertex(v0);
684 g.setGraphId(-1);
685 g.appendVertexOnAP(v0.getAP(0), v1.getAP(0));
686 g.appendVertexOnAP(v1.getAP(2), v2.getAP(1));
687 g.appendVertexOnAP(v2.getAP(0), v3.getAP(0));
688 g.appendVertexOnAP(v1.getAP(1), v4.getAP(1));
689 g.appendVertexOnAP(v4.getAP(0), v5.getAP(1));
690
691 Template t1 = new Template(BBType.NONE);
692 t1.setInnerGraph(g);
693 t1.setProperty("Label", "t1");
695
696 // Assemble the first graph: graphA
697
698 EmptyVertex m1 = new EmptyVertex(101);
699 m1.addAP(APCA);
700 m1.setProperty("Label", "m101");
701
702 EmptyVertex m2 = new EmptyVertex(102);
703 m2.addAP(APCA);
704 m2.addAP(APCB);
705 m2.setProperty("Label", "m102");
706
707 EmptyVertex m3 = new EmptyVertex(103);
708 m3.addAP(APCB);
709 m3.setProperty("Label", "m103");
710
711 EmptyVertex m4 = new EmptyVertex(104);
712 m4.addAP(APCC);
713 m4.setProperty("Label", "m104");
714
715 EmptyVertex m5 = new EmptyVertex(105);
716 m5.addAP(APCA);
717 m5.setProperty("Label", "m105");
718
719 DGraph graphA = new DGraph();
720 graphA.addVertex(m1);
721 graphA.appendVertexOnAP(m1.getAP(0), t1.getAP(0));
722 graphA.appendVertexOnAP(t1.getAP(2), m2.getAP(0));
723 graphA.appendVertexOnAP(m2.getAP(1), m3.getAP(0));
724 graphA.appendVertexOnAP(t1.getAP(1), m4.getAP(0));
725 graphA.appendVertexOnAP(t1.getAP(3), m5.getAP(0));
726
727 graphA.setGraphId(11111);
728
729 //Prepare special building block: template T2
730 EmptyVertex w1 = new EmptyVertex(11);
731 w1.addAP(APCA);
732 w1.addAP(APCB);
733 w1.addAP(APCC);
734 w1.setProperty("Label", "tw11");
735
736 EmptyVertex w2 = new EmptyVertex(12);
737 w2.addAP(APCB);
738 w2.addAP(APCC);
739 w2.setProperty("Label", "tw12");
740
741 EmptyVertex w3 = new EmptyVertex(13);
742 w3.addAP(APCA);
743 w3.addAP(APCB);
744 w3.setProperty("Label", "tw13");
745
746 EmptyVertex w4 = new EmptyVertex(14);
747 w4.addAP(APCA);
748 w4.addAP(APCA);
749 w4.setProperty("Label", "tw14");
750
751 DGraph g2 = new DGraph();
752 g2.addVertex(w1);
753 g2.appendVertexOnAP(w1.getAP(1), w2.getAP(1));
754 g2.appendVertexOnAP(w2.getAP(0), w3.getAP(1));
755 g2.appendVertexOnAP(w3.getAP(0), w4.getAP(0));
756 g2.setGraphId(-2);
757
758 Template t2 = new Template(BBType.NONE);
759 t2.setInnerGraph(g2);
760 t2.setProperty("Label", "t2");
762
763 // Assemble the second graph: graphB
764
765 EmptyVertex f1 = new EmptyVertex(1001);
766 f1.addAP(APCA);
767 f1.setProperty("Label", "f1001");
768
769 EmptyVertex f2 = new EmptyVertex(1002);
770 f2.addAP(APCA);
771 f2.addAP(APCB);
772 f2.setProperty("Label", "f1002");
773
774 EmptyVertex f3 = new EmptyVertex(1003);
775 f3.addAP(APCB);
776 f3.addAP(APCC);
777 f3.setProperty("Label", "f1003");
778
779 EmptyVertex f4 = new EmptyVertex(1004);
780 f4.addAP(APCC);
781 f4.setProperty("Label", "f1004");
782
783 EmptyVertex f5 = new EmptyVertex(1005);
784 f5.addAP(APCC);
785 f5.setProperty("Label", "f1005");
786
787 DGraph graphB = new DGraph();
788 graphB.addVertex(f1);
789 graphB.appendVertexOnAP(f1.getAP(0), t2.getAP(0));
790 graphB.appendVertexOnAP(t2.getAP(2), f2.getAP(0));
791 graphB.appendVertexOnAP(f2.getAP(1), f3.getAP(0));
792 graphB.appendVertexOnAP(f3.getAP(1), f4.getAP(0));
793 graphB.appendVertexOnAP(t2.getAP(1), f5.getAP(0));
794 graphB.setGraphId(22222);
795
796 DGraph[] pair = new DGraph[2];
797 pair[0] = graphA;
798 pair[1] = graphB;
799
800 return pair;
801 }
802
803//------------------------------------------------------------------------------
804
820 private FragmentSpace prepare() throws Exception
821 {
822 // Prepare APClass compatibility rules
823 APCA = APClass.make("A", 0);
824 APCB = APClass.make("B", 0);
825 APCC = APClass.make("C", 0);
826 APCD = APClass.make("D", 0);
827
828 HashMap<APClass,ArrayList<APClass>> cpMap =
829 new HashMap<APClass,ArrayList<APClass>>();
830 ArrayList<APClass> lstA = new ArrayList<APClass>();
831 lstA.add(APCA);
832 cpMap.put(APCA, lstA);
833 ArrayList<APClass> lstB = new ArrayList<APClass>();
834 lstB.add(APCB);
835 lstB.add(APCC);
836 cpMap.put(APCB, lstB);
837 ArrayList<APClass> lstC = new ArrayList<APClass>();
838 lstC.add(APCC);
839 cpMap.put(APCC, lstC);
840 ArrayList<APClass> lstD = new ArrayList<APClass>();
841 lstD.add(APCD);
842 cpMap.put(APCD, lstD);
843
844 HashMap<APClass,APClass> capMap = new HashMap<APClass,APClass>();
845 HashSet<APClass> forbEnds = new HashSet<APClass>();
846
848 FragmentSpace fs = new FragmentSpace(fsp,
849 new ArrayList<Vertex>(),
850 new ArrayList<Vertex>(),
851 new ArrayList<Vertex>(),
852 cpMap, capMap, forbEnds, cpMap);
854
855 return fs;
856 }
857
858//------------------------------------------------------------------------------
859
860 @Test
861 public void testAddRing() throws Exception
862 {
863 /* This is the graph we work with
864 *
865 * * * * RCV_M
866 * | | | |
867 * RCV_P--[O]----[C]--[C]--[C]--[C]--[C]----[N]--RCV_M
868 * vO vC vC2 vC3 vC4 vC5 vN
869 *
870 */
871
872 APClass apc = APClass.make("A", 0);
873
874 IAtomContainer iacO = chemBuilder.newAtomContainer();
875 IAtom aO = new Atom("O",new Point3d(0,0,0));
876 iacO.addAtom(aO);
877 Fragment vO = new Fragment(0, iacO,BBType.FRAGMENT);
878 vO.addAP(0, new Point3d(0,-1,0), apc);
879 vO.addAP(0, new Point3d(2,0,0), apc);
880 vO.addAP(0, new Point3d(0,1,0), apc);
881
882 IAtomContainer iacC = chemBuilder.newAtomContainer();
883 IAtom aC = new Atom("C",new Point3d(0,0,0));
884 iacC.addAtom(aC);
885 Fragment vC = new Fragment(1, iacC,BBType.FRAGMENT);
886 vC.addAP(0, new Point3d(0,-1,0), apc);
887 vC.addAP(0, new Point3d(2,0,0), apc);
888 vC.addAP(0, new Point3d(0,1,0), apc);
889
890 IAtomContainer iacCd = chemBuilder.newAtomContainer();
891 IAtom aCd = new Atom("C",new Point3d(0,0,0));
892 iacCd.addAtom(aCd);
893 Fragment vC2 = new Fragment(2, iacCd,BBType.FRAGMENT);
894 vC2.addAP(0, new Point3d(0,-1,0), apc);
895 vC2.addAP(0, new Point3d(0,1,0), apc);
896
897 Fragment vC3 = vC2.clone();
898 vC3.setVertexId(33);
899
900 Fragment vC4 = vC2.clone();
901 vC4.setVertexId(34);
902
903 Fragment vC5 = vC.clone();
904 vC5.setVertexId(3);
905
906 IAtomContainer iacN = chemBuilder.newAtomContainer();
907 IAtom aN = new Atom("N",new Point3d(0,0,0));
908 iacN.addAtom(aN);
909 Fragment vN = new Fragment(4, iacN,BBType.FRAGMENT);
910 vN.addAP(0, new Point3d(0,-1,0), apc);
911 vN.addAP(0, new Point3d(2,0,0), apc);
912 vN.addAP(0, new Point3d(0,1,0), apc);
913
914 APClass atMinus = APClass.RCACLASSMINUS;
915
916 IAtomContainer iacD = chemBuilder.newAtomContainer();
917 iacD.addAtom(new PseudoAtom(RingClosingAttractor.RCALABELPERAPCLASS.get(atMinus),
918 new Point3d(0,0,0)));
919 Fragment rcvM = new Fragment(6, iacD,BBType.FRAGMENT);
920 rcvM.addAP(0, new Point3d(-1,0,0), atMinus);
921 rcvM.setAsRCV(true);
922
923 Fragment rcvM2 = rcvM.clone();
924 rcvM2.setVertexId(7);
925
927
928 IAtomContainer iacE = chemBuilder.newAtomContainer();
929 iacE.addAtom(new PseudoAtom(RingClosingAttractor.RCALABELPERAPCLASS.get(atPlus),
930 new Point3d(0,0,0)));
931 Fragment rcvP = new Fragment(8, iacE,BBType.FRAGMENT);
932 rcvP.addAP(0, new Point3d(-1,0,0), atPlus);
933 rcvP.setAsRCV(true);
934
935 DGraph graph = new DGraph();
936 graph.addVertex(vC);
937 graph.appendVertexOnAP(vC.getAP(0), vO.getAP(2));
938 graph.appendVertexOnAP(vO.getAP(1), rcvP.getAP(0));
939 graph.appendVertexOnAP(vC.getAP(2), vC2.getAP(1));
940 graph.appendVertexOnAP(vC2.getAP(0), vC3.getAP(0));
941 graph.appendVertexOnAP(vC3.getAP(1), vC4.getAP(0));
942 graph.appendVertexOnAP(vC4.getAP(1), vC5.getAP(0));
943 graph.appendVertexOnAP(vC5.getAP(2), vN.getAP(0));
944 graph.appendVertexOnAP(vN.getAP(1), rcvM.getAP(0));
945 graph.appendVertexOnAP(vN.getAP(2), rcvM2.getAP(0));
946
947 // Prepare environment to run graph operation. First, a monitor of events
948 Monitor mnt = new Monitor();
949
950 // Then, a fragment space that allows ring closures
951 HashMap<APClass,ArrayList<APClass>> cpMap =
952 new HashMap<APClass,ArrayList<APClass>>();
953 ArrayList<APClass> lstA = new ArrayList<APClass>();
954 lstA.add(apc);
955 cpMap.put(apc, lstA);
957 FragmentSpace fs = new FragmentSpace(fsp,
958 new ArrayList<Vertex>(),
959 new ArrayList<Vertex>(),
960 new ArrayList<Vertex>(),
961 cpMap,
962 new HashMap<APClass,APClass>(),
963 new HashSet<APClass>(),
964 cpMap);
966
967 // Then, settings of ring-closing machinery
969 List<Integer> biases = new ArrayList<Integer>();
970 for (int i=0; i<rcParams.getMaxRingSize(); i++)
971 {
972 biases.add(0); // 0 means ring-closure not allowed
973 }
974 biases.set(5, 1);
975 rcParams.setRingSizeBias(biases);
976
977 // Then, some GA-parameters
978 GAParameters gaParams = new GAParameters();
979 gaParams.setParameters(rcParams);
980
981 // All ready, do the ring-adding mutation
982 assertEquals(0, graph.getRingCount());
983 GraphOperations.addRing(vC5, mnt, true, fs, gaParams);
984 assertEquals(1, graph.getRingCount());
985 }
986
987//------------------------------------------------------------------------------
988
989 @Test
990 public void testAddFusedRings() throws Exception
991 {
992 APClass apcA = APClass.make("apcA:1");
993 APClass hyd = APClass.make("hyd:1");
994
995 // Prepare environment to run graph operation. First, a monitor of events
996 Monitor mnt = new Monitor();
997
998 ArrayList<Vertex> libFrags = new ArrayList<Vertex>();
999
1000 APClass APC4EL = APClass.make("4el:0");
1001 Fragment bridge4el = new Fragment(4);
1002 IAtom a4_0 = new Atom("Si", new Point3d());
1003 IAtom a4_1 = new Atom("Si", new Point3d());
1004 IAtom a4_2 = new Atom("Si", new Point3d());
1005 IAtom a4_3 = new Atom("Si", new Point3d());
1006 bridge4el.addAtom(a4_0);
1007 bridge4el.addAtom(a4_1);
1008 bridge4el.addAtom(a4_2);
1009 bridge4el.addAtom(a4_3);
1010 bridge4el.addBond(new Bond(a4_0, a4_1, IBond.Order.DOUBLE));
1011 bridge4el.addBond(new Bond(a4_1, a4_2, IBond.Order.SINGLE));
1012 bridge4el.addBond(new Bond(a4_2, a4_3, IBond.Order.DOUBLE));
1013 bridge4el.addAP(0, new Point3d(), APC4EL);
1014 bridge4el.addAP(3, new Point3d(), APC4EL);
1015 bridge4el.addAP(0, new Point3d(), apcA);
1016 bridge4el.addAP(1, new Point3d(), apcA);
1017 bridge4el.addAP(2, new Point3d(), apcA);
1018 bridge4el.addAP(3, new Point3d(), apcA);
1019 libFrags.add(bridge4el);
1020
1021 Fragment bridge4el3Atm = new Fragment(2);
1022 IAtom a3_0 = new Atom("Ge", new Point3d());
1023 IAtom a3_1 = new Atom("N", new Point3d());
1024 IAtom a3_2 = new Atom("Ge", new Point3d());
1025 bridge4el3Atm.addAtom(a3_0);
1026 bridge4el3Atm.addAtom(a3_1);
1027 bridge4el3Atm.addAtom(a3_2);
1028 bridge4el3Atm.addBond(new Bond(a3_0, a3_1, IBond.Order.SINGLE));
1029 bridge4el3Atm.addBond(new Bond(a3_1, a3_2, IBond.Order.SINGLE));
1030 bridge4el3Atm.addAP(0, new Point3d(), APC4EL);
1031 bridge4el3Atm.addAP(2, new Point3d(), APC4EL);
1032 bridge4el3Atm.addAP(0, new Point3d(), apcA);
1033 bridge4el3Atm.addAP(2, new Point3d(), apcA);
1034 libFrags.add(bridge4el3Atm);
1035
1036 APClass APC1EL = APClass.make("1el:0");
1037 Fragment bridge1el = new Fragment(1);
1038 IAtom a1_0 = new Atom("N", new Point3d());
1039 bridge1el.addAtom(a1_0);
1040 bridge1el.addAP(0, new Point3d(), APC1EL);
1041 bridge1el.addAP(0, new Point3d(), APC1EL);
1042 libFrags.add(bridge1el);
1043
1044 HashMap<APClass,APClass> cappingRules = new HashMap<APClass,APClass>();
1045 cappingRules.put(apcA, hyd);
1046
1047 ArrayList<Vertex> cappingGroups = new ArrayList<Vertex>();
1048 Fragment capH = new Fragment();
1049 capH.addAtom(new Atom("H", new Point3d()));
1050 capH.addAP(0, new Point3d(1.0, 0, 0), hyd);
1051 cappingGroups.add(capH);
1052
1053 HashMap<APClass,ArrayList<APClass>> rcCpMap =
1054 new HashMap<APClass,ArrayList<APClass>>();
1055 rcCpMap.put(apcA, new ArrayList<APClass>(Arrays.asList(APC4EL)));
1056
1058 FragmentSpace fs = new FragmentSpace(fsp,
1059 new ArrayList<Vertex>(),
1060 libFrags,
1061 cappingGroups,
1062 new HashMap<APClass,ArrayList<APClass>>(),
1063 cappingRules,
1064 new HashSet<APClass>(),
1065 rcCpMap);
1066 //NB: a non-empty rcCpMap is enough to trigger the automated recognition
1067 // that we are within the class-based approach.
1068
1069 // Then, some GA-parameters
1070 GAParameters gaParams = new GAParameters();
1071 gaParams.setParameters(new RingClosureParameters());
1072 gaParams.setRandomizer(new Randomizer(1L));
1073
1074 //
1075 // Add multiple rings
1076 //
1077
1078 SmilesParser parser = new SmilesParser(chemBuilder);
1079 IAtomContainer benzene = parser.parseSmiles("c1ccccc1");
1081 StructureDiagramGenerator sdg = new StructureDiagramGenerator();
1082 sdg.generateCoordinates(benzene);
1083 Fragment benzeneScaffold = new Fragment(benzene, BBType.FRAGMENT);
1084 for (int i= 0; i<6; i++)
1085 {
1086 EAUtilsTest.replaceHatomWithAP(benzeneScaffold, i, apcA);
1087 }
1088 benzeneScaffold.setVertexId(123);
1089 DGraph graph = new DGraph();
1090 graph.addVertex(benzeneScaffold);
1091
1092 assertEquals(0, graph.getRingCount());
1093 GraphOperations.addFusedRing(benzeneScaffold, mnt, true, fs, gaParams);
1094
1095 assertEquals(3, graph.getRingCount());
1096 int numSiAtoms = 0;
1097 for (Vertex v : graph.getVertexList())
1098 {
1099 numSiAtoms = numSiAtoms + MoleculeUtils.countAtomsOfElement(
1100 v.getIAtomContainer(), "Si");
1101 }
1102 assertEquals(12, numSiAtoms);
1103
1104 //
1105 // Adding one atom to close 6-member aromatic ring
1106 //
1107
1108 IAtomContainer arom = parser.parseSmiles("c1cccc(c12)ccc(c23)ccc(c34)cccc4");
1110 sdg.generateCoordinates(arom);
1111 Fragment frag = new Fragment(arom, BBType.FRAGMENT);
1112 EAUtilsTest.replaceHatomWithAP(frag, 0, apcA);
1113 EAUtilsTest.replaceHatomWithAP(frag, 17, apcA);
1114 frag.setVertexId(123);
1115 graph = new DGraph();
1116 graph.addVertex(frag);
1117
1118 assertEquals(0, graph.getRingCount());
1119 GraphOperations.addFusedRing(frag, mnt, true, fs, gaParams);
1120 assertEquals(1, graph.getRingCount());
1121
1122 //
1123 // Adhering to ring-size biases
1124 //
1125
1126 IAtomContainer arom2 = parser.parseSmiles("c1cccc(c12)ccc(c23)ccc(c34)cccc4");
1128 sdg.generateCoordinates(arom2);
1129 Fragment frag2 = new Fragment(arom2, BBType.FRAGMENT);
1130 // These two lead to a 5atm5el site, which can generate a 6atom ring
1131 EAUtilsTest.replaceHatomWithAP(frag2, 0, apcA);
1132 EAUtilsTest.replaceHatomWithAP(frag2, 17, apcA);
1133 // these lead to a 2atm2el site that can lead to 6- or 5-membered ring
1134 EAUtilsTest.replaceHatomWithAP(frag2, 14, apcA);
1135 EAUtilsTest.replaceHatomWithAP(frag2, 15, apcA);
1136 frag2.setVertexId(1);
1137 graph = new DGraph();
1138 graph.addVertex(frag2);
1141 // 0,1,2,3,4,5,6,7
1142 rcParams.setRingSizeBias(Arrays.asList(0,0,0,0,0,1,0,0));
1143
1144 assertEquals(0, graph.getRingCount());
1145 GraphOperations.addFusedRing(frag2, mnt, true, fs, gaParams);
1146 assertEquals(1, graph.getRingCount());
1147 numSiAtoms = 0;
1148 int numNAtoms = 0;
1149 int numGeAtoms = 0;
1150 for (Vertex v : graph.getVertexList())
1151 {
1152 numSiAtoms = numSiAtoms + MoleculeUtils.countAtomsOfElement(
1153 v.getIAtomContainer(), "Si");
1154 numNAtoms = numNAtoms + MoleculeUtils.countAtomsOfElement(
1155 v.getIAtomContainer(), "N");
1156 numGeAtoms = numGeAtoms + MoleculeUtils.countAtomsOfElement(
1157 v.getIAtomContainer(), "Ge");
1158 }
1159 assertEquals(0, numSiAtoms);
1160 assertEquals(1, numNAtoms);
1161 assertEquals(2, numGeAtoms);
1162 }
1163
1164//------------------------------------------------------------------------------
1165
1166 /*
1167 * Here we test whether the method detects that extension should be done in
1168 * all symmetric location, including APs belonging to the same vertex and
1169 * outside of it.
1170 */
1171
1172 @Test
1173 public void testExtendGraph() throws Exception
1174 {
1175 APClass APCA = APClass.make("A", 0);
1176 APClass APCB = APClass.make("B", 0);
1177
1178 Fragment vC1 = new Fragment();
1179 Atom ac1 = new Atom("C", new Point3d());
1180 vC1.addAtom(ac1);
1181 vC1.addAP(0, APCB, new Point3d(1.1, 0.0, 0.0));
1182 vC1.addAP(0, APCB, new Point3d(1.1, 1.0, 0.0));
1183 vC1.addAP(0, APCB, new Point3d(1.1, 1.0, 2.0));
1184 vC1.addAP(0, APCB, new Point3d(1.1,-1.0, 2.0));
1185
1186 Fragment vC3 = new Fragment();
1187 Atom ac31 = new Atom("C", new Point3d(0.0, 2.0, 0.0));
1188 Atom ac32 = new Atom("C", new Point3d(0.0, 0.0, 2.0));
1189 Atom ac33 = new Atom("C", new Point3d(0.0, 0.0, 0.0));
1190 vC3.addAtom(ac31);
1191 vC3.addAtom(ac32);
1192 vC3.addAtom(ac33);
1193 vC3.addBond(new Bond(ac31, ac32));
1194 vC3.addBond(new Bond(ac32, ac33));
1195 vC3.addBond(new Bond(ac33, ac31));
1196 vC3.addAP(0, APCA, new Point3d(0.0, 2.0, -1.0));
1197 vC3.addAP(1, APCA, new Point3d(-1.0,-1.0, 3.0));
1198 vC3.addAP(1, APCA, new Point3d(1.0, -1.0, 3.0));
1199 vC3.addAP(2, APCA, new Point3d(-1.0,-1.0, 1.0));
1200 vC3.addAP(2, APCA, new Point3d(1.0, -1.0, 1.0));
1201
1202 Fragment vCl = new Fragment();
1203 Atom acl = new Atom("Cl", new Point3d());
1204 vCl.addAtom(acl);
1205 vCl.addAP(0, APCB, new Point3d(1.1, 0.0, 0.0));
1206
1207 Fragment vN = new Fragment();
1208 Atom aN = new Atom("N", new Point3d());
1209 vN.addAtom(aN);
1210 vN.addAP(0, APCB, new Point3d(1.1, 0.0, 0.0));
1211 vN.addAP(0, APCA, new Point3d(1.1, 1.0, 0.0));
1212 vN.addAP(0, APCB, new Point3d(1.1, 1.0, 2.0));
1213
1214 ArrayList<Vertex> fragments = new ArrayList<Vertex>();
1215 fragments.add(vC1);
1216 fragments.add(vC3);
1217 fragments.add(vCl);
1218 fragments.add(vN);
1219
1220 // Use clones of the vertexes to simulate the construction from BBSpace
1221 Vertex cvC1a = vC1.clone();
1222 cvC1a.setVertexId(1);
1223 Vertex cvC1b = vC1.clone();
1224 cvC1b.setVertexId(2);
1225 Vertex cvC3a = vC3.clone();
1226 cvC3a.setVertexId(3);
1227 Vertex cvC3b = vC3.clone();
1228 cvC3b.setVertexId(4);
1229 Vertex cvN = vN.clone();
1230 cvN.setVertexId(0);
1231
1232 /* This is the graph we work with ('*' is a free AP)
1233 *
1234 * * *
1235 * / /
1236 * *-C---C-*
1237 * \ /
1238 * C
1239 * / *
1240 * / /
1241 * N(root)-----C-*
1242 * \ \
1243 * \ *
1244 * C---C-*
1245 * \ / \
1246 * C *
1247 * / \
1248 * *-C *
1249 * / \
1250 * * *
1251 *
1252 */
1253
1254 DGraph graph = new DGraph();
1255 graph.addVertex(cvN);
1256 graph.appendVertexOnAP(cvN.getAP(0), cvC3a.getAP(0));
1257 graph.appendVertexOnAP(cvN.getAP(1), cvC1a.getAP(0));
1258 graph.appendVertexOnAP(cvN.getAP(2), cvC3b.getAP(0));
1259 graph.appendVertexOnAP(cvC3b.getAP(2), cvC1b.getAP(0));
1260 graph.addSymmetricSetOfVertices(new SymmetricVertexes(Arrays.asList(
1261 cvC3a, cvC3b)));
1262
1263 //Logger logger = Logger.getLogger("DummyLogger");
1264 //Randomizer rng = new Randomizer();
1265 //DenoptimIO.writeGraphToSDF(new File("/tmp/graph.sdf"), graph, false, logger, rng);
1266
1267 HashMap<APClass,ArrayList<APClass>> cpMap =
1268 new HashMap<APClass,ArrayList<APClass>>();
1269 ArrayList<APClass> lstA = new ArrayList<APClass>();
1270 lstA.add(APCB);
1271 cpMap.put(APCA, lstA);
1272 ArrayList<APClass> lstB = new ArrayList<APClass>();
1273 lstA.add(APCA);
1274 cpMap.put(APCB, lstB);
1275
1277 FragmentSpace fs = new FragmentSpace(fsParams,
1278 new ArrayList<Vertex>(),
1279 fragments,
1280 new ArrayList<Vertex>(),
1281 cpMap,
1282 new HashMap<APClass,APClass>(),
1283 new HashSet<APClass>(),
1284 new HashMap<APClass,ArrayList<APClass>>());
1285 fs.setAPclassBasedApproach(true);
1286
1287 GAParameters gaParams = new GAParameters();
1288 gaParams.setParameters(fsParams);
1289
1290 assertEquals(5, graph.getVertexCount());
1291
1292 GraphOperations.extendGraph(cvC3a, false, true, true, 2, 0, gaParams);
1293
1294 assertEquals(12, graph.getVertexCount());
1295 assertEquals(2, graph.getSymmetricSetCount());
1296 assertEquals(2, graph.getSymVerticesForVertex(cvC3a).size());
1297 assertEquals(7, graph.getSymVerticesForVertex(
1298 graph.getVertexAtPosition(graph.getVertexCount()-1)).size());
1299 }
1300
1301//------------------------------------------------------------------------------
1302
1303}
Class defining a space of building blocks.
void setAPclassBasedApproach(boolean useAPC)
Set the fragment space to behave according to APClass-based approach.
Parameters defining the fragment space.
static void replaceHatomWithAP(Fragment frag, int srcId, APClass apc)
Collection of operators meant to alter graphs and associated utilities.
static List< XoverSite > locateCompatibleXOverPoints(DGraph graphA, DGraph graphB, FragmentSpace fragSpace, int maxSizeXoverSubGraph, int maxCompatibleVrtxPairs, int maxEndPointsCombinations, int maxEndPointsPermutations, int maxAPMappingCombinations)
Identify crossover sites, i.e., subgraphs that can be swapped between two graphs (i....
static boolean extendGraph(Vertex curVertex, boolean extend, boolean symmetryOnAps, GAParameters settings)
function that will keep extending the graph according to the growth/substitution probability.
static boolean addFusedRing(Vertex vertex, Monitor mnt, boolean force, FragmentSpace fragSpace, GAParameters settings)
Tries to add a fused ring using a pair of free APs, one of which on the given vertex.
static boolean addRing(Vertex vertex, Monitor mnt, boolean force, FragmentSpace fragSpace, GAParameters settings)
Tries to use any free AP of the given vertex to close ring in the graph by adding a chord.
boolean matchesExpected(Collection< DGraph > actuals)
ExtractPatternCase(DGraph g, int expectedSize, Set< DGraph > expectedGraphs)
DGraph[] getPairOfTestGraphs()
Generates a pair of graphs that include templates with free content.
Set< DGraph > getExpectedSubgraphs(DGraph graph)
Vertex buildFragment(String elementSymbol, int apCount, boolean isRCV)
FragmentSpace prepare()
Sets the compatibility matrix (src -> trg);.
void addRings(List< Vertex > vertices, DGraph g)
DGraph getThreeCycle()
Returns a 3-cycle.
DGraph buildGraph(List< Vertex > vertices, List< List< Integer > > edges)
ExtractPatternCase getFusedRings()
Returns a molecule consisting of two pairs of fused rings connected by an oxygen atom.
This class collects the data identifying the subgraphs that would be swapped by a crossover event.
Definition: XoverSite.java:36
static final APClass RCACLASSPLUS
Conventional class of attachment points on ring-closing vertexes.
Definition: APClass.java:85
static final APClass RCACLASSMINUS
Conventional class of attachment points on ring-closing vertexes.
Definition: APClass.java:92
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....
Container for the list of vertices and the edges that connect them.
Definition: DGraph.java:104
int getSymmetricSetCount()
Returns the number of symmetric sets of vertices.
Definition: DGraph.java:323
Vertex getSourceVertex()
Identifies and return the vertex from which the spanning tree originates.
Definition: DGraph.java:996
void removeRing(Ring ring)
Definition: DGraph.java:3286
void addVertex(Vertex vertex)
Appends a vertex to this graph without creating any edge.
Definition: DGraph.java:1391
void removeVertex(Vertex vertex)
Remove a vertex from this graph.
Definition: DGraph.java:1413
void setGraphId(int id)
Definition: DGraph.java:266
int indexOf(Vertex v)
Returns the index of a vertex in the list of vertices of this graph.
Definition: DGraph.java:3218
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
static void setScaffold(Vertex v)
Update the graph so that the vertex argument is at the scaffold level i.e.
Definition: DGraph.java:7567
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
static boolean compareGraphNodes(Vertex thisV, DGraph thisG, Vertex otherV, DGraph otherG)
Compares graphs by spanning vertices starting from the given vertex and following the direction of ed...
Definition: DGraph.java:4475
DGraph clone()
Returns almost "deep-copy" of this graph.
Definition: DGraph.java:3836
List< DGraph > extractPattern(GraphPattern pattern)
Extracts subgraphs that match the provided pattern.
Definition: DGraph.java:5157
void renumberGraphVertices()
Reassign vertex IDs to all vertices of this graph.
Definition: DGraph.java:5983
List< Vertex > getSymVerticesForVertex(Vertex v)
Definition: DGraph.java:345
List< Ring > getRings()
Definition: DGraph.java:1027
void addSymmetricSetOfVertices(SymmetricVertexes symSet)
Adds a symmetric set of vertices to this graph.
Definition: DGraph.java:891
void addRing(Ring ring)
Definition: DGraph.java:1304
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
void addAP(int atomPositionNumber)
Adds an attachment point with a dummy APClass.
Definition: Fragment.java:343
void addBond(IBond bond)
Definition: Fragment.java:871
Fragment clone()
Returns a deep copy of this fragments.
Definition: Fragment.java:733
void addAtom(IAtom atom)
Definition: Fragment.java:836
This class represents the closure of a ring in a spanning tree.
Definition: Ring.java:40
void addVertex(Vertex v)
Append a Vertex to the list.
Definition: Ring.java:71
A collection of Vertexs that are related by a relation that we call "symmetry", even though this clas...
void setInnerGraph(DGraph innerGraph)
Definition: Template.java:298
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
void setAsRCV(boolean isRCV)
Definition: Vertex.java:274
abstract List< AttachmentPoint > getAttachmentPoints()
void setUniquefyingProperty(String key)
Add the given key among the properties that are checked for equality when comparing vertices with the...
Definition: Vertex.java:1199
void setProperty(Object key, Object property)
Definition: Vertex.java:1235
AttachmentPoint getAP(int i)
Get attachment point i on this vertex.
Definition: Vertex.java:1007
The RingClosingAttractor represent the available valence/connection that allows to close a ring.
static final HashMap< APClass, String > RCALABELPERAPCLASS
Conventional labels for attractor pseudoatom.
Parameters and setting related to handling ring closures.
void setRingSizeBias(List< Integer > biases)
Sets the preference for certain ring sizes or the prohibition to generate certain rings (i....
A collection of counters user to count actions taken by the evolutionary algorithm.
Definition: Monitor.java:37
void setRandomizer(Randomizer rng)
Sets the randomizer.
void setParameters(RunTimeParameters otherParams)
RunTimeParameters getParameters(ParametersType type)
Parameters for genetic algorithm.
Utilities for graphs.
Definition: GraphUtils.java:40
static synchronized long getUniqueVertexIndex()
Unique counter for the number of graph vertices generated.
Definition: GraphUtils.java:97
static String getLabel(Vertex v)
Utilities for molecule conversion.
static int countAtomsOfElement(IAtomContainer mol, String symbol)
Count atoms with the given elemental symbol.
static void explicitHydrogens(IAtomContainer mol)
Converts all the implicit hydrogens to explicit.
Tool to generate random numbers and random decisions.
Definition: Randomizer.java:36
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
RC_PARAMS
Parameters pertaining to ring closures in graphs.