From 8482cd09952c312443ed164f9fbba995f34d5ee2 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Sun, 26 Jul 2026 16:19:46 -0500 Subject: [PATCH 01/13] Piece retrievals: lose the get_ --- namedisl/expression_like.py | 8 ++++---- namedisl/set_like.py | 12 ++++++------ namedisl/test/test_set_like.py | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/namedisl/expression_like.py b/namedisl/expression_like.py index 23d65fe..905729b 100644 --- a/namedisl/expression_like.py +++ b/namedisl/expression_like.py @@ -505,7 +505,7 @@ class PwAff(_NamedAffLike[isl.PwAff]): .. automethod:: zero_like_me .. autoattribute:: var_pw_affs .. automethod:: where - .. automethod:: get_pieces + .. autoattribute:: pieces .. automethod:: coalesce .. automethod:: eq_set .. automethod:: ne_set @@ -613,7 +613,7 @@ def min(self, other: PwAff) -> PwAff: self_a, other_a = _align_two_expr_likes(self, other) return PwAff(self_a._obj.min(other_a._obj), self_a.space) - def get_pieces(self) -> list[tuple[Set, Aff]]: + def pieces(self) -> list[tuple[Set, Aff]]: set_space = self.space.as_set_space() from .set_like import Set return [ @@ -746,7 +746,7 @@ def make_qpolynomial( class PwQPolynomial(_NamedPolynomialLike[isl.PwQPolynomial]): __doc__ = f""" - .. automethod:: get_pieces + .. automethod:: pieces {_NamedPolynomialLike.__doc__} {_NamedExpressionLike.__doc__} {NamedIslObject.__doc__} @@ -754,7 +754,7 @@ class PwQPolynomial(_NamedPolynomialLike[isl.PwQPolynomial]): _isl_type: ClassVar[type[IslObject]] = isl.PwQPolynomial - def get_pieces(self) -> list[tuple[Set, QPolynomial]]: + def pieces(self) -> list[tuple[Set, QPolynomial]]: set_space = self.space.as_set_space() from .set_like import Set return [ diff --git a/namedisl/set_like.py b/namedisl/set_like.py index c17239f..c7e5f9c 100644 --- a/namedisl/set_like.py +++ b/namedisl/set_like.py @@ -320,7 +320,7 @@ class BasicSet(_NamedIslSetLike[isl.BasicSet], _NamedIslBasic[isl.BasicSet]): .. automethod:: add_constraint .. autoattribute:: var_affs .. automethod:: as_set - .. automethod:: get_constraints + .. automethod:: constraints {_NamedIslSetLike.__doc__} {_NamedIslBasic.__doc__} {_NamedIslSetOrMapLike.__doc__} @@ -336,7 +336,7 @@ def add_constraint(self, cns: Constraint, /) -> BasicSet: raise ValueError("spaces don't match") return BasicSet(self._obj.add_constraint(cns._obj), self.space) - def get_constraints(self): + def constraints(self): from .expression_like import Constraint return [ Constraint(cns, self.space.with_empty_dim_type(DimType.in_)) @@ -382,7 +382,7 @@ class Set(_NamedIslSetLike[isl.Set], _NamedIslUnbasic[isl.Set]): .. automethod:: complement .. automethod:: simple_hull .. automethod:: convex_hull - .. automethod:: get_basic_sets + .. automethod:: basic_sets .. automethod:: dim_max .. automethod:: dim_min .. autoattribute:: var_affs @@ -405,7 +405,7 @@ def simple_hull(self): def convex_hull(self) -> BasicSet: return BasicSet(self._obj.convex_hull(), self.space) - def get_basic_sets(self) -> list[BasicSet]: + def basic_sets(self) -> list[BasicSet]: return [BasicSet(bs, self.space) for bs in self._obj.get_basic_sets()] def dim_max(self, name: str, *, cache: Cache | None = None) -> PwAff: @@ -595,7 +595,7 @@ class Map(_NamedIslMapLike[isl.Map], _NamedIslUnbasic[isl.Map]): .. automethod:: complement .. automethod:: simple_hull .. automethod:: convex_hull - .. automethod:: get_basic_maps + .. automethod:: basic_maps .. automethod:: domain .. automethod:: range .. automethod:: intersect_domain @@ -625,7 +625,7 @@ def simple_hull(self): def convex_hull(self) -> BasicMap: return BasicMap(self._obj.convex_hull(), self.space) - def get_basic_maps(self) -> list[BasicMap]: + def basic_maps(self) -> list[BasicMap]: return [BasicMap(bs, self.space) for bs in self._obj.get_basic_maps()] def domain(self) -> Set: diff --git a/namedisl/test/test_set_like.py b/namedisl/test/test_set_like.py index b66711c..a4cabea 100644 --- a/namedisl/test/test_set_like.py +++ b/namedisl/test/test_set_like.py @@ -311,8 +311,8 @@ def test_map_coalesce() -> None: map_ = nisl.make_map( "{ [i] -> [j = i] : 0 <= i < 5 or 5 <= i < 10 }" ) - assert len(map_.get_basic_maps()) == 2 - assert len(map_.coalesce().get_basic_maps()) == 1 + assert len(map_.basic_maps()) == 2 + assert len(map_.coalesce().basic_maps()) == 1 @pytest.mark.parametrize("ndims_domain", [2, 3, 4, 5]) From 5147125f633c34095bd378d48c9d1e8643d73ade Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Sun, 26 Jul 2026 16:48:56 -0500 Subject: [PATCH 02/13] Refactor _unparam to work on bare isl objects --- namedisl/expression_like.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/namedisl/expression_like.py b/namedisl/expression_like.py index 905729b..f251adc 100644 --- a/namedisl/expression_like.py +++ b/namedisl/expression_like.py @@ -110,14 +110,17 @@ bound="_NamedExpressionLike[IslScalarExpressionLike]") -def _unparam_expr_domain(obj: NamedExpressionLikeT) -> NamedExpressionLikeT: +def _unparam_expr_domain(obj: IslExpressionLikeT) -> IslExpressionLikeT: """If the domain of obj is a param domain, this will make it not a param domain.""" # Oh isl. There *has* to be a better way. + if isinstance(obj, (isl.PwMultiAff, isl.Constraint)): + raise NotImplementedError(f"not supported for {type(obj)}") + dt = isl.dim_type.in_ - d = obj._obj.dim(dt) - return type(obj)(obj._obj.add_dims(dt, 1).drop_dims(dt, d, 1), obj.space) + d = obj.dim(dt) + return cast("IslExpressionLikeT", obj.add_dims(dt, 1).drop_dims(dt, d, 1)) def _align_two_expr_likes( @@ -130,9 +133,9 @@ def _align_two_expr_likes( lhs, rhs = align_two(lhs, rhs) if lhs._obj.get_domain_space().is_params(): - lhs = _unparam_expr_domain(lhs) + lhs = type(lhs)(_unparam_expr_domain(lhs._obj), lhs.space) if rhs._obj.get_domain_space().is_params(): - rhs = _unparam_expr_domain(rhs) + rhs = type(rhs)(_unparam_expr_domain(rhs._obj), rhs.space) return lhs, rhs From 7151a5358870da9d53c44d7bcdb4e6350ffca2f1 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Sun, 26 Jul 2026 16:49:21 -0500 Subject: [PATCH 03/13] make_*: Use unparam if necessary --- namedisl/expression_like.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/namedisl/expression_like.py b/namedisl/expression_like.py index f251adc..5adc736 100644 --- a/namedisl/expression_like.py +++ b/namedisl/expression_like.py @@ -407,6 +407,8 @@ def make_aff(src: isl.Aff) -> Aff: def make_aff(src: str | isl.Aff, ctx: isl.Context | None = None) -> Aff: obj = isl.Aff(src, ctx) if isinstance(src, str) else src + if obj.get_domain_space().is_params(): + obj = _unparam_expr_domain(obj) return Aff(obj, Space.from_isl(obj, Aff.active_dim_types)) @@ -664,6 +666,8 @@ def make_pw_aff(src: str | isl.PwAff, ctx: isl.Context | None = None) -> PwAff: Create a :class:`PwAff` from isl syntax or an :class:`islpy.PwAff`. """ obj = isl.PwAff(src, ctx) if isinstance(src, str) else src + if obj.get_domain_space().is_params(): + obj = _unparam_expr_domain(obj) return PwAff(obj, Space.from_isl(obj, PwAff. active_dim_types)) @@ -744,6 +748,9 @@ def make_qpolynomial( else: obj = src + if obj.get_domain_space().is_params(): + obj = _unparam_expr_domain(obj) + return QPolynomial(obj, Space.from_isl(obj, QPolynomial.active_dim_types)) @@ -785,6 +792,8 @@ def make_pw_qpolynomial( Create a :class:`PwQPolynomial` from isl syntax or an isl object. """ obj = isl.PwQPolynomial(src, ctx) if isinstance(src, str) else src + if obj.get_domain_space().is_params(): + obj = _unparam_expr_domain(obj) return PwQPolynomial( obj, Space.from_isl(obj, PwQPolynomial.active_dim_types)) From 04bf5f3d88237eb134a399c86c9dc41e61e3d938 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Sun, 26 Jul 2026 17:13:21 -0500 Subject: [PATCH 04/13] unparam results of dim_{min,max} --- namedisl/set_like.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/namedisl/set_like.py b/namedisl/set_like.py index c7e5f9c..d9c50fe 100644 --- a/namedisl/set_like.py +++ b/namedisl/set_like.py @@ -412,16 +412,20 @@ def dim_max(self, name: str, *, cache: Cache | None = None) -> PwAff: dt, idx = self.space.name_to_dim[name] if dt != DimType.out: raise ValueError("can only take max with respect to set dimensions") - from .expression_like import PwAff - return PwAff(with_cache(cache, isl.Set.dim_max, self._obj, idx), + from .expression_like import PwAff, _unparam_expr_domain + isl_result = _unparam_expr_domain( + with_cache(cache, isl.Set.dim_max, self._obj, idx)) + return PwAff(isl_result, self.space.drop_dim_type(DimType.out).with_empty_dim_type(DimType.in_)) def dim_min(self, name: str, *, cache: Cache | None = None) -> PwAff: dt, idx = self.space.name_to_dim[name] if dt != DimType.out: raise ValueError("can only take min with respect to set dimensions") - from .expression_like import PwAff - return PwAff(with_cache(cache, isl.Set.dim_min, self._obj, idx), + from .expression_like import PwAff, _unparam_expr_domain + isl_result = _unparam_expr_domain( + with_cache(cache, isl.Set.dim_min, self._obj, idx)) + return PwAff(isl_result, self.space.drop_dim_type(DimType.out).with_empty_dim_type(DimType.in_)) @cached_property From 4cbee4c49ddc5d1952ff807123144004c0ccef66 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Sun, 26 Jul 2026 16:49:31 -0500 Subject: [PATCH 05/13] Add Term --- namedisl/__init__.py | 2 ++ namedisl/expression_like.py | 44 ++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/namedisl/__init__.py b/namedisl/__init__.py index 31a2b22..ace697b 100644 --- a/namedisl/__init__.py +++ b/namedisl/__init__.py @@ -36,6 +36,7 @@ PwMultiAff, PwQPolynomial, QPolynomial, + Term, affs_from_domain_space, make_aff, make_constraint, @@ -74,6 +75,7 @@ "QPolynomial", "Set", "Space", + "Term", "affs_from_domain_space", "align_two", "make_aff", diff --git a/namedisl/expression_like.py b/namedisl/expression_like.py index 5adc736..1fcf3f5 100644 --- a/namedisl/expression_like.py +++ b/namedisl/expression_like.py @@ -18,6 +18,10 @@ .. autofunction:: make_pw_aff .. autofunction:: pw_affs_from_domain_space +Quasipolynomial term +-------------------- +.. autoclass:: Term + Quasipolynomial --------------- .. autoclass:: QPolynomial @@ -67,7 +71,7 @@ """ import operator -from collections.abc import Mapping +from collections.abc import Mapping, Sequence from dataclasses import dataclass from functools import cached_property from typing import ( @@ -86,6 +90,7 @@ from .core import ( DimType, IslAffLikeT_co, + IslExpressionLikeT, IslExpressionLikeT_co, IslHasCoefficientsT_co, IslObject, @@ -716,14 +721,51 @@ def __pow__(self, other: int) -> Self: return type(self)(cast("IslPolynomialLikeT_co", self._obj ** other), self.space) +@dataclass(frozen=True, eq=False) +class Term: + """ + .. autoattribute:: space + .. autoattribute:: coefficient + .. automethod:: get_exp + .. autoattribute:: num_divs + .. automethod:: get_div + .. automethod:: get_div_exp + """ + # Term is super-rudimentary + _obj: isl.Term + space: Space + + @property + def coefficient(self) -> isl.Val: + return self._obj.get_coefficient_val() + + def get_exp(self, name: str) -> int: + dt, idx = self.space.name_to_dim[name] + return self._obj.get_exp(dt.as_isl(), idx) + + @property + def num_divs(self) -> int: + return self._obj.dim(isl.dim_type.div) + + def get_div(self, index: int) -> Aff: + return Aff(self._obj.get_div(index), self.space) + + def get_div_exp(self, index: int) -> int: + return self._obj.get_exp(isl.dim_type.div, index) + + class QPolynomial(_NamedPolynomialLike[isl.QPolynomial]): __doc__ = f""" + .. automethod:: terms {_NamedPolynomialLike.__doc__} {_NamedExpressionLike.__doc__} {NamedIslObject.__doc__} """ _isl_type: ClassVar[type[IslObject]] = isl.QPolynomial + def terms(self) -> Sequence[Term]: + return [Term(trm, self.space) for trm in self._obj.get_terms()] + @overload def make_qpolynomial(src: str, ctx: isl.Context | None = None) -> QPolynomial: From 5d41b02ebb344c3194fb0984ece3cef3fdd2bdb4 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Sun, 26 Jul 2026 17:30:19 -0500 Subject: [PATCH 06/13] get_constant -> constant attr --- namedisl/expression_like.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/namedisl/expression_like.py b/namedisl/expression_like.py index 1fcf3f5..54863ae 100644 --- a/namedisl/expression_like.py +++ b/namedisl/expression_like.py @@ -332,7 +332,7 @@ class _NamedHasCoefficients(NamedIslObject[IslHasCoefficientsT_co]): .. automethod:: get_div .. automethod:: get_div_coefficient - .. automethod:: get_constant + .. autoattribute:: constant """ @property @@ -349,7 +349,8 @@ def get_coefficient(self, name: str) -> isl.Val: dt, idx = self.space.name_to_dim[name] return self._obj.get_coefficient_val(dt.as_isl(), idx) - def get_constant(self) -> isl.Val: + @property + def constant(self) -> isl.Val: return self._obj.get_constant_val() From dc2361575d492814b12897efba8a9ad1afeae17e Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Sun, 26 Jul 2026 17:32:38 -0500 Subject: [PATCH 07/13] More get_ extermination --- namedisl/expression_like.py | 8 ++++---- namedisl/set_like.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/namedisl/expression_like.py b/namedisl/expression_like.py index 54863ae..4c0932d 100644 --- a/namedisl/expression_like.py +++ b/namedisl/expression_like.py @@ -359,7 +359,7 @@ class Aff(_NamedAffLike[isl.Aff], _NamedHasCoefficients[isl.Aff]): .. automethod:: zero_on_domain .. automethod:: as_pw_aff .. automethod:: set_coefficient - .. automethod:: get_denominator + .. automethod:: denominator .. autoattribute:: var_affs @@ -384,7 +384,7 @@ def set_coefficient(self, name: str, value: int) -> Aff: dt, idx = self.space.name_to_dim[name] return Aff(self._obj.set_coefficient_val(dt.as_isl(), idx, value), self.space) - def get_denominator(self) -> isl.Val: + def denominator(self) -> isl.Val: return self._obj.get_denominator_val() @cached_property @@ -526,7 +526,7 @@ class PwAff(_NamedAffLike[isl.PwAff]): .. automethod:: lt_set .. automethod:: max .. automethod:: min - .. automethod:: get_aggregate_domain + .. automethod:: aggregate_domain .. automethod:: union_max .. automethod:: union_min .. automethod:: union_add @@ -637,7 +637,7 @@ def pieces(self) -> list[tuple[Set, Aff]]: def coalesce(self) -> PwAff: return PwAff(self._obj.coalesce(), self.space) - def get_aggregate_domain(self) -> Set: + def aggregate_domain(self) -> Set: from .set_like import Set agg_domain = self._obj.get_aggregate_domain() return Set( diff --git a/namedisl/set_like.py b/namedisl/set_like.py index d9c50fe..3a69a26 100644 --- a/namedisl/set_like.py +++ b/namedisl/set_like.py @@ -512,7 +512,7 @@ class BasicMap(_NamedIslMapLike[isl.BasicMap], _NamedIslBasic[isl.BasicMap]): .. automethod:: range .. automethod:: intersect_domain .. automethod:: intersect_range - .. automethod:: get_constraints + .. automethod:: constraints {_NamedIslMapLike.__doc__} {_NamedIslBasic.__doc__} {_NamedIslSetOrMapLike.__doc__} @@ -526,7 +526,7 @@ def add_constraint(self, cns: Constraint, /) -> BasicMap: raise ValueError("spaces don't match") return BasicMap(self._obj.add_constraint(cns._obj), self.space) - def get_constraints(self): + def constraints(self): from .expression_like import Constraint return [ Constraint(cns, self.space) for cns in self._obj.get_constraints()] From cb386c3bb96897c424980def7ef3ee5a02d06890 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 27 Jul 2026 09:13:39 -0500 Subject: [PATCH 08/13] Optimize _unparam: use add_dims(0) --- namedisl/expression_like.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/namedisl/expression_like.py b/namedisl/expression_like.py index 4c0932d..663b03b 100644 --- a/namedisl/expression_like.py +++ b/namedisl/expression_like.py @@ -124,8 +124,7 @@ def _unparam_expr_domain(obj: IslExpressionLikeT) -> IslExpressionLikeT: raise NotImplementedError(f"not supported for {type(obj)}") dt = isl.dim_type.in_ - d = obj.dim(dt) - return cast("IslExpressionLikeT", obj.add_dims(dt, 1).drop_dims(dt, d, 1)) + return cast("IslExpressionLikeT", obj.add_dims(dt, 0)) def _align_two_expr_likes( From 4ab7c4c0ecd6cde6b07441c521cfb11acaeb2364 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 27 Jul 2026 09:13:54 -0500 Subject: [PATCH 09/13] Add compute_divs --- namedisl/set_like.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/namedisl/set_like.py b/namedisl/set_like.py index 3a69a26..f2fda2f 100644 --- a/namedisl/set_like.py +++ b/namedisl/set_like.py @@ -113,6 +113,7 @@ class _NamedIslSetOrMapLike(NamedIslObject[IslSetOrMapLikeT_co]): .. automethod:: project_out_except .. automethod:: gist .. automethod:: remove_divs + .. automethod:: compute_divs .. automethod:: __and__ .. automethod:: __or__ .. automethod:: __sub__ @@ -230,6 +231,12 @@ def gist(self, context: Self) -> Self: self_aligned.space, ) + def compute_divs(self) -> Self: + return type(self)( + cast("IslSetOrMapLikeT_co", self._obj.compute_divs()), + self.space, + ) + def remove_divs(self) -> Self: return type(self)( cast("IslSetOrMapLikeT_co", self._obj.remove_divs()), From 3ce5acd411bb8105fcd0ff0c87eca9a785706fd0 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 27 Jul 2026 09:18:49 -0500 Subject: [PATCH 10/13] Catch and ban maps with params domains --- namedisl/set_like.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/namedisl/set_like.py b/namedisl/set_like.py index f2fda2f..b12f8fc 100644 --- a/namedisl/set_like.py +++ b/namedisl/set_like.py @@ -507,6 +507,12 @@ class _NamedIslMapLike(_NamedIslSetOrMapLike[IslMapLikeT]): active_dim_types: ClassVar[frozenset[DimType]] = frozenset( {DimType.param, DimType.in_, DimType.out}) + if __debug__: + def __post_init__(self) -> None: + if self._obj.space.domain().is_params(): + raise ValueError("domain is params, this is not allowed") + return super().__post_init__() + def reverse(self) -> Self: return type(self)( cast("IslMapLikeT", self._obj.reverse()), From 2e2d705259dc803dee3d9dd1e8e93ef74613dbe9 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 27 Jul 2026 09:19:06 -0500 Subject: [PATCH 11/13] Optimize Set.as_map --- namedisl/set_like.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/namedisl/set_like.py b/namedisl/set_like.py index b12f8fc..fec0bfb 100644 --- a/namedisl/set_like.py +++ b/namedisl/set_like.py @@ -463,8 +463,7 @@ def var_pw_affs(self) -> Mapping[str | Literal[0], PwAff]: return _PwAffMapping(self.space.as_expr_space(), self._obj.space) def as_map(self, in_names: Collection[str]) -> Map: - result = isl.Map.universe(self._obj.space) - result = result.intersect_range(self._obj) + result = isl.Map.from_range(self._obj) named_map = Map(result, Space(dimtype_to_names=constantdict({ **self.space.dimtype_to_names, DimType.in_: () From e9f2a79ea0d9dca07637f8f8fbf4cb2d5ac5ca90 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 28 Jul 2026 09:33:11 -0500 Subject: [PATCH 12/13] PwAff: use Self in return types --- namedisl/expression_like.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/namedisl/expression_like.py b/namedisl/expression_like.py index 663b03b..65cbec5 100644 --- a/namedisl/expression_like.py +++ b/namedisl/expression_like.py @@ -633,8 +633,8 @@ def pieces(self) -> list[tuple[Set, Aff]]: for set, aff in self._obj.get_pieces() ] - def coalesce(self) -> PwAff: - return PwAff(self._obj.coalesce(), self.space) + def coalesce(self) -> Self: + return type(self)(self._obj.coalesce(), self.space) def aggregate_domain(self) -> Set: from .set_like import Set @@ -643,17 +643,17 @@ def aggregate_domain(self) -> Set: agg_domain.from_params() if agg_domain.is_params() else agg_domain, self.space.as_set_space()) - def union_max(self, other: PwAff) -> PwAff: + def union_max(self, other: PwAff) -> Self: self_a, other_a = _align_two_expr_likes(self, other) - return PwAff(self_a._obj.union_max(other_a._obj), self_a.space) + return type(self)(self_a._obj.union_max(other_a._obj), self_a.space) - def union_min(self, other: PwAff) -> PwAff: + def union_min(self, other: PwAff) -> Self: self_a, other_a = _align_two_expr_likes(self, other) - return PwAff(self_a._obj.union_min(other_a._obj), self_a.space) + return type(self)(self_a._obj.union_min(other_a._obj), self_a.space) - def union_add(self, other: PwAff) -> PwAff: + def union_add(self, other: PwAff) -> Self: self_a, other_a = _align_two_expr_likes(self, other) - return PwAff(self_a._obj.union_add(other_a._obj), self_a.space) + return type(self)(self_a._obj.union_add(other_a._obj), self_a.space) @overload From 55087686c92f94323865a33d2271889aefef15d3 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 28 Jul 2026 09:34:07 -0500 Subject: [PATCH 13/13] Build out PwQPoly functionality a bit --- namedisl/expression_like.py | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/namedisl/expression_like.py b/namedisl/expression_like.py index 65cbec5..dace11d 100644 --- a/namedisl/expression_like.py +++ b/namedisl/expression_like.py @@ -529,6 +529,7 @@ class PwAff(_NamedAffLike[isl.PwAff]): .. automethod:: union_max .. automethod:: union_min .. automethod:: union_add + .. automethod:: as_pw_qpoly {_NamedAffLike.__doc__} {_NamedExpressionLike.__doc__} {NamedIslObject.__doc__} @@ -655,6 +656,9 @@ def union_add(self, other: PwAff) -> Self: self_a, other_a = _align_two_expr_likes(self, other) return type(self)(self_a._obj.union_add(other_a._obj), self_a.space) + def as_pw_qpoly(self) -> PwQPolynomial: + return PwQPolynomial(isl.PwQPolynomial.from_pw_aff(self._obj), self.space) + @overload def make_pw_aff(src: str, ctx: isl.Context | None = None) -> PwAff: @@ -798,7 +802,11 @@ def make_qpolynomial( class PwQPolynomial(_NamedPolynomialLike[isl.PwQPolynomial]): __doc__ = f""" + .. automethod:: zero + .. automethod:: from_piece_and_qpolynomial .. automethod:: pieces + .. automethod:: coalesce + .. automethod:: add_disjoint {_NamedPolynomialLike.__doc__} {_NamedExpressionLike.__doc__} {NamedIslObject.__doc__} @@ -806,6 +814,30 @@ class PwQPolynomial(_NamedPolynomialLike[isl.PwQPolynomial]): _isl_type: ClassVar[type[IslObject]] = isl.PwQPolynomial + @classmethod + def zero(cls, space: Space): + return cls(isl.PwQPolynomial.zero(space.as_isl()), space) + + @staticmethod + def from_piece_and_qpolynomial(piece: Set, qpoly: QPolynomial) -> PwQPolynomial: + if not piece.space.order_equals(qpoly.space.as_set_space()): + raise ValueError("spaces don't match") + + if qpoly.space.dim(DimType.in_): + return PwQPolynomial( + isl.PwQPolynomial.alloc(piece._obj, qpoly._obj), qpoly.space) + else: + piece_obj = piece._obj + + # match piece to qpoly's params status + if qpoly._obj.get_domain_space().is_params(): + piece_obj = piece_obj.params() + else: + if piece_obj.is_params(): + piece_obj = piece_obj.from_params() + return PwQPolynomial( + isl.PwQPolynomial.alloc(piece_obj, qpoly._obj), qpoly.space) + def pieces(self) -> list[tuple[Set, QPolynomial]]: set_space = self.space.as_set_space() from .set_like import Set @@ -814,6 +846,14 @@ def pieces(self) -> list[tuple[Set, QPolynomial]]: for set, qp in self._obj.get_pieces() ] + def coalesce(self) -> Self: + return type(self)(self._obj.coalesce(), self.space) + + def add_disjoint(self, other: Self) -> Self: + self_a, other_a = _align_two_expr_likes(self, other) + return type(self)( + self_a._obj.add_disjoint(other_a._obj), self.space) + @overload def make_pw_qpolynomial(