From 02a7fdb4e666718a5a83fac16524eb91e6e5b9fd Mon Sep 17 00:00:00 2001 From: John Mayfield Date: Sat, 9 Mar 2024 08:37:52 +0000 Subject: [PATCH] The number of essential/relevant cycles can be exponential for some molecules - e.g. cyclo-phanes. We know how many there are before generating them so we can et a reasonable limit which just fails if this limit is reached. This limit can be configured by a system property. --- .../org/openscience/cdk/graph/Cycles.java | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/base/core/src/main/java/org/openscience/cdk/graph/Cycles.java b/base/core/src/main/java/org/openscience/cdk/graph/Cycles.java index 83d0ed8346..74a5aebdae 100644 --- a/base/core/src/main/java/org/openscience/cdk/graph/Cycles.java +++ b/base/core/src/main/java/org/openscience/cdk/graph/Cycles.java @@ -32,6 +32,7 @@ import org.openscience.cdk.interfaces.IRing; import org.openscience.cdk.interfaces.IRingSet; import org.openscience.cdk.ringsearch.RingSearch; +import org.openscience.cdk.tools.LoggingToolFactory; import java.util.ArrayDeque; import java.util.ArrayList; @@ -90,6 +91,22 @@ */ public final class Cycles { + private static final String CDK_MAX_RELEVANT_CYCLES_KEY = "cdk.maxRelevantCycles"; + private static final long MAX_RELEVANT_CYCLES = getSystemInteger(CDK_MAX_RELEVANT_CYCLES_KEY, 512000); + + private static long getSystemInteger(String key, long val) { + String prop = System.getProperty(key); + if (prop == null) + return val; + try { + return Long.parseLong(prop); + } catch (NumberFormatException ex) { + LoggingToolFactory.createLoggingTool(Cycles.class) + .error("Error - Invalid number for system property=" + key); + } + return val; + } + /** Vertex paths for each cycle. */ private final int[][] paths; @@ -861,19 +878,23 @@ int[][] apply(int[][] graph, int length) { /** {@inheritDoc} */ @Override - int[][] apply(int[][] graph, int length) { + int[][] apply(int[][] graph, int length) throws Intractable { InitialCycles ic = InitialCycles.ofBiconnectedComponent(graph, length); RelevantCycles rc = new RelevantCycles(ic); - return new EssentialCycles(rc, ic).paths(); + numberOfCyclesCheck(rc); + EssentialCycles essentialCycles = new EssentialCycles(rc, ic); + return essentialCycles.paths(); } }, RELEVANT { /** {@inheritDoc} */ @Override - int[][] apply(int[][] graph, int length) { + int[][] apply(int[][] graph, int length) throws Intractable { InitialCycles ic = InitialCycles.ofBiconnectedComponent(graph, length); - return new RelevantCycles(ic).paths(); + RelevantCycles rc = new RelevantCycles(ic); + numberOfCyclesCheck(rc); + return rc.paths(); } }, ALL { @@ -1024,6 +1045,12 @@ public Cycles find(IAtomContainer molecule, int[][] graph, int length) throws In } } + private static void numberOfCyclesCheck(RelevantCycles rc) throws Intractable { + if (rc.size() > MAX_RELEVANT_CYCLES) + throw new Intractable("Too many relevant cycles cycles! max=" + MAX_RELEVANT_CYCLES + " was=" + rc.size() + "." + + " Increase this limit with System property -D" + CDK_MAX_RELEVANT_CYCLES_KEY + "="); + } + /** * Internal - lifts a path in a subgraph back to the original graph. *