From 4648c62be2bc36ff41ceb4ead3c0bb40b292ec96 Mon Sep 17 00:00:00 2001
From: ComboProblem <102884863+ComboProblem@users.noreply.github.com>
Date: Thu, 21 Aug 2025 18:12:20 -0700
Subject: [PATCH 1/9] add _partial_eval method to ParametricRealField
---
.../igp/parametric.sage | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/cutgeneratingfunctionology/igp/parametric.sage b/cutgeneratingfunctionology/igp/parametric.sage
index 908b10e9a..b5bd9da43 100644
--- a/cutgeneratingfunctionology/igp/parametric.sage
+++ b/cutgeneratingfunctionology/igp/parametric.sage
@@ -562,6 +562,28 @@ class ParametricRealField(Field):
except TypeError: # 'None' components
pass
raise FactorUndetermined("{} cannot be evaluated because the test point is not complete".format(fac))
+
+ def _partial_eval_factor(self, fac):
+ """
+ Partially evaluate ``fac`` on the test point.
+
+ This function is only intended to be called after ``FactorUndetermined`` is raised from ``_eval_factor``.
+ """
+ val_dict = {sym:val for sym, val zip([symb.sym() for symb in self._gens], self._values) if val is not None}
+ return fac.subs(val_dict)
+
+# Returns a symbolic expression or raises an ``EvaluationSuccessfulFlag``.
+# Receiving an ``EvaluationSuccessfulFlag`` means ``fac`` can be evaluated with the known values of the
+# test point.
+# base_ring = self._sym_field.base_ring()
+# if fac in base_ring:
+# raise EvaluationSuccessfulFlag("{} can be evaluated in the base_ring. Use _eval_factor instead.".format(fac))
+# try:
+# fac(self._values)
+# raise EvaluationSuccessfulFlag("{} can be evaluated with the test point. Use _eval_factor instead.".format(fac))
+# except TypeError:
+# val_dict = {sym:val for sym, val zip([symb.sym() for symb in self._gens], self._values) if val is not None}
+# return fac.subs(val_dict)
def _factor_sign(self, fac):
"""
From dbdfb61139b362e949a79e045d990d1b9b13a6d6 Mon Sep 17 00:00:00 2001
From: ComboProblem <102884863+ComboProblem@users.noreply.github.com>
Date: Thu, 21 Aug 2025 18:13:22 -0700
Subject: [PATCH 2/9] update doc to design goals for partial test points
---
cutgeneratingfunctionology/igp/parametric.sage | 17 +++++++----------
1 file changed, 7 insertions(+), 10 deletions(-)
diff --git a/cutgeneratingfunctionology/igp/parametric.sage b/cutgeneratingfunctionology/igp/parametric.sage
index b5bd9da43..04f688b69 100644
--- a/cutgeneratingfunctionology/igp/parametric.sage
+++ b/cutgeneratingfunctionology/igp/parametric.sage
@@ -158,25 +158,22 @@ class ParametricRealField(Field):
sage: f[0]*f[1] <= 4
True
- Test-point free mode (limited functionality and MUCH slower because of many more polynoial
- evaluations via libsingular)::
+ Test-point free descriptions can be written which every comparison is assumed to be true.
+ MUCH slower because of many more polynoial evaluations via libsingular::
sage: K. = ParametricRealField(None, mutable_values=True)
sage: a <= 2
- Traceback (most recent call last):
- ...
- FactorUndetermined: a cannot be evaluated because the test point is not complete
+ True
sage: K.assume_comparison(a.sym(), operator.le, 3)
- Partial test point mode::
+ Comparisons with test-points that are partially defined are supported. Comparisons made in
+ unspecified variables are assumed to be true::
sage: K. = ParametricRealField([None, 1], mutable_values=True)
sage: a <= 2
- Traceback (most recent call last):
- ...
- FactorUndetermined: a cannot be evaluated because the test point is not complete
- sage: b <= 11
True
+ sage: b <= 11
+ True
"""
Element = ParametricRealFieldElement
From e47fcd5f5891eb6a8fdd88fbb9096109519e8f9c Mon Sep 17 00:00:00 2001
From: ComboProblem <102884863+ComboProblem@users.noreply.github.com>
Date: Thu, 21 Aug 2025 18:18:16 -0700
Subject: [PATCH 3/9] change assume_comparison to support partial evaluations
---
cutgeneratingfunctionology/igp/parametric.sage | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/cutgeneratingfunctionology/igp/parametric.sage b/cutgeneratingfunctionology/igp/parametric.sage
index 04f688b69..7628e7541 100644
--- a/cutgeneratingfunctionology/igp/parametric.sage
+++ b/cutgeneratingfunctionology/igp/parametric.sage
@@ -174,7 +174,6 @@ class ParametricRealField(Field):
True
sage: b <= 11
True
-
"""
Element = ParametricRealFieldElement
@@ -859,14 +858,24 @@ class ParametricRealField(Field):
try:
comparison_val = comparison.val()
except FactorUndetermined:
- comparison_val = None
+ # partial test point evaluation; assume evaluation is true
+ # so record the assumed factor in the BSA
+ # it is the responsibility of the BSA to know if it is empty or not
+ # most implementations of BSAs cannot do this for non-linear cases.
+ assumed_fac = self._partial_eval_factor(comparison)
+ if not is_factor_known(assumed_fac):
+ record_comparision(assumed_fac, op)
+ return
comparison = comparison.sym()
else:
comparison = self._sym_field(comparison)
try:
comparison_val = self._eval_factor(comparison)
except FactorUndetermined:
- comparison_val = None
+ assumed_fac = self._partial_eval_factor(comparison)
+ if not is_factor_known(assumed_fac):
+ record_comparision(assumed_fac, op)
+ return
if comparison_val is not None:
if not op(comparison_val, 0):
if comparison in base_ring:
From 44cf014f6ea22948f65db308aeda3360da89c65c Mon Sep 17 00:00:00 2001
From: ComboProblem <102884863+ComboProblem@users.noreply.github.com>
Date: Fri, 22 Aug 2025 14:34:21 -0700
Subject: [PATCH 4/9] fix syntax
---
cutgeneratingfunctionology/igp/parametric.sage | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/cutgeneratingfunctionology/igp/parametric.sage b/cutgeneratingfunctionology/igp/parametric.sage
index 7628e7541..78d96b260 100644
--- a/cutgeneratingfunctionology/igp/parametric.sage
+++ b/cutgeneratingfunctionology/igp/parametric.sage
@@ -565,7 +565,9 @@ class ParametricRealField(Field):
This function is only intended to be called after ``FactorUndetermined`` is raised from ``_eval_factor``.
"""
- val_dict = {sym:val for sym, val zip([symb.sym() for symb in self._gens], self._values) if val is not None}
+ syms = [symb.sym() for symb in self._gens]
+ val_dict = {sym:val for sym, val in zip(syms , self._values) if val is not None}
+ print(val_dict)
return fac.subs(val_dict)
# Returns a symbolic expression or raises an ``EvaluationSuccessfulFlag``.
From 96f0921d0bf645da3a8dc55bd623d500579e1d56 Mon Sep 17 00:00:00 2001
From: ComboProblem <102884863+ComboProblem@users.noreply.github.com>
Date: Fri, 22 Aug 2025 14:52:21 -0700
Subject: [PATCH 5/9] move FactorUndetermined to its own file to make it a
shared resouce
---
cutgeneratingfunctionology/igp/parametric.sage | 4 +---
cutgeneratingfunctionology/shared/EvaluationExceptions.py | 2 ++
.../spam/parametric_real_field_element.py | 3 ++-
3 files changed, 5 insertions(+), 4 deletions(-)
create mode 100644 cutgeneratingfunctionology/shared/EvaluationExceptions.py
diff --git a/cutgeneratingfunctionology/igp/parametric.sage b/cutgeneratingfunctionology/igp/parametric.sage
index 78d96b260..8facd9031 100644
--- a/cutgeneratingfunctionology/igp/parametric.sage
+++ b/cutgeneratingfunctionology/igp/parametric.sage
@@ -20,6 +20,7 @@ from cutgeneratingfunctionology.spam.basic_semialgebraic_local import BasicSemia
from cutgeneratingfunctionology.spam.semialgebraic_mathematica import BasicSemialgebraicSet_mathematica, from_mathematica
from cutgeneratingfunctionology.spam.basic_semialgebraic_groebner_basis import BasicSemialgebraicSet_groebner_basis
from cutgeneratingfunctionology.spam.polyhedral_complex import PolyhedralComplex
+from cutgeneratingfunctionology.shared.EvaluationExceptions import FactorUndetermined
from .parametric_family import Classcall, ParametricFamily_base, ParametricFamily
debug_new_factors = False
@@ -58,9 +59,6 @@ class ParametricRealFieldRefinementError(ValueError):
from contextlib import contextmanager
-class FactorUndetermined(Exception):
- pass
-
allow_refinement_default = True
big_cells_default = 'if_not_allow_refinement'
mutable_values_default = False
diff --git a/cutgeneratingfunctionology/shared/EvaluationExceptions.py b/cutgeneratingfunctionology/shared/EvaluationExceptions.py
new file mode 100644
index 000000000..7e7dd6e04
--- /dev/null
+++ b/cutgeneratingfunctionology/shared/EvaluationExceptions.py
@@ -0,0 +1,2 @@
+class FactorUndetermined(Exception): # FactorUndetermined is raised when an expression can not be evaluated with a test point.
+ pass
\ No newline at end of file
diff --git a/cutgeneratingfunctionology/spam/parametric_real_field_element.py b/cutgeneratingfunctionology/spam/parametric_real_field_element.py
index c6688eeeb..40c1a4ea9 100644
--- a/cutgeneratingfunctionology/spam/parametric_real_field_element.py
+++ b/cutgeneratingfunctionology/spam/parametric_real_field_element.py
@@ -9,6 +9,7 @@
from sage.rings.real_mpfr import RR
from sage.functions.other import ceil, floor
from sage.functions.generalized import sign
+from cutgeneratingfunctionology.shared.EvaluationExceptions import FactorUndetermined
import operator
def richcmp_op_negation(op):
@@ -20,7 +21,7 @@ def richcmp_op_negation(op):
return op_NE
elif op == op_NE:
return op_EQ
- elif op == op_GT:
+ elif op == op_GT:s
return op_LE
elif op == op_GE:
return op_LT
From 387f17799fa34c8ef917fce9943c8d1ffecdc015 Mon Sep 17 00:00:00 2001
From: ComboProblem <102884863+ComboProblem@users.noreply.github.com>
Date: Thu, 28 Aug 2025 15:13:15 -0700
Subject: [PATCH 6/9] inprogress
---
.../igp/parametric.sage | 30 +++++++++++--------
.../spam/parametric_real_field_element.py | 17 +++++++----
2 files changed, 30 insertions(+), 17 deletions(-)
diff --git a/cutgeneratingfunctionology/igp/parametric.sage b/cutgeneratingfunctionology/igp/parametric.sage
index 8facd9031..4dbc7b660 100644
--- a/cutgeneratingfunctionology/igp/parametric.sage
+++ b/cutgeneratingfunctionology/igp/parametric.sage
@@ -563,9 +563,7 @@ class ParametricRealField(Field):
This function is only intended to be called after ``FactorUndetermined`` is raised from ``_eval_factor``.
"""
- syms = [symb.sym() for symb in self._gens]
- val_dict = {sym:val for sym, val in zip(syms , self._values) if val is not None}
- print(val_dict)
+ val_dict = {sym:val for sym, val in zip(fac.parent().gens() , self._values) if val is not None}
return fac.subs(val_dict)
# Returns a symbolic expression or raises an ``EvaluationSuccessfulFlag``.
@@ -858,14 +856,21 @@ class ParametricRealField(Field):
try:
comparison_val = comparison.val()
except FactorUndetermined:
- # partial test point evaluation; assume evaluation is true
- # so record the assumed factor in the BSA
- # it is the responsibility of the BSA to know if it is empty or not
- # most implementations of BSAs cannot do this for non-linear cases.
+ # Partial test point evaluation assumes the partially
+ # evaluated factor is True.
+ # So, we record the assumed factor in the BSA without checking if the factor
+ # should be addeded or not.
+ # It becomes the responsibility of the BSA to detemined if the recorded factors
+ # so far repersent a non-empty BSA.
+ # Most implementations of BSAs cannot do this for non-linear cases.
+ # With a BSA that is equipped with a first order logic solver like QPEAD
+ # should be able to do this.
assumed_fac = self._partial_eval_factor(comparison)
- if not is_factor_known(assumed_fac):
- record_comparision(assumed_fac, op)
- return
+ self.record_factor(assumed_fac, op)
+ print(assumed_fac)
+ if self._bsa.is_empty():
+ raise ParametricRealFieldInconsistencyError("Assumed constraint {} derivied from the comparision {} {} {} is inconsistent with already recoreded constraints".format(assumed_fac, lhs, op, rhs))
+ return
comparison = comparison.sym()
else:
comparison = self._sym_field(comparison)
@@ -873,8 +878,9 @@ class ParametricRealField(Field):
comparison_val = self._eval_factor(comparison)
except FactorUndetermined:
assumed_fac = self._partial_eval_factor(comparison)
- if not is_factor_known(assumed_fac):
- record_comparision(assumed_fac, op)
+ if not self.is_factor_known(assumed_fac, op):
+ self.record_factor(assumed_fac, op)
+ print("here", assumed_fac)
return
if comparison_val is not None:
if not op(comparison_val, 0):
diff --git a/cutgeneratingfunctionology/spam/parametric_real_field_element.py b/cutgeneratingfunctionology/spam/parametric_real_field_element.py
index 40c1a4ea9..99d6a82fc 100644
--- a/cutgeneratingfunctionology/spam/parametric_real_field_element.py
+++ b/cutgeneratingfunctionology/spam/parametric_real_field_element.py
@@ -21,7 +21,7 @@ def richcmp_op_negation(op):
return op_NE
elif op == op_NE:
return op_EQ
- elif op == op_GT:s
+ elif op == op_GT:
return op_LE
elif op == op_GE:
return op_LT
@@ -77,9 +77,13 @@ def sym(self):
def val(self):
try:
return self._val
- except AttributeError:
- return self.parent()._eval_factor(self._sym)
-
+ except AttributeError: # with imutable values, this fales because we get some hash map weirdness
+ try:
+ return self.parent()._eval_factor(self._sym)
+ except FactorUndetermined:
+ possible_val = self.parent()._partial_eval_factor(self._sym)
+ if possible_val in possible_val.base_ring():
+ return possible_val
def _richcmp_(left, right, op):
r"""
Examples for traditional cmp semantics::
@@ -127,7 +131,10 @@ def _richcmp_(left, right, op):
# shouldn't really happen, within coercion
raise TypeError("comparing elements from different fields")
if left.parent()._big_cells:
- result = richcmp(left.val(), right.val(), op)
+ try:
+ result = richcmp(left.val(), right.val(), op)
+ except FactorUndetermined:
+ result = True
if result:
true_op = op
else:
From 56baa49e5eb3edc6f25bb93f81ec3ff670edbb89 Mon Sep 17 00:00:00 2001
From: ComboProblem <102884863+ComboProblem@users.noreply.github.com>
Date: Sat, 30 Aug 2025 10:39:31 -0700
Subject: [PATCH 7/9] working partial test point more, next step fix doc string
tests
---
.../igp/parametric.sage | 31 ++++++-------------
1 file changed, 10 insertions(+), 21 deletions(-)
diff --git a/cutgeneratingfunctionology/igp/parametric.sage b/cutgeneratingfunctionology/igp/parametric.sage
index 4dbc7b660..2ae87bb7f 100644
--- a/cutgeneratingfunctionology/igp/parametric.sage
+++ b/cutgeneratingfunctionology/igp/parametric.sage
@@ -171,7 +171,7 @@ class ParametricRealField(Field):
sage: a <= 2
True
sage: b <= 11
- True
+ True
"""
Element = ParametricRealFieldElement
@@ -856,38 +856,27 @@ class ParametricRealField(Field):
try:
comparison_val = comparison.val()
except FactorUndetermined:
- # Partial test point evaluation assumes the partially
- # evaluated factor is True.
- # So, we record the assumed factor in the BSA without checking if the factor
- # should be addeded or not.
- # It becomes the responsibility of the BSA to detemined if the recorded factors
- # so far repersent a non-empty BSA.
- # Most implementations of BSAs cannot do this for non-linear cases.
- # With a BSA that is equipped with a first order logic solver like QPEAD
- # should be able to do this.
- assumed_fac = self._partial_eval_factor(comparison)
- self.record_factor(assumed_fac, op)
- print(assumed_fac)
- if self._bsa.is_empty():
- raise ParametricRealFieldInconsistencyError("Assumed constraint {} derivied from the comparision {} {} {} is inconsistent with already recoreded constraints".format(assumed_fac, lhs, op, rhs))
- return
+ comparison_val = None
comparison = comparison.sym()
else:
comparison = self._sym_field(comparison)
try:
comparison_val = self._eval_factor(comparison)
except FactorUndetermined:
- assumed_fac = self._partial_eval_factor(comparison)
- if not self.is_factor_known(assumed_fac, op):
- self.record_factor(assumed_fac, op)
- print("here", assumed_fac)
- return
+ comparison_val = None
if comparison_val is not None:
if not op(comparison_val, 0):
if comparison in base_ring:
raise ParametricRealFieldInconsistencyError("New constant constraint {} {} {} is not satisfied".format(lhs, op, rhs))
else:
raise ParametricRealFieldInconsistencyError("New constraint {} {} {} is not satisfied by the test point".format(lhs, op, rhs))
+ else: #A numerical evaluation of the expression has failed. Assume the partial evaluation of the expression holds.
+ comparison_val_or_expr = self._partial_eval_factor(comparison)
+ if not op(comparison_val_or_expr, 0): #The partial evual
+ if comparison_val_or_expr in base_ring:
+ raise ParametricRealFieldInconsistencyError("New constant constraint {} {} {} is not satisfied".format(lhs, op, rhs))
+ else: # comparision_val_or_expr is algebraic expresion, the only "true" comparision here is comparionsion val_or_expr
+ comparison = comparison_val_or_expr
if comparison in base_ring:
return
if comparison.denominator() == 1 and comparison.numerator().degree() == 1:
From 921178f667a152f7845692ec201a9f0cc0ae2999 Mon Sep 17 00:00:00 2001
From: ComboProblem <102884863+ComboProblem@users.noreply.github.com>
Date: Sat, 30 Aug 2025 15:12:41 -0700
Subject: [PATCH 8/9] finish comments; clean up tests.
---
cutgeneratingfunctionology/igp/parametric.sage | 17 ++++++++---------
.../spam/parametric_real_field_element.py | 2 +-
2 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/cutgeneratingfunctionology/igp/parametric.sage b/cutgeneratingfunctionology/igp/parametric.sage
index 2ae87bb7f..631226716 100644
--- a/cutgeneratingfunctionology/igp/parametric.sage
+++ b/cutgeneratingfunctionology/igp/parametric.sage
@@ -162,7 +162,8 @@ class ParametricRealField(Field):
sage: K. = ParametricRealField(None, mutable_values=True)
sage: a <= 2
True
- sage: K.assume_comparison(a.sym(), operator.le, 3)
+ sage: K. = ParametricRealField(None, mutable_values=True)
+ sage: K.assume_comparison(a.sym(), operator.le, 2)
Comparisons with test-points that are partially defined are supported. Comparisons made in
unspecified variables are assumed to be true::
@@ -312,7 +313,7 @@ class ParametricRealField(Field):
sage: sqrt2, = nice_field_values([sqrt(2)])
sage: K. = ParametricRealField([0], base_ring=sqrt2.parent())
sage: f + sqrt2
- (f + (a))~
+ (f + a)~
This currently does not work for Sage's built-in embedded number field elements...
"""
@@ -404,9 +405,7 @@ class ParametricRealField(Field):
....: with K.temporary_assumptions():
....: K.assume_comparison(a.sym(), operator.le, 3)
....: a <= 4
- Traceback (most recent call last):
- ...
- FactorUndetermined: a cannot be evaluated because the test point is not complete...
+ True
"""
self._values = [ None for n in self._names ]
@@ -872,11 +871,11 @@ class ParametricRealField(Field):
raise ParametricRealFieldInconsistencyError("New constraint {} {} {} is not satisfied by the test point".format(lhs, op, rhs))
else: #A numerical evaluation of the expression has failed. Assume the partial evaluation of the expression holds.
comparison_val_or_expr = self._partial_eval_factor(comparison)
- if not op(comparison_val_or_expr, 0): #The partial evual
- if comparison_val_or_expr in base_ring:
+ if comparison_val_or_expr in base_ring:
+ if not op(comparison_val_or_expr, 0): #The partial evaluation is ture, means
raise ParametricRealFieldInconsistencyError("New constant constraint {} {} {} is not satisfied".format(lhs, op, rhs))
- else: # comparision_val_or_expr is algebraic expresion, the only "true" comparision here is comparionsion val_or_expr
- comparison = comparison_val_or_expr
+ else: # comparision_val_or_expr is algebraic expresion, asume the comparision here is comparionsion_val_or_expr
+ comparison = comparison_val_or_expr
if comparison in base_ring:
return
if comparison.denominator() == 1 and comparison.numerator().degree() == 1:
diff --git a/cutgeneratingfunctionology/spam/parametric_real_field_element.py b/cutgeneratingfunctionology/spam/parametric_real_field_element.py
index 99d6a82fc..656734c4a 100644
--- a/cutgeneratingfunctionology/spam/parametric_real_field_element.py
+++ b/cutgeneratingfunctionology/spam/parametric_real_field_element.py
@@ -133,7 +133,7 @@ def _richcmp_(left, right, op):
if left.parent()._big_cells:
try:
result = richcmp(left.val(), right.val(), op)
- except FactorUndetermined:
+ except FactorUndetermined: # Partial evauation is happen, assume the result is True.
result = True
if result:
true_op = op
From 81d9b6cfb19d269274eeceae9f05ad156bcbb977 Mon Sep 17 00:00:00 2001
From: ComboProblem <102884863+ComboProblem@users.noreply.github.com>
Date: Sat, 30 Aug 2025 15:19:42 -0700
Subject: [PATCH 9/9] remove some comments
---
.../spam/parametric_real_field_element.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cutgeneratingfunctionology/spam/parametric_real_field_element.py b/cutgeneratingfunctionology/spam/parametric_real_field_element.py
index 656734c4a..b50c7d8d1 100644
--- a/cutgeneratingfunctionology/spam/parametric_real_field_element.py
+++ b/cutgeneratingfunctionology/spam/parametric_real_field_element.py
@@ -77,7 +77,7 @@ def sym(self):
def val(self):
try:
return self._val
- except AttributeError: # with imutable values, this fales because we get some hash map weirdness
+ except AttributeError:
try:
return self.parent()._eval_factor(self._sym)
except FactorUndetermined: