$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);
534
535 assertEquals(expectedNumberOfSites.get(i), xoverSites.size());
536
537 // NB: this is code that is unlocked only in development phase to
538 // generate the code that defined the expected invariant.
539 // Here, we exploit the fact that every vertex has a unique label as a
540 // property and the combination of sites generates an invariant.
541 // To generate this labels programmatically the following code is used
542 // but only after having checked manually.
543 boolean writeCode = false; //NB: make this true to generate the code!
544 if (writeCode)
545 {
546 String varName = "invariant" + contracts.get(i) + "Contract";
547 System.out.println("Set<String> " + varName + " = new HashSet<String>();");
548 for (XoverSite x : xoverSites)
549 {
550 String s = "\"\"";
551 for (Vertex v : x.getA())
552 {
553 String g = "";
554 if (v.getGraphOwner()==graphA)
555 g = "graphA";
556 else if (v.getGraphOwner()==graphB)
557 g = "graphB";
558 else if (v.getGraphOwner()==t1.getInnerGraph())
559 g = "t1.getInnerGraph()";
560 else if (v.getGraphOwner()==t2.getInnerGraph())
561 g = "t2.getInnerGraph()";
562 else
563 g = "noGraph";
564
565 s = s + "+GraphUtils.getLabel("+g+","+v.getGraphOwner().indexOf(v)+")+\"_\"";
566 }
567 s = s + "+\"@@@_\"";
568 for (Vertex v : x.getB())
569 {
570 String g = "";
571 if (v.getGraphOwner()==graphA)
572 g = "graphA";
573 else if (v.getGraphOwner()==graphB)
574 g = "graphB";
575 else if (v.getGraphOwner()==t1.getInnerGraph())
576 g = "t1.getInnerGraph()";
577 else if (v.getGraphOwner()==t2.getInnerGraph())
578 g = "t2.getInnerGraph()";
579 else
580 g = "noGraph";
581
582 s = s + "+GraphUtils.getLabel("+g+","+v.getGraphOwner().indexOf(v)+")+\"_\"";
583 }
584 System.out.println(varName + ".add("+s+");");
585 }
586 System.out.println("expectedInvariants.add("+varName+");");
587 }
588
589 for (XoverSite site : xoverSites)
590 {
591 String label = "";
592 for (Vertex v : site.getA())
593 {
594 label = label + GraphUtils.getLabel(v.getGraphOwner(),
595 v.getGraphOwner().indexOf(v)) + "_";
596 }
597 label = label + "@@@_";
598 for (Vertex v : site.getB())
599 {
600 label = label + GraphUtils.getLabel(v.getGraphOwner(),
601 v.getGraphOwner().indexOf(v)) + "_";
602 }
603 assertTrue(expectedInvariants.get(i).contains(label),
604 "For contract " + i + " (" + contracts.get(i)
605 + ") - Missing label: "+label);
606 }
607 }
608 }
609
610//------------------------------------------------------------------------------
611
644 private DGraph[] getPairOfTestGraphs() throws Exception
645 {
646 prepare();
647
648 // Prepare special building block: template T1
649 EmptyVertex v0 = new EmptyVertex(0);
650 v0.addAP(APCA);
651 v0.addAP(APCA);
652 v0.setProperty("Label", "tv0");
653
654 EmptyVertex v1 = new EmptyVertex(1);
655 v1.addAP(APCA);
656 v1.addAP(APCA);
657 v1.addAP(APCB);
658 v1.addAP(APCC);
659 v1.setProperty("Label", "tv1");
660
661 EmptyVertex v2 = new EmptyVertex(2);
662 v2.addAP(APCA);
663 v2.addAP(APCC);
664 v2.setProperty("Label", "tv2");
665
666 EmptyVertex v3 = new EmptyVertex(3);
667 v3.addAP(APCA);
668 v3.addAP(APCA);
669 v3.setProperty("Label", "tv3");
670
671 EmptyVertex v4 = new EmptyVertex(4);
672 v4.addAP(APCA);
673 v4.addAP(APCA);
674 v4.setProperty("Label", "tv4");
675
676 EmptyVertex v5 = new EmptyVertex(5);
677 v5.addAP(APCA);
678 v5.addAP(APCA);
679 v5.setProperty("Label", "tv5");
680
681 DGraph g = new DGraph();
682 g.addVertex(v0);
683 g.setGraphId(-1);
684 g.appendVertexOnAP(v0.getAP(0), v1.getAP(0));
685 g.appendVertexOnAP(v1.getAP(2), v2.getAP(1));
686 g.appendVertexOnAP(v2.getAP(0), v3.getAP(0));
687 g.appendVertexOnAP(v1.getAP(1), v4.getAP(1));
688 g.appendVertexOnAP(v4.getAP(0), v5.getAP(1));
689
690 Template t1 = new Template(BBType.NONE);
691 t1.setInnerGraph(g);
692 t1.setProperty("Label", "t1");
694
695 // Assemble the first graph: graphA
696
697 EmptyVertex m1 = new EmptyVertex(101);
698 m1.addAP(APCA);
699 m1.setProperty("Label", "m101");
700
701 EmptyVertex m2 = new EmptyVertex(102);
702 m2.addAP(APCA);
703 m2.addAP(APCB);
704 m2.setProperty("Label", "m102");
705
706 EmptyVertex m3 = new EmptyVertex(103);
707 m3.addAP(APCB);
708 m3.setProperty("Label", "m103");
709
710 EmptyVertex m4 = new EmptyVertex(104);
711 m4.addAP(APCC);
712 m4.setProperty("Label", "m104");
713
714 EmptyVertex m5 = new EmptyVertex(105);
715 m5.addAP(APCA);
716 m5.setProperty("Label", "m105");
717
718 DGraph graphA = new DGraph();
719 graphA.addVertex(m1);
720 graphA.appendVertexOnAP(m1.getAP(0), t1.getAP(0));
721 graphA.appendVertexOnAP(t1.getAP(2), m2.getAP(0));
722 graphA.appendVertexOnAP(m2.getAP(1), m3.getAP(0));
723 graphA.appendVertexOnAP(t1.getAP(1), m4.getAP(0));
724 graphA.appendVertexOnAP(t1.getAP(3), m5.getAP(0));
725
726 graphA.setGraphId(11111);
727
728 //Prepare special building block: template T2
729 EmptyVertex w1 = new EmptyVertex(11);
730 w1.addAP(APCA);
731 w1.addAP(APCB);
732 w1.addAP(APCC);
733 w1.setProperty("Label", "tw11");
734
735 EmptyVertex w2 = new EmptyVertex(12);
736 w2.addAP(APCB);
737 w2.addAP(APCC);
738 w2.setProperty("Label", "tw12");
739
740 EmptyVertex w3 = new EmptyVertex(13);
741 w3.addAP(APCA);
742 w3.addAP(APCB);
743 w3.setProperty("Label", "tw13");
744
745 EmptyVertex w4 = new EmptyVertex(14);
746 w4.addAP(APCA);
747 w4.addAP(APCA);
748 w4.setProperty("Label", "tw14");
749
750 DGraph g2 = new DGraph();
751 g2.addVertex(w1);
752 g2.appendVertexOnAP(w1.getAP(1), w2.getAP(1));
753 g2.appendVertexOnAP(w2.getAP(0), w3.getAP(1));
754 g2.appendVertexOnAP(w3.getAP(0), w4.getAP(0));
755 g2.setGraphId(-2);
756
757 Template t2 = new Template(BBType.NONE);
758 t2.setInnerGraph(g2);
759 t2.setProperty("Label", "t2");
761
762 // Assemble the second graph: graphB
763
764 EmptyVertex f1 = new EmptyVertex(1001);
765 f1.addAP(APCA);
766 f1.setProperty("Label", "f1001");
767
768 EmptyVertex f2 = new EmptyVertex(1002);
769 f2.addAP(APCA);
770 f2.addAP(APCB);
771 f2.setProperty("Label", "f1002");
772
773 EmptyVertex f3 = new EmptyVertex(1003);
774 f3.addAP(APCB);
775 f3.addAP(APCC);
776 f3.setProperty("Label", "f1003");
777
778 EmptyVertex f4 = new EmptyVertex(1004);
779 f4.addAP(APCC);
780 f4.setProperty("Label", "f1004");
781
782 EmptyVertex f5 = new EmptyVertex(1005);
783 f5.addAP(APCC);
784 f5.setProperty("Label", "f1005");
785
786 DGraph graphB = new DGraph();
787 graphB.addVertex(f1);
788 graphB.appendVertexOnAP(f1.getAP(0), t2.getAP(0));
789 graphB.appendVertexOnAP(t2.getAP(2), f2.getAP(0));
790 graphB.appendVertexOnAP(f2.getAP(1), f3.getAP(0));
791 graphB.appendVertexOnAP(f3.getAP(1), f4.getAP(0));
792 graphB.appendVertexOnAP(t2.getAP(1), f5.getAP(0));
793 graphB.setGraphId(22222);
794
795 DGraph[] pair = new DGraph[2];
796 pair[0] = graphA;
797 pair[1] = graphB;
798
799 return pair;
800 }
801
802//------------------------------------------------------------------------------
803
819 private FragmentSpace prepare() throws Exception
820 {
821 // Prepare APClass compatibility rules
822 APCA = APClass.make("A", 0);
823 APCB = APClass.make("B", 0);
824 APCC = APClass.make("C", 0);
825 APCD = APClass.make("D", 0);
826
827 HashMap<APClass,ArrayList<APClass>> cpMap =
828 new HashMap<APClass,ArrayList<APClass>>();
829 ArrayList<APClass> lstA = new ArrayList<APClass>();
830 lstA.add(APCA);
831 cpMap.put(APCA, lstA);
832 ArrayList<APClass> lstB = new ArrayList<APClass>();
833 lstB.add(APCB);
834 lstB.add(APCC);
835 cpMap.put(APCB, lstB);
836 ArrayList<APClass> lstC = new ArrayList<APClass>();
837 lstC.add(APCC);
838 cpMap.put(APCC, lstC);
839 ArrayList<APClass> lstD = new ArrayList<APClass>();
840 lstD.add(APCD);
841 cpMap.put(APCD, lstD);
842
843 HashMap<APClass,APClass> capMap = new HashMap<APClass,APClass>();
844 HashSet<APClass> forbEnds = new HashSet<APClass>();
845
847 FragmentSpace fs = new FragmentSpace(fsp,
848 new ArrayList<Vertex>(),
849 new ArrayList<Vertex>(),
850 new ArrayList<Vertex>(),
851 cpMap, capMap, forbEnds, cpMap);
853
854 return fs;
855 }
856
857//------------------------------------------------------------------------------
858
859 @Test
860 public void testAddRing() throws Exception
861 {
862 /* This is the graph we work with
863 *
864 * * * * RCV_M
865 * | | | |
866 * RCV_P--[O]----[C]--[C]--[C]--[C]--[C]----[N]--RCV_M
867 * vO vC vC2 vC3 vC4 vC5 vN
868 *
869 */
870
871 APClass apc = APClass.make("A", 0);
872
873 IAtomContainer iacO = chemBuilder.newAtomContainer();
874 IAtom aO = new Atom("O",new Point3d(0,0,0));
875 iacO.addAtom(aO);
876 Fragment vO = new Fragment(0, iacO,BBType.FRAGMENT);
877 vO.addAP(0, new Point3d(0,-1,0), apc);
878 vO.addAP(0, new Point3d(2,0,0), apc);
879 vO.addAP(0, new Point3d(0,1,0), apc);
880
881 IAtomContainer iacC = chemBuilder.newAtomContainer();
882 IAtom aC = new Atom("C",new Point3d(0,0,0));
883 iacC.addAtom(aC);
884 Fragment vC = new Fragment(1, iacC,BBType.FRAGMENT);
885 vC.addAP(0, new Point3d(0,-1,0), apc);
886 vC.addAP(0, new Point3d(2,0,0), apc);
887 vC.addAP(0, new Point3d(0,1,0), apc);
888
889 IAtomContainer iacCd = chemBuilder.newAtomContainer();
890 IAtom aCd = new Atom("C",new Point3d(0,0,0));
891 iacCd.addAtom(aCd);
892 Fragment vC2 = new Fragment(2, iacCd,BBType.FRAGMENT);
893 vC2.addAP(0, new Point3d(0,-1,0), apc);
894 vC2.addAP(0, new Point3d(0,1,0), apc);
895
896 Fragment vC3 = vC2.clone();
897 vC3.setVertexId(33);
898
899 Fragment vC4 = vC2.clone();
900 vC4.setVertexId(34);
901
902 Fragment vC5 = vC.clone();
903 vC5.setVertexId(3);
904
905 IAtomContainer iacN = chemBuilder.newAtomContainer();
906 IAtom aN = new Atom("N",new Point3d(0,0,0));
907 iacN.addAtom(aN);
908 Fragment vN = new Fragment(4, iacN,BBType.FRAGMENT);
909 vN.addAP(0, new Point3d(0,-1,0), apc);
910 vN.addAP(0, new Point3d(2,0,0), apc);
911 vN.addAP(0, new Point3d(0,1,0), apc);
912
913 APClass atMinus = APClass.RCACLASSMINUS;
914
915 IAtomContainer iacD = chemBuilder.newAtomContainer();
916 iacD.addAtom(new PseudoAtom(RingClosingAttractor.RCALABELPERAPCLASS.get(atMinus),
917 new Point3d(0,0,0)));
918 Fragment rcvM = new Fragment(6, iacD,BBType.FRAGMENT);
919 rcvM.addAP(0, new Point3d(-1,0,0), atMinus);
920 rcvM.setAsRCV(true);
921
922 Fragment rcvM2 = rcvM.clone();
923 rcvM2.setVertexId(7);
924
926
927 IAtomContainer iacE = chemBuilder.newAtomContainer();
928 iacE.addAtom(new PseudoAtom(RingClosingAttractor.RCALABELPERAPCLASS.get(atPlus),
929 new Point3d(0,0,0)));
930 Fragment rcvP = new Fragment(8, iacE,BBType.FRAGMENT);
931 rcvP.addAP(0, new Point3d(-1,0,0), atPlus);
932 rcvP.setAsRCV(true);
933
934 DGraph graph = new DGraph();
935 graph.addVertex(vC);
936 graph.appendVertexOnAP(vC.getAP(0), vO.getAP(2));
937 graph.appendVertexOnAP(vO.getAP(1), rcvP.getAP(0));
938 graph.appendVertexOnAP(vC.getAP(2), vC2.getAP(1));
939 graph.appendVertexOnAP(vC2.getAP(0), vC3.getAP(0));
940 graph.appendVertexOnAP(vC3.getAP(1), vC4.getAP(0));
941 graph.appendVertexOnAP(vC4.getAP(1), vC5.getAP(0));
942 graph.appendVertexOnAP(vC5.getAP(2), vN.getAP(0));
943 graph.appendVertexOnAP(vN.getAP(1), rcvM.getAP(0));
944 graph.appendVertexOnAP(vN.getAP(2), rcvM2.getAP(0));
945
946 // Prepare environment to run graph operation. First, a monitor of events
947 Monitor mnt = new Monitor();
948
949 // Then, a fragment space that allows ring closures
950 HashMap<APClass,ArrayList<APClass>> cpMap =
951 new HashMap<APClass,ArrayList<APClass>>();
952 ArrayList<APClass> lstA = new ArrayList<APClass>();
953 lstA.add(apc);
954 cpMap.put(apc, lstA);
956 FragmentSpace fs = new FragmentSpace(fsp,
957 new ArrayList<Vertex>(),
958 new ArrayList<Vertex>(),
959 new ArrayList<Vertex>(),
960 cpMap,
961 new HashMap<APClass,APClass>(),
962 new HashSet<APClass>(),
963 cpMap);
965
966 // Then, settings of ring-closing machinery
968 List<Integer> biases = new ArrayList<Integer>();
969 for (int i=0; i<rcParams.getMaxRingSize(); i++)
970 {
971 biases.add(0); // 0 means ring-closure not allowed
972 }
973 biases.set(5, 1);
974 rcParams.setRingSizeBias(biases);
975
976 // Then, some GA-parameters
977 GAParameters gaParams = new GAParameters();
978 gaParams.setParameters(rcParams);
979
980 // All ready, do the ring-adding mutation
981 assertEquals(0, graph.getRingCount());
982 GraphOperations.addRing(vC5, mnt, true, fs, gaParams);
983 assertEquals(1, graph.getRingCount());
984 }
985
986//------------------------------------------------------------------------------
987
988 @Test
989 public void testAddFusedRings() throws Exception
990 {
991 APClass apcA = APClass.make("apcA:1");
992 APClass hyd = APClass.make("hyd:1");
993
994 // Prepare environment to run graph operation. First, a monitor of events
995 Monitor mnt = new Monitor();
996
997 ArrayList<Vertex> libFrags = new ArrayList<Vertex>();
998
999 APClass APC4EL = APClass.make("4el:0");
1000 Fragment bridge4el = new Fragment(4);
1001 IAtom a4_0 = new Atom("Si", new Point3d());
1002 IAtom a4_1 = new Atom("Si", new Point3d());
1003 IAtom a4_2 = new Atom("Si", new Point3d());
1004 IAtom a4_3 = new Atom("Si", new Point3d());
1005 bridge4el.addAtom(a4_0);
1006 bridge4el.addAtom(a4_1);
1007 bridge4el.addAtom(a4_2);
1008 bridge4el.addAtom(a4_3);
1009 bridge4el.addBond(new Bond(a4_0, a4_1, IBond.Order.DOUBLE));
1010 bridge4el.addBond(new Bond(a4_1, a4_2, IBond.Order.SINGLE));
1011 bridge4el.addBond(new Bond(a4_2, a4_3, IBond.Order.DOUBLE));
1012 bridge4el.addAP(0, new Point3d(), APC4EL);
1013 bridge4el.addAP(3, new Point3d(), APC4EL);
1014 bridge4el.addAP(0, new Point3d(), apcA);
1015 bridge4el.addAP(1, new Point3d(), apcA);
1016 bridge4el.addAP(2, new Point3d(), apcA);
1017 bridge4el.addAP(3, new Point3d(), apcA);
1018 libFrags.add(bridge4el);
1019
1020 Fragment bridge4el3Atm = new Fragment(2);
1021 IAtom a3_0 = new Atom("Ge", new Point3d());
1022 IAtom a3_1 = new Atom("N", new Point3d());
1023 IAtom a3_2 = new Atom("Ge", new Point3d());
1024 bridge4el3Atm.addAtom(a3_0);
1025 bridge4el3Atm.addAtom(a3_1);
1026 bridge4el3Atm.addAtom(a3_2);
1027 bridge4el3Atm.addBond(new Bond(a3_0, a3_1, IBond.Order.SINGLE));
1028 bridge4el3Atm.addBond(new Bond(a3_1, a3_2, IBond.Order.SINGLE));
1029 bridge4el3Atm.addAP(0, new Point3d(), APC4EL);
1030 bridge4el3Atm.addAP(2, new Point3d(), APC4EL);
1031 bridge4el3Atm.addAP(0, new Point3d(), apcA);
1032 bridge4el3Atm.addAP(2, new Point3d(), apcA);
1033 libFrags.add(bridge4el3Atm);
1034
1035 APClass APC1EL = APClass.make("1el:0");
1036 Fragment bridge1el = new Fragment(1);
1037 IAtom a1_0 = new Atom("N", new Point3d());
1038 bridge1el.addAtom(a1_0);
1039 bridge1el.addAP(0, new Point3d(), APC1EL);
1040 bridge1el.addAP(0, new Point3d(), APC1EL);
1041 libFrags.add(bridge1el);
1042
1043 HashMap<APClass,APClass> cappingRules = new HashMap<APClass,APClass>();
1044 cappingRules.put(apcA, hyd);
1045
1046 ArrayList<Vertex> cappingGroups = new ArrayList<Vertex>();
1047 Fragment capH = new Fragment();
1048 capH.addAtom(new Atom("H", new Point3d()));
1049 capH.addAP(0, new Point3d(1.0, 0, 0), hyd);
1050 cappingGroups.add(capH);
1051
1052 HashMap<APClass,ArrayList<APClass>> rcCpMap =
1053 new HashMap<APClass,ArrayList<APClass>>();
1054 rcCpMap.put(apcA, new ArrayList<APClass>(Arrays.asList(APC4EL)));
1055
1057 FragmentSpace fs = new FragmentSpace(fsp,
1058 new ArrayList<Vertex>(),
1059 libFrags,
1060 cappingGroups,
1061 new HashMap<APClass,ArrayList<APClass>>(),
1062 cappingRules,
1063 new HashSet<APClass>(),
1064 rcCpMap);
1065 //NB: a non-empty rcCpMap is enough to trigger the automated recognition
1066 // that we are within the class-based approach.
1067
1068 // Then, some GA-parameters
1069 GAParameters gaParams = new GAParameters();
1070 gaParams.setParameters(new RingClosureParameters());
1071 gaParams.setRandomizer(new Randomizer(1L));
1072
1073 //
1074 // Add multiple rings
1075 //
1076
1077 SmilesParser parser = new SmilesParser(chemBuilder);
1078 IAtomContainer benzene = parser.parseSmiles("c1ccccc1");
1080 StructureDiagramGenerator sdg = new StructureDiagramGenerator();
1081 sdg.generateCoordinates(benzene);
1082 Fragment benzeneScaffold = new Fragment(benzene, BBType.FRAGMENT);
1083 for (int i= 0; i<6; i++)
1084 {
1085 EAUtilsTest.replaceHatomWithAP(benzeneScaffold, i, apcA);
1086 }
1087 benzeneScaffold.setVertexId(123);
1088 DGraph graph = new DGraph();
1089 graph.addVertex(benzeneScaffold);
1090
1091 assertEquals(0, graph.getRingCount());
1092 GraphOperations.addFusedRing(benzeneScaffold, mnt, true, fs, gaParams);
1093
1094 assertEquals(3, graph.getRingCount());
1095 int numSiAtoms = 0;
1096 for (Vertex v : graph.getVertexList())
1097 {
1098 numSiAtoms = numSiAtoms + MoleculeUtils.countAtomsOfElement(
1099 v.getIAtomContainer(), "Si");
1100 }
1101 assertEquals(12, numSiAtoms);
1102
1103 //
1104 // Adding one atom to close 6-member aromatic ring
1105 //
1106
1107 IAtomContainer arom = parser.parseSmiles("c1cccc(c12)ccc(c23)ccc(c34)cccc4");
1109 sdg.generateCoordinates(arom);
1110 Fragment frag = new Fragment(arom, BBType.FRAGMENT);
1111 EAUtilsTest.replaceHatomWithAP(frag, 0, apcA);
1112 EAUtilsTest.replaceHatomWithAP(frag, 17, apcA);
1113 frag.setVertexId(123);
1114 graph = new DGraph();
1115 graph.addVertex(frag);
1116
1117 assertEquals(0, graph.getRingCount());
1118 GraphOperations.addFusedRing(frag, mnt, true, fs, gaParams);
1119 assertEquals(1, graph.getRingCount());
1120
1121 //
1122 // Adhering to ring-size biases
1123 //
1124
1125 IAtomContainer arom2 = parser.parseSmiles("c1cccc(c12)ccc(c23)ccc(c34)cccc4");
1127 sdg.generateCoordinates(arom2);
1128 Fragment frag2 = new Fragment(arom2, BBType.FRAGMENT);
1129 // These two lead to a 5atm5el site, which can generate a 6atom ring
1130 EAUtilsTest.replaceHatomWithAP(frag2, 0, apcA);
1131 EAUtilsTest.replaceHatomWithAP(frag2, 17, apcA);
1132 // these lead to a 2atm2el site that can lead to 6- or 5-membered ring
1133 EAUtilsTest.replaceHatomWithAP(frag2, 14, apcA);
1134 EAUtilsTest.replaceHatomWithAP(frag2, 15, apcA);
1135 frag2.setVertexId(1);
1136 graph = new DGraph();
1137 graph.addVertex(frag2);
1140 // 0,1,2,3,4,5,6,7
1141 rcParams.setRingSizeBias(Arrays.asList(0,0,0,0,0,1,0,0));
1142
1143 assertEquals(0, graph.getRingCount());
1144 GraphOperations.addFusedRing(frag2, mnt, true, fs, gaParams);
1145 assertEquals(1, graph.getRingCount());
1146 numSiAtoms = 0;
1147 int numNAtoms = 0;
1148 int numGeAtoms = 0;
1149 for (Vertex v : graph.getVertexList())
1150 {
1151 numSiAtoms = numSiAtoms + MoleculeUtils.countAtomsOfElement(
1152 v.getIAtomContainer(), "Si");
1153 numNAtoms = numNAtoms + MoleculeUtils.countAtomsOfElement(
1154 v.getIAtomContainer(), "N");
1155 numGeAtoms = numGeAtoms + MoleculeUtils.countAtomsOfElement(
1156 v.getIAtomContainer(), "Ge");
1157 }
1158 assertEquals(0, numSiAtoms);
1159 assertEquals(1, numNAtoms);
1160 assertEquals(2, numGeAtoms);
1161 }
1162
1163//------------------------------------------------------------------------------
1164
1165 /*
1166 * Here we test whether the method detects that extension should be done in
1167 * all symmetric location, including APs belonging to the same vertex and
1168 * outside of it.
1169 */
1170
1171 @Test
1172 public void testExtendGraph() throws Exception
1173 {
1174 APClass APCA = APClass.make("A", 0);
1175 APClass APCB = APClass.make("B", 0);
1176
1177 Fragment vC1 = new Fragment();
1178 Atom ac1 = new Atom("C", new Point3d());
1179 vC1.addAtom(ac1);
1180 vC1.addAP(0, APCB, new Point3d(1.1, 0.0, 0.0));
1181 vC1.addAP(0, APCB, new Point3d(1.1, 1.0, 0.0));
1182 vC1.addAP(0, APCB, new Point3d(1.1, 1.0, 2.0));
1183 vC1.addAP(0, APCB, new Point3d(1.1,-1.0, 2.0));
1184
1185 Fragment vC3 = new Fragment();
1186 Atom ac31 = new Atom("C", new Point3d(0.0, 2.0, 0.0));
1187 Atom ac32 = new Atom("C", new Point3d(0.0, 0.0, 2.0));
1188 Atom ac33 = new Atom("C", new Point3d(0.0, 0.0, 0.0));
1189 vC3.addAtom(ac31);
1190 vC3.addAtom(ac32);
1191 vC3.addAtom(ac33);
1192 vC3.addBond(new Bond(ac31, ac32));
1193 vC3.addBond(new Bond(ac32, ac33));
1194 vC3.addBond(new Bond(ac33, ac31));
1195 vC3.addAP(0, APCA, new Point3d(0.0, 2.0, -1.0));
1196 vC3.addAP(1, APCA, new Point3d(-1.0,-1.0, 3.0));
1197 vC3.addAP(1, APCA, new Point3d(1.0, -1.0, 3.0));
1198 vC3.addAP(2, APCA, new Point3d(-1.0,-1.0, 1.0));
1199 vC3.addAP(2, APCA, new Point3d(1.0, -1.0, 1.0));
1200
1201 Fragment vCl = new Fragment();
1202 Atom acl = new Atom("Cl", new Point3d());
1203 vCl.addAtom(acl);
1204 vCl.addAP(0, APCB, new Point3d(1.1, 0.0, 0.0));
1205
1206 Fragment vN = new Fragment();
1207 Atom aN = new Atom("N", new Point3d());
1208 vN.addAtom(aN);
1209 vN.addAP(0, APCB, new Point3d(1.1, 0.0, 0.0));
1210 vN.addAP(0, APCA, new Point3d(1.1, 1.0, 0.0));
1211 vN.addAP(0, APCB, new Point3d(1.1, 1.0, 2.0));
1212
1213 ArrayList<Vertex> fragments = new ArrayList<Vertex>();
1214 fragments.add(vC1);
1215 fragments.add(vC3);
1216 fragments.add(vCl);
1217 fragments.add(vN);
1218
1219 // Use clones of the vertexes to simulate the construction from BBSpace
1220 Vertex cvC1a = vC1.clone();
1221 cvC1a.setVertexId(1);
1222 Vertex cvC1b = vC1.clone();
1223 cvC1b.setVertexId(2);
1224 Vertex cvC3a = vC3.clone();
1225 cvC3a.setVertexId(3);
1226 Vertex cvC3b = vC3.clone();
1227 cvC3b.setVertexId(4);
1228 Vertex cvN = vN.clone();
1229 cvN.setVertexId(0);
1230
1231 /* This is the graph we work with ('*' is a free AP)
1232 *
1233 * * *
1234 * / /
1235 * *-C---C-*
1236 * \ /
1237 * C
1238 * / *
1239 * / /
1240 * N(root)-----C-*
1241 * \ \
1242 * \ *
1243 * C---C-*
1244 * \ / \
1245 * C *
1246 * / \
1247 * *-C *
1248 * / \
1249 * * *
1250 *
1251 */
1252
1253 DGraph graph = new DGraph();
1254 graph.addVertex(cvN);
1255 graph.appendVertexOnAP(cvN.getAP(0), cvC3a.getAP(0));
1256 graph.appendVertexOnAP(cvN.getAP(1), cvC1a.getAP(0));
1257 graph.appendVertexOnAP(cvN.getAP(2), cvC3b.getAP(0));
1258 graph.appendVertexOnAP(cvC3b.getAP(2), cvC1b.getAP(0));
1259 graph.addSymmetricSetOfVertices(new SymmetricVertexes(Arrays.asList(
1260 cvC3a, cvC3b)));
1261
1262 //Logger logger = Logger.getLogger("DummyLogger");
1263 //Randomizer rng = new Randomizer();
1264 //DenoptimIO.writeGraphToSDF(new File("/tmp/graph.sdf"), graph, false, logger, rng);
1265
1266 HashMap<APClass,ArrayList<APClass>> cpMap =
1267 new HashMap<APClass,ArrayList<APClass>>();
1268 ArrayList<APClass> lstA = new ArrayList<APClass>();
1269 lstA.add(APCB);
1270 cpMap.put(APCA, lstA);
1271 ArrayList<APClass> lstB = new ArrayList<APClass>();
1272 lstA.add(APCA);
1273 cpMap.put(APCB, lstB);
1274
1276 FragmentSpace fs = new FragmentSpace(fsParams,
1277 new ArrayList<Vertex>(),
1278 fragments,
1279 new ArrayList<Vertex>(),
1280 cpMap,
1281 new HashMap<APClass,APClass>(),
1282 new HashSet<APClass>(),
1283 new HashMap<APClass,ArrayList<APClass>>());
1284 fs.setAPclassBasedApproach(true);
1285
1286 GAParameters gaParams = new GAParameters();
1287 gaParams.setParameters(fsParams);
1288
1289 assertEquals(5, graph.getVertexCount());
1290
1291 GraphOperations.extendGraph(cvC3a, false, true, true, 2, 0, gaParams);
1292
1293 assertEquals(12, graph.getVertexCount());
1294 assertEquals(2, graph.getSymmetricSetCount());
1295 assertEquals(2, graph.getSymVerticesForVertex(cvC3a).size());
1296 assertEquals(7, graph.getSymVerticesForVertex(
1297 graph.getVertexAtPosition(graph.getVertexCount()-1)).size());
1298 }
1299
1300//------------------------------------------------------------------------------
1301
1302}
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)
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:102
int getSymmetricSetCount()
Returns the number of symmetric sets of vertices.
Definition: DGraph.java:321
Vertex getSourceVertex()
Identifies and return the vertex from which the spanning tree originates.
Definition: DGraph.java:968
void removeRing(Ring ring)
Definition: DGraph.java:2866
void addVertex(Vertex vertex)
Appends a vertex to this graph without creating any edge.
Definition: DGraph.java:1325
void removeVertex(Vertex vertex)
Remove a vertex from this graph.
Definition: DGraph.java:1347
void setGraphId(int id)
Definition: DGraph.java:264
int indexOf(Vertex v)
Returns the index of a vertex in the list of vertices of this graph.
Definition: DGraph.java:2798
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:2743
static void setScaffold(Vertex v)
Update the graph so that the vertex argument is at the scaffold level i.e.
Definition: DGraph.java:7126
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:6005
List< Vertex > getVertexList()
Definition: DGraph.java:947
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:4054
DGraph clone()
Returns almost "deep-copy" of this graph.
Definition: DGraph.java:3415
List< DGraph > extractPattern(GraphPattern pattern)
Extracts subgraphs that match the provided pattern.
Definition: DGraph.java:4686
void renumberGraphVertices()
Reassign vertex IDs to all vertices of this graph.
Definition: DGraph.java:5512
List< Vertex > getSymVerticesForVertex(Vertex v)
Definition: DGraph.java:343
List< Ring > getRings()
Definition: DGraph.java:999
void addSymmetricSetOfVertices(SymmetricVertexes symSet)
Adds a symmetric set of vertices to this graph.
Definition: DGraph.java:889
void addRing(Ring ring)
Definition: DGraph.java:1258
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 DENOPTIMVertex 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:35
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.