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