Skip to content

Commit 81fbffe

Browse files
committed
first sketch for callable factorisations
1 parent 1ca4a47 commit 81fbffe

File tree

1 file changed

+72
-35
lines changed

1 file changed

+72
-35
lines changed

src/sage/structure/factorization.py

Lines changed: 72 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -173,15 +173,15 @@
173173
universe functions
174174
"""
175175

176-
#*****************************************************************************
176+
# ****************************************************************************
177177
# Copyright (C) 2005 William Stein <[email protected]>
178178
#
179179
# This program is free software: you can redistribute it and/or modify
180180
# it under the terms of the GNU General Public License as published by
181181
# the Free Software Foundation, either version 2 of the License, or
182182
# (at your option) any later version.
183-
# http://www.gnu.org/licenses/
184-
#*****************************************************************************
183+
# https://www.gnu.org/licenses/
184+
# ****************************************************************************
185185

186186
from sage.structure.sage_object import SageObject
187187
from sage.structure.element import Element
@@ -465,7 +465,7 @@ def __copy__(self):
465465
# No need to sort, since the factorization is already sorted
466466
# in whatever order is desired.
467467
return Factorization(self.__x, unit=self.__unit, cr=self.__cr,
468-
sort=False, simplify=False)
468+
sort=False, simplify=False)
469469

470470
def __deepcopy__(self, memo):
471471
r"""
@@ -567,9 +567,9 @@ def base_change(self, U):
567567
try:
568568
return Factorization([(U(f[0]), f[1]) for f in list(self)], unit=U(self.unit()))
569569
except TypeError:
570-
raise TypeError("Impossible to coerce the factors of %s into %s"%(self, U))
570+
raise TypeError("Impossible to coerce the factors of %s into %s" % (self, U))
571571

572-
def is_commutative(self):
572+
def is_commutative(self) -> bool:
573573
"""
574574
Return True if my factors commute.
575575
@@ -837,17 +837,17 @@ def _repr_(self):
837837
n = self.__x[i][1]
838838
if not atomic and (n != 1 or len(self) > 1 or self.__unit != one):
839839
if '+' in t or '-' in t or ' ' in t:
840-
t = '(%s)'%t
840+
t = '(%s)' % t
841841
if n != 1:
842-
t += '^%s'%n
842+
t += '^%s' % n
843843
s += t
844-
if i < len(self)-1:
844+
if i < len(self) - 1:
845845
s += mul
846846
if self.__unit != one:
847847
if atomic:
848848
u = repr(self.__unit)
849849
else:
850-
u = '(%s)'%self.__unit
850+
u = '(%s)' % self.__unit
851851
s = u + mul + s
852852
return s
853853

@@ -877,18 +877,18 @@ def _latex_(self):
877877
for i in range(len(self)):
878878
t = self.__x[i][0]._latex_()
879879
if not atomic and ('+' in t or '-' in t or ' ' in t):
880-
t = '(%s)'%t
880+
t = '(%s)' % t
881881
n = self.__x[i][1]
882882
if n != 1:
883-
t += '^{%s}'%n
883+
t += '^{%s}' % n
884884
s += t
885-
if i < len(self)-1:
885+
if i < len(self) - 1:
886886
s += ' \\cdot '
887887
if self.__unit != 1:
888888
if atomic:
889889
u = self.__unit._latex_()
890890
else:
891-
u = '\\left(%s\\right)'%self.__unit._latex_()
891+
u = '\\left(%s\\right)' % self.__unit._latex_()
892892
s = u + ' \\cdot ' + s
893893
return s
894894

@@ -1073,17 +1073,17 @@ def __mul__(self, other):
10731073
self = self.base_change(U)
10741074
other = other.base_change(U)
10751075
except TypeError:
1076-
raise TypeError("Cannot multiply %s and %s because they cannot be coerced into a common universe"%(self,other))
1076+
raise TypeError("Cannot multiply %s and %s because they cannot be coerced into a common universe" % (self, other))
10771077

10781078
if self.is_commutative() and other.is_commutative():
10791079
d1 = dict(self)
10801080
d2 = dict(other)
10811081
s = {}
10821082
for a in set(d1).union(set(d2)):
1083-
s[a] = d1.get(a,0) + d2.get(a,0)
1084-
return Factorization(list(s.items()), unit=self.unit()*other.unit())
1083+
s[a] = d1.get(a, 0) + d2.get(a, 0)
1084+
return Factorization(list(s.items()), unit=self.unit() * other.unit())
10851085
else:
1086-
return Factorization(list(self) + list(other), unit=self.unit()*other.unit())
1086+
return Factorization(list(self) + list(other), unit=self.unit() * other.unit())
10871087

10881088
def __pow__(self, n):
10891089
"""
@@ -1123,7 +1123,8 @@ def __pow__(self, n):
11231123
if n == 0:
11241124
return Factorization([])
11251125
if self.is_commutative():
1126-
return Factorization([(p, n*e) for p, e in self], unit=self.unit()**n, cr=self.__cr, sort=False, simplify=False)
1126+
return Factorization([(p, n * e) for p, e in self], unit=self.unit()**n,
1127+
cr=self.__cr, sort=False, simplify=False)
11271128
if n < 0:
11281129
self = ~self
11291130
n = -n
@@ -1147,8 +1148,8 @@ def __invert__(self):
11471148
sage: F^-1 # optional - sage.combinat sage.modules
11481149
(1/2) * x^-1 * y^-2 * x^-3
11491150
"""
1150-
return Factorization([(p,-e) for p,e in reversed(self)],
1151-
cr=self._cr(), unit=self.unit()**(-1))
1151+
return Factorization([(p, -e) for p, e in reversed(self)],
1152+
cr=self._cr(), unit=self.unit()**(-1))
11521153

11531154
def __truediv__(self, other):
11541155
r"""
@@ -1174,6 +1175,41 @@ def __truediv__(self, other):
11741175
return self / Factorization([(other, 1)])
11751176
return self * other**-1
11761177

1178+
def __call__(self, *args, **kwds):
1179+
"""
1180+
Implement the substitution.
1181+
1182+
There is another mechanism for substitution
1183+
in symbolic products.
1184+
1185+
EXAMPLES::
1186+
1187+
sage: R.<x,y> = FreeAlgebra(QQ, 2) # optional - sage.combinat sage.modules
1188+
sage: F = Factorization([(x,3), (y, 2), (x,1)]) # optional - sage.combinat sage.modules
1189+
sage: F(x=4) # optional - sage.combinat sage.modules
1190+
(1) * 4^3 * y^2 * 4
1191+
sage: F.subs({y:2}) # optional - sage.combinat sage.modules
1192+
x^3 * 2^2 * x
1193+
1194+
sage: R.<x,y> = PolynomialRing(QQ, 2)
1195+
sage: F = Factorization([(x,3), (y, 2), (x,1)])
1196+
sage: F(x=4)
1197+
4 * 4^3 * y^2
1198+
sage: F.subs({y:x})
1199+
x * x^2 * x^3
1200+
sage: F(x=y+x)
1201+
(x + y) * y^2 * (x + y)^3
1202+
"""
1203+
unit = self.__unit.subs(*args, **kwds)
1204+
if unit == 0:
1205+
return self.universe().zero()
1206+
data = [(p.subs(*args, **kwds), e) for p, e in self.__x]
1207+
if any(p == 0 for p, _ in data):
1208+
return self.universe().zero()
1209+
return Factorization(data, unit=unit, simplify=False)
1210+
1211+
subs = __call__
1212+
11771213
def value(self):
11781214
"""
11791215
Return the product of the factors in the factorization, multiplied out.
@@ -1196,7 +1232,7 @@ def value(self):
11961232

11971233
# Two aliases for ``value(self)``.
11981234
expand = value
1199-
prod = value
1235+
prod = value
12001236

12011237
def gcd(self, other):
12021238
r"""
@@ -1228,14 +1264,14 @@ def gcd(self, other):
12281264
self = self.base_change(U)
12291265
other = other.base_change(U)
12301266
except TypeError:
1231-
raise TypeError("Cannot take the gcd of %s and %s because they cannot be coerced into a common universe"%(self,other))
1267+
raise TypeError("Cannot take the gcd of %s and %s because they cannot be coerced into a common universe" % (self, other))
12321268

12331269
if self.is_commutative() and other.is_commutative():
12341270
d1 = dict(self)
12351271
d2 = dict(other)
12361272
s = {}
12371273
for a in set(d1).intersection(set(d2)):
1238-
s[a] = min(d1[a],d2[a])
1274+
s[a] = min(d1[a], d2[a])
12391275
return Factorization(list(s.items()))
12401276
else:
12411277
raise NotImplementedError("gcd is not implemented for non-commutative factorizations")
@@ -1270,19 +1306,19 @@ def lcm(self, other):
12701306
self = self.base_change(U)
12711307
other = other.base_change(U)
12721308
except TypeError:
1273-
raise TypeError("Cannot take the lcm of %s and %s because they cannot be coerced into a common universe"%(self,other))
1309+
raise TypeError("Cannot take the lcm of %s and %s because they cannot be coerced into a common universe" % (self, other))
12741310

12751311
if self.is_commutative() and other.is_commutative():
12761312
d1 = dict(self)
12771313
d2 = dict(other)
12781314
s = {}
12791315
for a in set(d1).union(set(d2)):
1280-
s[a] = max(d1.get(a,0),d2.get(a,0))
1316+
s[a] = max(d1.get(a, 0), d2.get(a, 0))
12811317
return Factorization(list(s.items()))
12821318
else:
12831319
raise NotImplementedError("lcm is not implemented for non-commutative factorizations")
12841320

1285-
def is_integral(self):
1321+
def is_integral(self) -> bool:
12861322
r"""
12871323
Return True iff all exponents of this Factorization are non-negative.
12881324
@@ -1318,11 +1354,12 @@ def radical(self):
13181354
sage: factor(1/2).radical()
13191355
Traceback (most recent call last):
13201356
...
1321-
ValueError: All exponents in the factorization must be positive.
1357+
ValueError: all exponents in the factorization must be positive
13221358
"""
1323-
if not all(e > 0 for p, e in self.__x):
1324-
raise ValueError("All exponents in the factorization must be positive.")
1325-
return Factorization([(p,1) for p,e in self.__x], unit=self.unit().parent()(1), cr=self.__cr, sort=False, simplify=False)
1359+
if not all(e > 0 for _, e in self.__x):
1360+
raise ValueError("all exponents in the factorization must be positive")
1361+
return Factorization([(p, 1) for p, e in self.__x], unit=self.unit().parent()(1),
1362+
cr=self.__cr, sort=False, simplify=False)
13261363

13271364
def radical_value(self):
13281365
"""
@@ -1343,9 +1380,9 @@ def radical_value(self):
13431380
sage: factor(1/2).radical_value()
13441381
Traceback (most recent call last):
13451382
...
1346-
ValueError: All exponents in the factorization must be positive.
1383+
ValueError: all exponents in the factorization must be positive
13471384
"""
1348-
if not all(e > 0 for p, e in self.__x):
1349-
raise ValueError("All exponents in the factorization must be positive.")
1385+
if not all(e > 0 for _, e in self.__x):
1386+
raise ValueError("all exponents in the factorization must be positive")
13501387
from sage.misc.misc_c import prod
1351-
return prod([p for p, e in self.__x])
1388+
return prod([p for p, _ in self.__x])

0 commit comments

Comments
 (0)