From e6a72df6a92401cad666fbc618c8165923db6d33 Mon Sep 17 00:00:00 2001
From: VIGNET Pierre <pierre.vignet@irisa.fr>
Date: Thu, 19 Dec 2019 22:57:38 +0100
Subject: [PATCH] [lib] CLUnfolder Fix: ability to check the validity of the
 given query

---
 .../clause_constraints/mcl/CLUnfolder.py      | 68 ++++++++++++++++++-
 1 file changed, 66 insertions(+), 2 deletions(-)

diff --git a/library/cadbiom/models/clause_constraints/mcl/CLUnfolder.py b/library/cadbiom/models/clause_constraints/mcl/CLUnfolder.py
index 72938cb..e97a122 100644
--- a/library/cadbiom/models/clause_constraints/mcl/CLUnfolder.py
+++ b/library/cadbiom/models/clause_constraints/mcl/CLUnfolder.py
@@ -398,7 +398,57 @@ class CLUnfolder(object):
         self.__shift_direction = None     # FORWARD or BACKWARD
         self.__locked = False
 
-    def init_with_query(self, query):
+    def check_query(self, query):
+        """Check textual and DIMACS properties of the given query
+
+        If textual properties have changed since the last initialization of the
+        CLUnfolder, new auxiliary variables will be added to the dynamic system.
+
+        Also check if values of literals are in the limits of the dynamical
+        system (shift_step_init). If it's not the case, a ValueError exception
+        will be raised.
+
+        Called by:
+            :meth:`init_with_query`
+
+        :param query: Query built with start, invariant, final, variant properties
+            in textual and/or DIMACS forms.
+        :type query: <MCLSimpleQuery>
+        """
+        # Check textual properties
+        if (self.__initial_property != query.start_prop
+            or self.__final_property != query.final_prop
+            or self.__invariant_property != query.inv_prop
+            or self.__variant_property != query.variant_prop):
+            # System will be modified; Auxiliary clauses will be added
+            # Do not reload cached constraints
+            self.__include_aux_clauses_changed = True
+
+        # Check values of literals
+        values = set(it.chain(*query.dim_start))
+        values.update(it.chain(*query.dim_final))
+        values.update(it.chain(*query.dim_inv))
+        if query.dim_variant_prop:
+            # Handle empty steps:
+            # Ex: [[], [[4]], [[6], [7]], []]
+            g = (step for step in query.dim_variant_prop if step)
+            [values.update(it.chain(*step)) for step in g]
+
+        # Get all values that are not in the initial dynamic system
+        out_of_range_values = {val for val in values if abs(val) > self.shift_step_init}
+        if not out_of_range_values:
+            return
+
+        # The literal comes from an auxilary clause; not from the dynamic model.
+        # Since the auxiliary clauses are reset here, this literal is suspect
+        # and its use dangerous because its value is not reproductible.
+        raise ValueError(
+            "%s variable is not in the initial system.\n"
+            "Insertion of auxiliary variables is not allowed here."
+            % out_of_range_values
+        )
+
+    def init_with_query(self, query, check_query=True):
         """Initialise the unfolder with the given query
 
         Following attributes are used from the query:
@@ -411,8 +461,22 @@ class CLUnfolder(object):
         This compilation step is costly due to ANTLR performances...
 
         .. warning:: ALL textual properties are susceptible to add new auxiliary
-            variables in the system (increase shift_step).
+            variables in the system (increase shift_step). Thus, the system
+            will be rebuilt.
+
+        :param query: Query built with start, invariant, final, variant properties
+            in textual and/or DIMACS forms.
+        :key check_query: Check textual and DIMACS properties of the given query.
+
+            .. warning:: This option should be disable for performance reasons;
+                or if you know what you are doing.
+
+        :type query: <MCLSimpleQuery>
+        :type check_query: <boolean>
         """
+        if check_query:
+            self.check_query(query)
+
         # Reset the unfolder before a new query
         self.reset()
         # Init with query properties and clauses
-- 
GitLab