islpy 2024.2__cp38-cp38-musllinux_1_2_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
islpy/__init__.py ADDED
@@ -0,0 +1,1283 @@
1
+ __copyright__ = "Copyright (C) 2011-20 Andreas Kloeckner"
2
+
3
+ __license__ = """
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+ """
22
+
23
+ from typing import Any, Callable, Optional, TypeVar, cast
24
+
25
+ import islpy._isl as _isl
26
+ from islpy.version import VERSION, VERSION_TEXT # noqa
27
+
28
+
29
+ __version__ = VERSION_TEXT
30
+
31
+ # {{{ copied verbatim from pytools to avoid numpy/pytools dependency
32
+
33
+ F = TypeVar("F", bound=Callable[..., Any])
34
+
35
+
36
+ class _HasKwargs:
37
+ pass
38
+
39
+
40
+ def _memoize_on_first_arg(function: F, cache_dict_name: Optional[str] = None) -> F:
41
+ """Like :func:`memoize_method`, but for functions that take the object
42
+ in which do memoization information is stored as first argument.
43
+
44
+ Supports cache deletion via ``function_name.clear_cache(self)``.
45
+ """
46
+ from sys import intern
47
+
48
+ if cache_dict_name is None:
49
+ cache_dict_name = intern(
50
+ f"_memoize_dic_{function.__module__}{function.__name__}"
51
+ )
52
+
53
+ def wrapper(obj, *args, **kwargs):
54
+ if kwargs:
55
+ key = (_HasKwargs, frozenset(kwargs.items()), *args)
56
+ else:
57
+ key = args
58
+
59
+ try:
60
+ return getattr(obj, cache_dict_name)[key]
61
+ except AttributeError:
62
+ attribute_error = True
63
+ except KeyError:
64
+ attribute_error = False
65
+
66
+ result = function(obj, *args, **kwargs)
67
+ if attribute_error:
68
+ object.__setattr__(obj, cache_dict_name, {key: result})
69
+ return result
70
+ else:
71
+ getattr(obj, cache_dict_name)[key] = result
72
+ return result
73
+
74
+ def clear_cache(obj):
75
+ object.__delattr__(obj, cache_dict_name)
76
+
77
+ from functools import update_wrapper
78
+ new_wrapper = update_wrapper(wrapper, function)
79
+
80
+ # type-ignore because mypy has a point here, stuffing random attributes
81
+ # into the function's dict is moderately sketchy.
82
+ new_wrapper.clear_cache = clear_cache # type: ignore[attr-defined]
83
+
84
+ return cast(F, new_wrapper)
85
+
86
+ # }}}
87
+
88
+
89
+ Error = _isl.Error
90
+
91
+ # {{{ name imports
92
+
93
+ isl_version = _isl.isl_version
94
+
95
+ Context = _isl.Context
96
+ IdList = _isl.IdList
97
+ ValList = _isl.ValList
98
+ BasicSetList = _isl.BasicSetList
99
+ BasicMapList = _isl.BasicMapList
100
+ SetList = _isl.SetList
101
+ MapList = _isl.MapList
102
+ UnionSetList = _isl.UnionSetList
103
+ ConstraintList = _isl.ConstraintList
104
+ AffList = _isl.AffList
105
+ PwAffList = _isl.PwAffList
106
+ PwMultiAffList = _isl.PwMultiAffList
107
+ AstExprList = _isl.AstExprList
108
+ AstNodeList = _isl.AstNodeList
109
+
110
+ QPolynomialList = _isl.QPolynomialList
111
+ PwQPolynomialList = _isl.PwQPolynomialList
112
+ PwQPolynomialFoldList = _isl.PwQPolynomialFoldList
113
+
114
+ UnionPwAffList = _isl.UnionPwAffList
115
+ UnionPwMultiAffList = _isl.UnionPwMultiAffList
116
+ UnionMapList = _isl.UnionMapList
117
+ UnionSetList = _isl.UnionSetList
118
+
119
+ IdToAstExpr = _isl.IdToAstExpr
120
+ Printer = _isl.Printer
121
+ Val = _isl.Val
122
+ MultiVal = _isl.MultiVal
123
+ Vec = _isl.Vec
124
+ Mat = _isl.Mat
125
+ FixedBox = _isl.FixedBox
126
+ Aff = _isl.Aff
127
+ PwAff = _isl.PwAff
128
+ UnionPwAff = _isl.UnionPwAff
129
+ MultiAff = _isl.MultiAff
130
+ MultiPwAff = _isl.MultiPwAff
131
+ PwMultiAff = _isl.PwMultiAff
132
+ UnionPwMultiAff = _isl.UnionPwMultiAff
133
+ UnionPwAffList = _isl.UnionPwAffList
134
+ MultiUnionPwAff = _isl.MultiUnionPwAff
135
+ Id = _isl.Id
136
+ MultiId = _isl.MultiId
137
+ Constraint = _isl.Constraint
138
+ Space = _isl.Space
139
+ LocalSpace = _isl.LocalSpace
140
+ BasicSet = _isl.BasicSet
141
+ BasicMap = _isl.BasicMap
142
+ Set = _isl.Set
143
+ Map = _isl.Map
144
+ UnionMap = _isl.UnionMap
145
+ UnionSet = _isl.UnionSet
146
+ Point = _isl.Point
147
+ Vertex = _isl.Vertex
148
+ Cell = _isl.Cell
149
+ Vertices = _isl.Vertices
150
+ StrideInfo = _isl.StrideInfo
151
+ QPolynomialFold = _isl.QPolynomialFold
152
+ PwQPolynomialFold = _isl.PwQPolynomialFold
153
+ UnionPwQPolynomialFold = _isl.UnionPwQPolynomialFold
154
+ UnionPwQPolynomial = _isl.UnionPwQPolynomial
155
+ QPolynomial = _isl.QPolynomial
156
+ PwQPolynomial = _isl.PwQPolynomial
157
+ Term = _isl.Term
158
+ ScheduleConstraints = _isl.ScheduleConstraints
159
+ ScheduleNode = _isl.ScheduleNode
160
+ Schedule = _isl.Schedule
161
+ AccessInfo = _isl.AccessInfo
162
+ Flow = _isl.Flow
163
+ Restriction = _isl.Restriction
164
+ UnionAccessInfo = _isl.UnionAccessInfo
165
+ UnionFlow = _isl.UnionFlow
166
+ AstExpr = _isl.AstExpr
167
+ AstNode = _isl.AstNode
168
+ AstPrintOptions = _isl.AstPrintOptions
169
+ AstBuild = _isl.AstBuild
170
+
171
+ error = _isl.error
172
+ stat = _isl.stat
173
+ dim_type = _isl.dim_type
174
+ schedule_node_type = _isl.schedule_node_type
175
+ ast_expr_op_type = _isl.ast_expr_op_type
176
+ ast_expr_type = _isl.ast_expr_type
177
+ ast_node_type = _isl.ast_node_type
178
+ ast_loop_type = _isl.ast_loop_type
179
+ fold = _isl.fold
180
+ format = _isl.format
181
+ yaml_style = _isl.yaml_style
182
+ bound = _isl.bound
183
+ on_error = _isl.on_error
184
+ schedule_algorithm = _isl.schedule_algorithm
185
+
186
+ # backward compatibility
187
+ ast_op_type = _isl.ast_expr_op_type
188
+
189
+ ALL_CLASSES = [Context, IdList, ValList, BasicSetList, BasicMapList, SetList,
190
+ MapList, UnionSetList, ConstraintList, AffList, PwAffList, AstExprList,
191
+ AstNodeList, IdToAstExpr, Printer, Val, MultiVal, Vec, Mat, Aff, PwAff,
192
+ UnionPwAff, MultiAff, MultiPwAff, PwMultiAff, UnionPwMultiAff,
193
+ UnionPwAffList, MultiUnionPwAff, Id, Constraint, Space, LocalSpace,
194
+ BasicSet, BasicMap, Set, Map, UnionMap, UnionSet, Point, Vertex, Cell,
195
+ Vertices, StrideInfo, QPolynomialFold, PwQPolynomialFold,
196
+ UnionPwQPolynomialFold, UnionPwQPolynomial, QPolynomial, PwQPolynomial,
197
+ Term, ScheduleConstraints, ScheduleNode, Schedule, AccessInfo,
198
+ Flow, Restriction, UnionAccessInfo, UnionFlow, AstExpr, AstNode,
199
+ AstPrintOptions, AstBuild]
200
+
201
+ # }}}
202
+
203
+
204
+ _CHECK_DIM_TYPES = [
205
+ dim_type.in_, dim_type.param, dim_type.set]
206
+
207
+ ALL_CLASSES = tuple(getattr(_isl, cls) for cls in dir(_isl) if cls[0].isupper())
208
+ EXPR_CLASSES = tuple(cls for cls in ALL_CLASSES
209
+ if "Aff" in cls.__name__ or "Polynomial" in cls.__name__)
210
+
211
+ DEFAULT_CONTEXT = Context()
212
+
213
+
214
+ def _get_default_context():
215
+ """A callable to get the default context for the benefit of Python's
216
+ ``__reduce__`` protocol.
217
+ """
218
+ return DEFAULT_CONTEXT
219
+
220
+
221
+ def _read_from_str_wrapper(cls, context, s, dims_with_apostrophes):
222
+ """A callable to reconstitute instances from strings for the benefit
223
+ of Python's ``__reduce__`` protocol.
224
+ """
225
+ cls_from_str = cls.read_from_str(context, s)
226
+
227
+ # Apostrophes in dim names have been lost, put them back
228
+ for dim_name, (dim_type, dim_idx) in dims_with_apostrophes.items():
229
+ cls_from_str = cls_from_str.set_dim_name(dim_type, dim_idx, dim_name)
230
+
231
+ return cls_from_str
232
+
233
+
234
+ def _add_functionality():
235
+ import islpy._isl as _isl # noqa
236
+
237
+ # {{{ dim_type
238
+
239
+ def dim_type_reduce(v):
240
+ return (dim_type, (int(v),))
241
+
242
+ dim_type.__reduce__ = dim_type_reduce
243
+
244
+ # }}}
245
+
246
+ # {{{ Context
247
+
248
+ def context_reduce(self):
249
+ if self._wraps_same_instance_as(DEFAULT_CONTEXT):
250
+ return (_get_default_context, ())
251
+ else:
252
+ return (Context, ())
253
+
254
+ def context_eq(self, other):
255
+ return isinstance(other, Context) and self._wraps_same_instance_as(other)
256
+
257
+ def context_ne(self, other):
258
+ return not self.__eq__(other)
259
+
260
+ Context.__reduce__ = context_reduce
261
+ Context.__eq__ = context_eq
262
+ Context.__ne__ = context_ne
263
+
264
+ # }}}
265
+
266
+ # {{{ generic initialization, pickling
267
+
268
+ def generic_reduce(self):
269
+ ctx = self.get_ctx()
270
+ prn = Printer.to_str(ctx)
271
+ prn = getattr(prn, f"print_{self._base_name}")(self)
272
+
273
+ # Reconstructing from string will remove apostrophes in dim names,
274
+ # so keep track of dim names with apostrophes
275
+ dims_with_apostrophes = {
276
+ dname: pos for dname, pos in self.get_var_dict().items()
277
+ if "'" in dname}
278
+
279
+ return (
280
+ _read_from_str_wrapper,
281
+ (type(self), ctx, prn.get_str(), dims_with_apostrophes))
282
+
283
+ for cls in ALL_CLASSES:
284
+ if hasattr(cls, "read_from_str"):
285
+ cls.__reduce__ = generic_reduce
286
+
287
+ # }}}
288
+
289
+ # {{{ printing
290
+
291
+ def generic_str(self):
292
+ prn = Printer.to_str(self.get_ctx())
293
+ getattr(prn, f"print_{self._base_name}")(self)
294
+ return prn.get_str()
295
+
296
+ def generic_repr(self):
297
+ prn = Printer.to_str(self.get_ctx())
298
+ getattr(prn, f"print_{self._base_name}")(self)
299
+ return f'{type(self).__name__}("{prn.get_str()}")'
300
+
301
+ for cls in ALL_CLASSES:
302
+ if (hasattr(cls, "_base_name")
303
+ and hasattr(Printer, f"print_{cls._base_name}")):
304
+ cls.__str__ = generic_str
305
+ cls.__repr__ = generic_repr
306
+
307
+ if not hasattr(cls, "__hash__"):
308
+ raise AssertionError(f"not hashable: {cls}")
309
+
310
+ # }}}
311
+
312
+ # {{{ Python set-like behavior
313
+
314
+ def obj_or(self, other):
315
+ try:
316
+ return self.union(other)
317
+ except TypeError:
318
+ return NotImplemented
319
+
320
+ def obj_and(self, other):
321
+ try:
322
+ return self.intersect(other)
323
+ except TypeError:
324
+ return NotImplemented
325
+
326
+ def obj_sub(self, other):
327
+ try:
328
+ return self.subtract(other)
329
+ except TypeError:
330
+ return NotImplemented
331
+
332
+ for cls in [BasicSet, BasicMap, Set, Map]:
333
+ cls.__or__ = obj_or
334
+ cls.__ror__ = obj_or
335
+ cls.__and__ = obj_and
336
+ cls.__rand__ = obj_and
337
+ cls.__sub__ = obj_sub
338
+
339
+ # }}}
340
+
341
+ # {{{ Space
342
+
343
+ def space_get_id_dict(self, dimtype=None):
344
+ """Return a dictionary mapping variable :class:`Id` instances to tuples
345
+ of (:class:`dim_type`, index).
346
+
347
+ :param dimtype: None to get all variables, otherwise
348
+ one of :class:`dim_type`.
349
+ """
350
+ result = {}
351
+
352
+ def set_dim_id(name, tp, idx):
353
+ if name in result:
354
+ raise RuntimeError(f"non-unique var id '{name}' encountered")
355
+ result[name] = tp, idx
356
+
357
+ if dimtype is None:
358
+ types = _CHECK_DIM_TYPES
359
+ else:
360
+ types = [dimtype]
361
+
362
+ for tp in types:
363
+ for i in range(self.dim(tp)):
364
+ name = self.get_dim_id(tp, i)
365
+ if name is not None:
366
+ set_dim_id(name, tp, i)
367
+
368
+ return result
369
+
370
+ def space_get_var_dict(self, dimtype=None, ignore_out=False):
371
+ """Return a dictionary mapping variable names to tuples of
372
+ (:class:`dim_type`, index).
373
+
374
+ :param dimtype: None to get all variables, otherwise
375
+ one of :class:`dim_type`.
376
+ """
377
+ result = {}
378
+
379
+ def set_dim_name(name, tp, idx):
380
+ if name in result:
381
+ raise RuntimeError(f"non-unique var name '{name}' encountered")
382
+ result[name] = tp, idx
383
+
384
+ if dimtype is None:
385
+ types = _CHECK_DIM_TYPES
386
+ if ignore_out:
387
+ types = types[:]
388
+ types.remove(dim_type.out)
389
+ else:
390
+ types = [dimtype]
391
+
392
+ for tp in types:
393
+ for i in range(self.dim(tp)):
394
+ name = self.get_dim_name(tp, i)
395
+ if name is not None:
396
+ set_dim_name(name, tp, i)
397
+
398
+ return result
399
+
400
+ def space_create_from_names(ctx, set=None, in_=None, out=None, params=()):
401
+ """Create a :class:`Space` from lists of variable names.
402
+
403
+ :param set_: names of `set`-type variables.
404
+ :param in_: names of `in`-type variables.
405
+ :param out: names of `out`-type variables.
406
+ :param params: names of parameter-type variables.
407
+ """
408
+ dt = dim_type
409
+
410
+ if set is not None:
411
+ if in_ is not None or out is not None:
412
+ raise RuntimeError("must pass only one of set / (in_,out)")
413
+
414
+ result = Space.set_alloc(ctx, nparam=len(params),
415
+ dim=len(set))
416
+
417
+ for i, name in enumerate(set):
418
+ result = result.set_dim_name(dt.set, i, name)
419
+
420
+ elif in_ is not None and out is not None:
421
+ if set is not None:
422
+ raise RuntimeError("must pass only one of set / (in_,out)")
423
+
424
+ result = Space.alloc(ctx, nparam=len(params),
425
+ n_in=len(in_), n_out=len(out))
426
+
427
+ for i, name in enumerate(in_):
428
+ result = result.set_dim_name(dt.in_, i, name)
429
+
430
+ for i, name in enumerate(out):
431
+ result = result.set_dim_name(dt.out, i, name)
432
+ else:
433
+ raise RuntimeError("invalid parameter combination")
434
+
435
+ for i, name in enumerate(params):
436
+ result = result.set_dim_name(dt.param, i, name)
437
+
438
+ return result
439
+
440
+ Space.create_from_names = staticmethod(space_create_from_names)
441
+ Space.get_var_dict = space_get_var_dict
442
+ Space.get_id_dict = space_get_id_dict
443
+
444
+ # }}}
445
+
446
+ # {{{ coefficient wrangling
447
+
448
+ def obj_set_coefficients(self, dim_tp, args):
449
+ """
450
+ :param dim_tp: :class:`dim_type`
451
+ :param args: :class:`list` of coefficients, for indices `0..len(args)-1`.
452
+
453
+ .. versionchanged:: 2011.3
454
+ New for :class:`Aff`
455
+ """
456
+ for i, coeff in enumerate(args):
457
+ self = self.set_coefficient_val(dim_tp, i, coeff)
458
+
459
+ return self
460
+
461
+ def obj_set_coefficients_by_name(self, iterable, name_to_dim=None):
462
+ """Set the coefficients and the constant.
463
+
464
+ :param iterable: a :class:`dict` or iterable of :class:`tuple`
465
+ instances mapping variable names to their coefficients.
466
+ The constant is set to the value of the key '1'.
467
+
468
+ .. versionchanged:: 2011.3
469
+ New for :class:`Aff`
470
+ """
471
+ try:
472
+ iterable = list(iterable.items())
473
+ except AttributeError:
474
+ pass
475
+
476
+ if name_to_dim is None:
477
+ name_to_dim = self.get_space().get_var_dict()
478
+
479
+ for name, coeff in iterable:
480
+ if name == 1:
481
+ self = self.set_constant_val(coeff)
482
+ else:
483
+ tp, idx = name_to_dim[name]
484
+ self = self.set_coefficient_val(tp, idx, coeff)
485
+
486
+ return self
487
+
488
+ def obj_get_coefficients_by_name(self, dimtype=None, dim_to_name=None):
489
+ """Return a dictionary mapping variable names to coefficients.
490
+
491
+ :param dimtype: None to get all variables, otherwise
492
+ one of :class:`dim_type`.
493
+
494
+ .. versionchanged:: 2011.3
495
+ New for :class:`Aff`
496
+ """
497
+ if dimtype is None:
498
+ types = _CHECK_DIM_TYPES
499
+ else:
500
+ types = [dimtype]
501
+
502
+ result = {}
503
+ for tp in types:
504
+ for i in range(self.get_space().dim(tp)):
505
+ coeff = self.get_coefficient_val(tp, i)
506
+ if coeff:
507
+ if dim_to_name is None:
508
+ name = self.get_dim_name(tp, i)
509
+ else:
510
+ name = dim_to_name[tp, i]
511
+
512
+ result[name] = coeff
513
+
514
+ const = self.get_constant_val()
515
+ if const:
516
+ result[1] = const
517
+
518
+ return result
519
+
520
+ for coeff_class in [Constraint, Aff]:
521
+ coeff_class.set_coefficients = obj_set_coefficients
522
+ coeff_class.set_coefficients_by_name = obj_set_coefficients_by_name
523
+ coeff_class.get_coefficients_by_name = obj_get_coefficients_by_name
524
+
525
+ # }}}
526
+
527
+ # {{{ Id
528
+
529
+ Id.user = property(Id.get_user)
530
+ Id.name = property(Id.get_name)
531
+
532
+ # }}}
533
+
534
+ # {{{ Constraint
535
+
536
+ def eq_from_names(space, coefficients=None):
537
+ """Create a constraint `const + coeff_1*var_1 +... == 0`.
538
+
539
+ :param space: :class:`Space`
540
+ :param coefficients: a :class:`dict` or iterable of :class:`tuple`
541
+ instances mapping variable names to their coefficients
542
+ The constant is set to the value of the key '1'.
543
+
544
+ .. versionchanged:: 2011.3
545
+ Eliminated the separate *const* parameter.
546
+ """
547
+ if coefficients is None:
548
+ coefficients = {}
549
+ c = Constraint.equality_alloc(space)
550
+ return c.set_coefficients_by_name(coefficients)
551
+
552
+ def ineq_from_names(space, coefficients=None):
553
+ """Create a constraint `const + coeff_1*var_1 +... >= 0`.
554
+
555
+ :param space: :class:`Space`
556
+ :param coefficients: a :class:`dict` or iterable of :class:`tuple`
557
+ instances mapping variable names to their coefficients
558
+ The constant is set to the value of the key '1'.
559
+
560
+ .. versionchanged:: 2011.3
561
+ Eliminated the separate *const* parameter.
562
+ """
563
+ if coefficients is None:
564
+ coefficients = {}
565
+ c = Constraint.inequality_alloc(space)
566
+ return c.set_coefficients_by_name(coefficients)
567
+
568
+ Constraint.eq_from_names = staticmethod(eq_from_names)
569
+ Constraint.ineq_from_names = staticmethod(ineq_from_names)
570
+
571
+ # }}}
572
+
573
+ def basic_obj_get_constraints(self):
574
+ """Get a list of constraints."""
575
+ result = []
576
+ self.foreach_constraint(result.append)
577
+ return result
578
+
579
+ # {{{ BasicSet
580
+
581
+ BasicSet.get_constraints = basic_obj_get_constraints
582
+
583
+ # }}}
584
+
585
+ # {{{ BasicMap
586
+
587
+ BasicMap.get_constraints = basic_obj_get_constraints
588
+
589
+ # }}}
590
+
591
+ # {{{ Set
592
+
593
+ def set_get_basic_sets(self):
594
+ """Get the list of :class:`BasicSet` instances in this :class:`Set`."""
595
+ result = []
596
+ self.foreach_basic_set(result.append)
597
+ return result
598
+
599
+ Set.get_basic_sets = set_get_basic_sets
600
+ BasicSet.get_basic_sets = set_get_basic_sets
601
+
602
+ # }}}
603
+
604
+ # {{{ Map
605
+
606
+ def map_get_basic_maps(self):
607
+ """Get the list of :class:`BasicMap` instances in this :class:`Map`."""
608
+ result = []
609
+ self.foreach_basic_map(result.append)
610
+ return result
611
+
612
+ Map.get_basic_maps = map_get_basic_maps
613
+
614
+ # }}}
615
+
616
+ # {{{ common functionality
617
+
618
+ def obj_get_id_dict(self, dimtype=None):
619
+ """Return a dictionary mapping :class:`Id` instances to tuples of
620
+ (:class:`dim_type`, index).
621
+
622
+ :param dimtype: None to get all variables, otherwise
623
+ one of :class:`dim_type`.
624
+ """
625
+ return self.get_space().get_id_dict(dimtype)
626
+
627
+ @_memoize_on_first_arg
628
+ def obj_get_var_dict(self, dimtype=None):
629
+ """Return a dictionary mapping variable names to tuples of
630
+ (:class:`dim_type`, index).
631
+
632
+ :param dimtype: None to get all variables, otherwise
633
+ one of :class:`dim_type`.
634
+ """
635
+ return self.get_space().get_var_dict(
636
+ dimtype, ignore_out=isinstance(self, EXPR_CLASSES))
637
+
638
+ def obj_get_var_ids(self, dimtype):
639
+ """Return a list of :class:`Id` instances for :class:`dim_type` *dimtype*."""
640
+ return [self.get_dim_name(dimtype, i) for i in range(self.dim(dimtype))]
641
+
642
+ @_memoize_on_first_arg
643
+ def obj_get_var_names(self, dimtype):
644
+ """Return a list of dim names (in order) for :class:`dim_type` *dimtype*."""
645
+ return [self.get_dim_name(dimtype, i) for i in range(self.dim(dimtype))]
646
+
647
+ for cls in ALL_CLASSES:
648
+ if hasattr(cls, "get_space") and cls is not Space:
649
+ cls.get_id_dict = obj_get_id_dict
650
+ cls.get_var_dict = obj_get_var_dict
651
+ cls.get_var_ids = obj_get_var_ids
652
+ cls.get_var_names = obj_get_var_names
653
+ cls.space = property(cls.get_space)
654
+
655
+ # }}}
656
+
657
+ # {{{ piecewise
658
+
659
+ def pwaff_get_pieces(self):
660
+ """
661
+ :return: list of (:class:`Set`, :class:`Aff`)
662
+ """
663
+
664
+ result = []
665
+
666
+ def append_tuple(*args):
667
+ result.append(args)
668
+
669
+ self.foreach_piece(append_tuple)
670
+ return result
671
+
672
+ def pwqpolynomial_get_pieces(self):
673
+ """
674
+ :return: list of (:class:`Set`, :class:`QPolynomial`)
675
+ """
676
+
677
+ result = []
678
+
679
+ def append_tuple(*args):
680
+ result.append(args)
681
+
682
+ self.foreach_piece(append_tuple)
683
+ return result
684
+
685
+ def pw_get_aggregate_domain(self):
686
+ """
687
+ :return: a :class:`Set` that is the union of the domains of all pieces
688
+ """
689
+
690
+ result = Set.empty(self.get_domain_space())
691
+ for dom, _ in self.get_pieces():
692
+ result = result.union(dom)
693
+
694
+ return result
695
+
696
+ PwAff.get_pieces = pwaff_get_pieces
697
+ Aff.get_pieces = pwaff_get_pieces
698
+ PwAff.get_aggregate_domain = pw_get_aggregate_domain
699
+
700
+ PwQPolynomial.get_pieces = pwqpolynomial_get_pieces
701
+ PwQPolynomial.get_aggregate_domain = pw_get_aggregate_domain
702
+
703
+ # }}}
704
+
705
+ # {{{ QPolynomial
706
+
707
+ def qpolynomial_get_terms(self):
708
+ """Get the list of :class:`Term` instances in this :class:`QPolynomial`."""
709
+ result = []
710
+ self.foreach_term(result.append)
711
+ return result
712
+
713
+ QPolynomial.get_terms = qpolynomial_get_terms
714
+
715
+ # }}}
716
+
717
+ # {{{ PwQPolynomial
718
+
719
+ def pwqpolynomial_eval_with_dict(self, value_dict):
720
+ """Evaluates *self* for the parameters specified by
721
+ *value_dict*, which maps parameter names to their values.
722
+ """
723
+
724
+ pt = Point.zero(self.space.params())
725
+
726
+ for i in range(self.space.dim(dim_type.param)):
727
+ par_name = self.space.get_dim_name(dim_type.param, i)
728
+ pt = pt.set_coordinate_val(
729
+ dim_type.param, i, value_dict[par_name])
730
+
731
+ return self.eval(pt).to_python()
732
+
733
+ PwQPolynomial.eval_with_dict = pwqpolynomial_eval_with_dict
734
+
735
+ # }}}
736
+
737
+ # {{{ arithmetic
738
+
739
+ def _number_to_expr_like(template, num):
740
+ number_aff = Aff.zero_on_domain(template.get_domain_space())
741
+ number_aff = number_aff.set_constant_val(num)
742
+
743
+ if isinstance(template, Aff):
744
+ return number_aff
745
+ if isinstance(template, QPolynomial):
746
+ return QPolynomial.from_aff(number_aff)
747
+
748
+ # everything else is piecewise
749
+
750
+ if template.get_pieces():
751
+ number_pw_aff = PwAff.empty(template.get_space())
752
+ for set, _ in template.get_pieces():
753
+ number_pw_aff = set.indicator_function().cond(
754
+ number_aff, number_pw_aff)
755
+ else:
756
+ number_pw_aff = PwAff.alloc(
757
+ Set.universe(template.domain().space),
758
+ number_aff)
759
+
760
+ if isinstance(template, PwAff):
761
+ return number_pw_aff
762
+
763
+ elif isinstance(template, PwQPolynomial):
764
+ return PwQPolynomial.from_pw_aff(number_pw_aff)
765
+
766
+ else:
767
+ raise TypeError("unexpected template type")
768
+
769
+ ARITH_CLASSES = (Aff, PwAff, QPolynomial, PwQPolynomial) # noqa
770
+
771
+ def expr_like_add(self, other):
772
+ if not isinstance(other, ARITH_CLASSES):
773
+ other = _number_to_expr_like(self, other)
774
+
775
+ try:
776
+ return self.add(other)
777
+ except TypeError:
778
+ return NotImplemented
779
+
780
+ def expr_like_sub(self, other):
781
+ if not isinstance(other, ARITH_CLASSES):
782
+ other = _number_to_expr_like(self, other)
783
+
784
+ try:
785
+ return self.sub(other)
786
+ except TypeError:
787
+ return NotImplemented
788
+
789
+ def expr_like_rsub(self, other):
790
+ if not isinstance(other, ARITH_CLASSES):
791
+ other = _number_to_expr_like(self, other)
792
+
793
+ return -self + other
794
+
795
+ def expr_like_mul(self, other):
796
+ if not isinstance(other, ARITH_CLASSES):
797
+ other = _number_to_expr_like(self, other)
798
+
799
+ try:
800
+ return self.mul(other)
801
+ except TypeError:
802
+ return NotImplemented
803
+
804
+ def expr_like_floordiv(self, other):
805
+ return self.scale_down_val(other).floor()
806
+
807
+ for expr_like_class in ARITH_CLASSES:
808
+ expr_like_class.__add__ = expr_like_add
809
+ expr_like_class.__radd__ = expr_like_add
810
+ expr_like_class.__sub__ = expr_like_sub
811
+ expr_like_class.__rsub__ = expr_like_rsub
812
+ expr_like_class.__mul__ = expr_like_mul
813
+ expr_like_class.__rmul__ = expr_like_mul
814
+ expr_like_class.__neg__ = expr_like_class.neg
815
+
816
+ for qpoly_class in [QPolynomial, PwQPolynomial]:
817
+ qpoly_class.__pow__ = qpoly_class.pow
818
+
819
+ for aff_class in [Aff, PwAff]:
820
+ aff_class.__mod__ = aff_class.mod_val
821
+ aff_class.__floordiv__ = expr_like_floordiv
822
+
823
+ # }}}
824
+
825
+ # {{{ Val
826
+
827
+ def val_rsub(self, other):
828
+ return -self + other
829
+
830
+ def val_bool(self):
831
+ return not self.is_zero()
832
+
833
+ def val_repr(self):
834
+ return f'{type(self).__name__}("{self.to_str()}")'
835
+
836
+ def val_to_python(self):
837
+ if not self.is_int():
838
+ raise ValueError("can only convert integer Val to python")
839
+
840
+ return int(self.to_str())
841
+
842
+ Val.__add__ = Val.add
843
+ Val.__radd__ = Val.add
844
+ Val.__sub__ = Val.sub
845
+ Val.__rsub__ = val_rsub
846
+ Val.__mul__ = Val.mul
847
+ Val.__rmul__ = Val.mul
848
+ Val.__neg__ = Val.neg
849
+ Val.__mod__ = Val.mod
850
+ Val.__bool__ = Val.__nonzero__ = val_bool
851
+
852
+ Val.__lt__ = Val.lt
853
+ Val.__gt__ = Val.gt
854
+ Val.__le__ = Val.le
855
+ Val.__ge__ = Val.ge
856
+ Val.__eq__ = Val.eq
857
+ Val.__ne__ = Val.ne
858
+
859
+ Val.__repr__ = val_repr
860
+ Val.__str__ = Val.to_str
861
+ Val.to_python = val_to_python
862
+
863
+ # }}}
864
+
865
+ # {{{ rich comparisons
866
+
867
+ def obj_eq(self, other):
868
+ assert self.get_ctx() == other.get_ctx(), (
869
+ "Equality-comparing two objects from different ISL Contexts "
870
+ "will likely lead to entertaining (but never useful) results. "
871
+ "In particular, Spaces with matching names will no longer be "
872
+ "equal.")
873
+
874
+ return self.is_equal(other)
875
+
876
+ def obj_ne(self, other):
877
+ return not self.__eq__(other)
878
+
879
+ for cls in ALL_CLASSES:
880
+ if hasattr(cls, "is_equal"):
881
+ cls.__eq__ = obj_eq
882
+ cls.__ne__ = obj_ne
883
+
884
+ def obj_lt(self, other):
885
+ return self.is_strict_subset(other)
886
+
887
+ def obj_le(self, other):
888
+ return self.is_subset(other)
889
+
890
+ def obj_gt(self, other):
891
+ return other.is_strict_subset(self)
892
+
893
+ def obj_ge(self, other):
894
+ return other.is_subset(self)
895
+
896
+ for cls in [BasicSet, BasicMap, Set, Map]:
897
+ cls.__lt__ = obj_lt
898
+ cls.__le__ = obj_le
899
+ cls.__gt__ = obj_gt
900
+ cls.__ge__ = obj_ge
901
+
902
+ # }}}
903
+
904
+ # {{{ project_out_except
905
+
906
+ def obj_project_out_except(obj, names, types):
907
+ """
908
+ :param types: list of :class:`dim_type` determining
909
+ the types of axes to project out
910
+ :param names: names of axes matching the above which
911
+ should be left alone by the projection
912
+
913
+ .. versionadded:: 2011.3
914
+ """
915
+
916
+ for tp in types:
917
+ while True:
918
+ space = obj.get_space()
919
+ var_dict = space.get_var_dict(tp)
920
+
921
+ all_indices = set(range(space.dim(tp)))
922
+ leftover_indices = {var_dict[name][1] for name in names
923
+ if name in var_dict}
924
+ project_indices = all_indices-leftover_indices
925
+ if not project_indices:
926
+ break
927
+
928
+ min_index = min(project_indices)
929
+ count = 1
930
+ while min_index+count in project_indices:
931
+ count += 1
932
+
933
+ obj = obj.project_out(tp, min_index, count)
934
+
935
+ return obj
936
+
937
+ # }}}
938
+
939
+ # {{{ eliminate_except
940
+
941
+ def obj_eliminate_except(obj, names, types):
942
+ """
943
+ :param types: list of :class:`dim_type` determining
944
+ the types of axes to eliminate
945
+ :param names: names of axes matching the above which
946
+ should be left alone by the eliminate
947
+
948
+ .. versionadded:: 2011.3
949
+ """
950
+
951
+ for tp in types:
952
+ space = obj.get_space()
953
+ var_dict = space.get_var_dict(tp)
954
+ to_eliminate = (
955
+ set(range(space.dim(tp)))
956
+ - {var_dict[name][1] for name in names
957
+ if name in var_dict})
958
+
959
+ while to_eliminate:
960
+ min_index = min(to_eliminate)
961
+ count = 1
962
+ while min_index+count in to_eliminate:
963
+ count += 1
964
+
965
+ obj = obj.eliminate(tp, min_index, count)
966
+
967
+ to_eliminate -= set(range(min_index, min_index+count))
968
+
969
+ return obj
970
+
971
+ # }}}
972
+
973
+ # {{{ add_constraints
974
+
975
+ def obj_add_constraints(obj, constraints):
976
+ """
977
+ .. versionadded:: 2011.3
978
+ """
979
+
980
+ for cns in constraints:
981
+ obj = obj.add_constraint(cns)
982
+
983
+ return obj
984
+
985
+ # }}}
986
+
987
+ for c in [BasicSet, BasicMap, Set, Map]:
988
+ c.project_out_except = obj_project_out_except
989
+ c.add_constraints = obj_add_constraints
990
+
991
+ for c in [BasicSet, Set]:
992
+ c.eliminate_except = obj_eliminate_except
993
+
994
+
995
+ _add_functionality()
996
+
997
+
998
+ def _back_to_basic(new_obj, old_obj):
999
+ # Work around set_dim_id not being available for Basic{Set,Map}
1000
+ if isinstance(old_obj, BasicSet) and isinstance(new_obj, Set):
1001
+ bsets = new_obj.get_basic_sets()
1002
+
1003
+ if len(bsets) == 0:
1004
+ bset = BasicSet.universe(new_obj.space).complement()
1005
+ else:
1006
+ bset, = bsets
1007
+
1008
+ return bset
1009
+
1010
+ if isinstance(old_obj, BasicMap) and isinstance(new_obj, Map):
1011
+ bmaps = new_obj.get_basic_maps()
1012
+
1013
+ if len(bmaps) == 0:
1014
+ bmap = BasicMap.universe(new_obj.space).complement()
1015
+ else:
1016
+ bmap, = bmaps
1017
+
1018
+ return bmap
1019
+
1020
+ return new_obj
1021
+
1022
+
1023
+ def _set_dim_id(obj, dt, idx, id):
1024
+ return _back_to_basic(obj.set_dim_id(dt, idx, id), obj)
1025
+
1026
+
1027
+ def _align_dim_type(template_dt, obj, template, obj_bigger_ok, obj_names,
1028
+ template_names):
1029
+
1030
+ # {{{ deal with Aff, PwAff
1031
+
1032
+ # The technique below will not work for PwAff et al, because there is *only*
1033
+ # the 'param' dim_type, and we are not allowed to move dims around in there.
1034
+ # We'll make isl do the work, using align_params.
1035
+
1036
+ if template_dt == dim_type.param and isinstance(obj, (Aff, PwAff)):
1037
+ if not isinstance(template, Space):
1038
+ template_space = template.space
1039
+ else:
1040
+ template_space = template
1041
+
1042
+ if not obj_bigger_ok:
1043
+ if (obj.dim(template_dt) > template.dim(template_dt)
1044
+ or not set(obj.get_var_dict()) <= set(template.get_var_dict())):
1045
+ raise Error("obj has leftover dimensions after alignment")
1046
+ return obj.align_params(template_space)
1047
+
1048
+ # }}}
1049
+
1050
+ if None in template_names:
1051
+ all_nones = [None] * len(template_names)
1052
+ if template_names == all_nones and obj_names == all_nones:
1053
+ # that's ok
1054
+ return obj
1055
+
1056
+ raise Error("template may not contain any unnamed dimensions")
1057
+
1058
+ obj_names = set(obj_names) - {None}
1059
+ template_names = set(template_names) - {None}
1060
+
1061
+ names_in_both = obj_names & template_names
1062
+
1063
+ tgt_idx = 0
1064
+ while tgt_idx < template.dim(template_dt):
1065
+ tgt_id = template.get_dim_id(template_dt, tgt_idx)
1066
+ tgt_name = tgt_id.name
1067
+
1068
+ if tgt_name in names_in_both:
1069
+ if (obj.dim(template_dt) > tgt_idx
1070
+ and tgt_name == obj.get_dim_name(template_dt, tgt_idx)):
1071
+ pass
1072
+
1073
+ else:
1074
+ src_dt, src_idx = obj.get_var_dict()[tgt_name]
1075
+
1076
+ if src_dt == template_dt:
1077
+ assert src_idx > tgt_idx
1078
+
1079
+ # isl requires move_dims to be between different types.
1080
+ # Not sure why. Let's make it happy.
1081
+ other_dt = dim_type.param
1082
+ if src_dt == other_dt:
1083
+ other_dt = dim_type.out
1084
+
1085
+ other_dt_dim = obj.dim(other_dt)
1086
+ obj = obj.move_dims(other_dt, other_dt_dim, src_dt, src_idx, 1)
1087
+ obj = obj.move_dims(
1088
+ template_dt, tgt_idx, other_dt, other_dt_dim, 1)
1089
+ else:
1090
+ obj = obj.move_dims(template_dt, tgt_idx, src_dt, src_idx, 1)
1091
+
1092
+ # names are same, make Ids the same, too
1093
+ obj = _set_dim_id(obj, template_dt, tgt_idx, tgt_id)
1094
+
1095
+ tgt_idx += 1
1096
+ else:
1097
+ obj = obj.insert_dims(template_dt, tgt_idx, 1)
1098
+ obj = _set_dim_id(obj, template_dt, tgt_idx, tgt_id)
1099
+
1100
+ tgt_idx += 1
1101
+
1102
+ if tgt_idx < obj.dim(template_dt) and not obj_bigger_ok:
1103
+ raise Error("obj has leftover dimensions after alignment")
1104
+
1105
+ return obj
1106
+
1107
+
1108
+ def align_spaces(obj, template, obj_bigger_ok=False, across_dim_types=None):
1109
+ """
1110
+ Try to make the space in which *obj* lives the same as that of *template* by
1111
+ adding/matching named dimensions.
1112
+
1113
+ :param obj_bigger_ok: If *True*, no error is raised if the resulting *obj*
1114
+ has more dimensions than *template*.
1115
+ """
1116
+
1117
+ if across_dim_types is not None:
1118
+ from warnings import warn
1119
+ warn("across_dim_types is deprecated and should no longer be used. "
1120
+ "It never had any effect anyway.",
1121
+ DeprecationWarning, stacklevel=2)
1122
+
1123
+ have_any_param_domains = (
1124
+ isinstance(obj, (Set, BasicSet))
1125
+ and isinstance(template, (Set, BasicSet))
1126
+ and (obj.is_params() or template.is_params()))
1127
+ if have_any_param_domains:
1128
+ if obj.is_params():
1129
+ obj = type(obj).from_params(obj)
1130
+ if template.is_params():
1131
+ template = type(template).from_params(template)
1132
+
1133
+ if isinstance(template, EXPR_CLASSES):
1134
+ dim_types = _CHECK_DIM_TYPES[:]
1135
+ dim_types.remove(dim_type.out)
1136
+ else:
1137
+ dim_types = _CHECK_DIM_TYPES
1138
+
1139
+ obj_names = [
1140
+ obj.get_dim_name(dt, i)
1141
+ for dt in dim_types
1142
+ for i in range(obj.dim(dt))
1143
+ ]
1144
+ template_names = [
1145
+ template.get_dim_name(dt, i)
1146
+ for dt in dim_types
1147
+ for i in range(template.dim(dt))
1148
+ ]
1149
+
1150
+ for dt in dim_types:
1151
+ obj = _align_dim_type(
1152
+ dt, obj, template, obj_bigger_ok, obj_names, template_names)
1153
+
1154
+ return obj
1155
+
1156
+
1157
+ def align_two(obj1, obj2, across_dim_types=None):
1158
+ """Align the spaces of two objects, potentially modifying both of them.
1159
+
1160
+ See also :func:`align_spaces`.
1161
+ """
1162
+
1163
+ if across_dim_types is not None:
1164
+ from warnings import warn
1165
+ warn("across_dim_types is deprecated and should no longer be used. "
1166
+ "It never had any effect anyway.",
1167
+ DeprecationWarning, stacklevel=2)
1168
+
1169
+ obj1 = align_spaces(obj1, obj2, obj_bigger_ok=True)
1170
+ obj2 = align_spaces(obj2, obj1, obj_bigger_ok=True)
1171
+ return (obj1, obj2)
1172
+
1173
+
1174
+ def make_zero_and_vars(set_vars, params=(), ctx=None):
1175
+ """
1176
+ :arg set_vars: an iterable of variable names, or a comma-separated string
1177
+ :arg params: an iterable of variable names, or a comma-separated string
1178
+
1179
+ :return: a dictionary from variable names (in *set_vars* and *params*)
1180
+ to :class:`PwAff` instances that represent each of the
1181
+ variables. They key '0' is also include and represents
1182
+ a :class:`PwAff` zero constant.
1183
+
1184
+ .. versionadded:: 2016.1.1
1185
+
1186
+ This function is intended to make it relatively easy to construct sets
1187
+ programmatically without resorting to string manipulation.
1188
+
1189
+ Usage example::
1190
+
1191
+ v = isl.make_zero_and_vars("i,j,k", "n")
1192
+
1193
+ myset = (
1194
+ v[0].le_set(v["i"] + v["j"])
1195
+ &
1196
+ (v["i"] + v["j"]).lt_set(v["n"])
1197
+ &
1198
+ (v[0].le_set(v["i"]))
1199
+ &
1200
+ (v["i"].le_set(13 + v["n"]))
1201
+ )
1202
+ """
1203
+ if ctx is None:
1204
+ ctx = DEFAULT_CONTEXT
1205
+
1206
+ if isinstance(set_vars, str):
1207
+ set_vars = [s.strip() for s in set_vars.split(",")]
1208
+ if isinstance(params, str):
1209
+ params = [s.strip() for s in params.split(",")]
1210
+
1211
+ space = Space.create_from_names(ctx, set=set_vars, params=params)
1212
+ return affs_from_space(space)
1213
+
1214
+
1215
+ def affs_from_space(space):
1216
+ """
1217
+ :return: a dictionary from variable names (in *set_vars* and *params*)
1218
+ to :class:`PwAff` instances that represent each of the
1219
+ variables *in*space*. They key '0' is also include and represents
1220
+ a :class:`PwAff` zero constant.
1221
+
1222
+ .. versionadded:: 2016.2
1223
+
1224
+ This function is intended to make it relatively easy to construct sets
1225
+ programmatically without resorting to string manipulation.
1226
+
1227
+ Usage example::
1228
+
1229
+ s = isl.Set("[n] -> {[i,j,k]: 0<=i,j,k<n}")
1230
+ v = isl.affs_from_space(s.space)
1231
+
1232
+ myset = (
1233
+ v[0].le_set(v["i"] + v["j"])
1234
+ &
1235
+ (v["i"] + v["j"]).lt_set(v["n"])
1236
+ &
1237
+ (v[0].le_set(v["i"]))
1238
+ &
1239
+ (v["i"].le_set(13 + v["n"]))
1240
+ )
1241
+ """
1242
+
1243
+ result = {}
1244
+
1245
+ zero = Aff.zero_on_domain(LocalSpace.from_space(space))
1246
+ result[0] = PwAff.from_aff(zero)
1247
+
1248
+ var_dict = zero.get_var_dict()
1249
+ for name, (dt, idx) in var_dict.items():
1250
+ result[name] = PwAff.from_aff(zero.set_coefficient_val(dt, idx, 1))
1251
+
1252
+ return result
1253
+
1254
+
1255
+ class SuppressedWarnings:
1256
+ def __init__(self, ctx):
1257
+ from warnings import warn
1258
+ warn("islpy.SuppressedWarnings is a deprecated no-op and will be removed "
1259
+ "in 2023. Simply remove the use of it to avoid this warning.",
1260
+ DeprecationWarning, stacklevel=1)
1261
+
1262
+ def __enter__(self):
1263
+ pass
1264
+
1265
+ def __exit__(self, type, value, traceback):
1266
+ pass
1267
+
1268
+
1269
+ # {{{ give sphinx something to import so we can produce docs
1270
+
1271
+ def _define_doc_link_names():
1272
+ class Div:
1273
+ pass
1274
+
1275
+ _isl.Div = Div
1276
+
1277
+
1278
+ _define_doc_link_names()
1279
+
1280
+ # }}}
1281
+
1282
+
1283
+ # vim: foldmethod=marker
islpy/version.py ADDED
@@ -0,0 +1,2 @@
1
+ VERSION = (2024, 2)
2
+ VERSION_TEXT = ".".join(str(i) for i in VERSION)
@@ -0,0 +1,73 @@
1
+ Metadata-Version: 2.1
2
+ Name: islpy
3
+ Version: 2024.2
4
+ Summary: Wrapper around isl, an integer set library
5
+ Home-page: http://documen.tician.de/islpy
6
+ Author: Andreas Kloeckner
7
+ Author-email: inform@tiker.net
8
+ License: MIT
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Intended Audience :: Other Audience
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Natural Language :: English
15
+ Classifier: Programming Language :: C++
16
+ Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
19
+ Classifier: Topic :: Scientific/Engineering
20
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
21
+ Classifier: Topic :: Scientific/Engineering :: Physics
22
+ Classifier: Topic :: Scientific/Engineering :: Visualization
23
+ Classifier: Topic :: Software Development :: Libraries
24
+ Requires-Python: ~=3.8
25
+ Provides-Extra: test
26
+ Requires-Dist: pytest>=2; extra == "test"
27
+
28
+ islpy: Polyhedral Analysis from Python
29
+ ======================================
30
+
31
+ .. image:: https://gitlab.tiker.net/inducer/islpy/badges/main/pipeline.svg
32
+ :alt: Gitlab Build Status
33
+ :target: https://gitlab.tiker.net/inducer/islpy/commits/main
34
+ .. image:: https://github.com/inducer/islpy/workflows/CI/badge.svg?branch=main&event=push
35
+ :alt: Github Build Status
36
+ :target: https://github.com/inducer/islpy/actions?query=branch%3Amain+workflow%3ACI+event%3Apush
37
+ .. image:: https://badge.fury.io/py/islpy.svg
38
+ :alt: Python Package Index Release Page
39
+ :target: https://pypi.org/project/islpy/
40
+ .. image:: https://zenodo.org/badge/2021524.svg
41
+ :alt: Zenodo DOI for latest release
42
+ :target: https://zenodo.org/badge/latestdoi/2021524
43
+
44
+ islpy is a Python wrapper around Sven Verdoolaege's `isl
45
+ <https://libisl.sourceforge.io/>`_, a library for manipulating sets and
46
+ relations of integer points bounded by linear constraints.
47
+
48
+ Supported operations on sets include
49
+
50
+ * intersection, union, set difference,
51
+ * emptiness check,
52
+ * convex hull,
53
+ * (integer) affine hull,
54
+ * integer projection,
55
+ * computing the lexicographic minimum using parametric integer programming,
56
+ * coalescing, and
57
+ * parametric vertex enumeration.
58
+
59
+ It also includes an ILP solver based on generalized basis reduction, transitive
60
+ closures on maps (which may encode infinite graphs), dependence analysis and
61
+ bounds on piecewise step-polynomials.
62
+
63
+ Islpy comes with comprehensive `documentation <http://documen.tician.de/islpy>`_.
64
+
65
+ *Requirements:* islpy needs a C++ compiler to build. It can optionally make use
66
+ of GMP for support of large integers.
67
+
68
+ One important thing to know about islpy is that it exposes every function in isl
69
+ that is visible in the headers, not just what isl's authors consider its
70
+ documented, public API (marked by ``__isl_export``). These (technically)
71
+ undocumented functions are marked in the islpy documentation. Many of them are useful
72
+ and essential for certain operations, but isl's API stability guarantees do not
73
+ apply to them. Use them at your own risk.
@@ -0,0 +1,7 @@
1
+ islpy/__init__.py,sha256=6380Da-Rvz_PxL-kmorbUtkdBaH9_XDF38ziESK6q3U,38066
2
+ islpy/version.py,sha256=GIrFDi1EGoev0c3vbRgeQwCmQCUsa_l35IlliuGaTLU,69
3
+ islpy/_isl.cpython-38-x86_64-linux-gnu.so,sha256=K-7nr8PiMmCBs-BHV3yE-lT2CRaw5VHx-UPOilkgevE,10170904
4
+ islpy-2024.2.dist-info/METADATA,sha256=lq6OJ8w6D6toAOYmNbAuqZYu569KwHIvTeZYuQt8gEU,3099
5
+ islpy-2024.2.dist-info/top_level.txt,sha256=txVjJJ85Sa3IMOF6WOh_bTkOyRDWiSW2kQOf8vSPb6M,6
6
+ islpy-2024.2.dist-info/RECORD,,
7
+ islpy-2024.2.dist-info/WHEEL,sha256=2HV5PGZ8TH1n812GS7W5MojrVTaui_zeH1HPlBU7Fe4,105
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: skbuild 0.18.1
3
+ Root-Is-Purelib: false
4
+ Tag: cp38-cp38-musllinux_1_2_x86_64
5
+
@@ -0,0 +1 @@
1
+ islpy