Skip to content

Commit 662e06d

Browse files
committed
New deflation functions
1 parent 2f9c24f commit 662e06d

6 files changed

Lines changed: 503 additions & 73 deletions

File tree

src/flint/flintlib/nmod_mpoly.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,4 @@ cdef extern from "flint/nmod_mpoly.h":
161161
# These functions seem to be undocumented but appear in the header.
162162
void nmod_mpoly_deflation(fmpz_struct * shift, fmpz_struct * stride, const nmod_mpoly_t A, const nmod_mpoly_ctx_t ctx)
163163
void nmod_mpoly_deflate(nmod_mpoly_t A, const nmod_mpoly_t B, const fmpz_struct * shift, const fmpz_struct * stride, const nmod_mpoly_ctx_t ctx)
164+
void nmod_mpoly_inflate(nmod_mpoly_t A, const nmod_mpoly_t B, const fmpz_struct * shift, const fmpz_struct * stride, const nmod_mpoly_ctx_t ctx)

src/flint/types/fmpq_mpoly.pyx

Lines changed: 126 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ from flint.flintlib.fmpq_mpoly cimport (
4747
fmpq_mpoly_neg,
4848
fmpq_mpoly_pow_fmpz,
4949
fmpq_mpoly_push_term_fmpq_ffmpz,
50+
fmpq_mpoly_push_term_ui_ffmpz,
5051
fmpq_mpoly_reduce,
5152
fmpq_mpoly_resultant,
5253
fmpq_mpoly_scalar_div_fmpq,
@@ -74,7 +75,8 @@ from flint.flintlib.fmpz cimport fmpz_init_set
7475
from flint.flintlib.fmpz_mpoly cimport (
7576
fmpz_mpoly_set,
7677
fmpz_mpoly_deflate,
77-
fmpz_mpoly_deflation
78+
fmpz_mpoly_deflation,
79+
fmpz_mpoly_inflate,
7880
)
7981

8082
from cpython.object cimport Py_EQ, Py_NE
@@ -994,28 +996,142 @@ cdef class fmpq_mpoly(flint_mpoly):
994996
fmpq_mpoly_integral(res.val, self.val, i, self.ctx.val)
995997
return res
996998

997-
def deflation(self):
999+
def inflate(self, N: list[int]) -> fmpq_mpoly:
9981000
"""
999-
Compute the deflation of ``self``. See Flint documentation for
1000-
details. Returns deflated polynomial and the stride vector.
1001+
Compute the inflation of ``self`` for a provided ``N``, that is return ``q``
1002+
such that ``q(X) = p(X^N)``.
1003+
1004+
>>> from flint import Ordering
1005+
>>> ctx = fmpq_mpoly_ctx.get_context(2, Ordering.lex, nametup=('x', 'y'))
1006+
>>> x, y = ctx.gens()
1007+
>>> f = x + y + 1
1008+
>>> f.inflate([2, 3])
1009+
x^2 + y^3 + 1
1010+
"""
1011+
1012+
cdef nvars = self.ctx.nvars()
1013+
1014+
if nvars != len(N):
1015+
raise ValueError(f"expected list of length {nvars}, got {len(N)}")
1016+
elif any(n < 0 for n in N):
1017+
raise ValueError("all inflate strides must be non-negative")
1018+
1019+
cdef:
1020+
fmpz_vec shift = fmpz_vec(nvars)
1021+
fmpz_vec stride = fmpz_vec(N)
1022+
fmpq_mpoly res = create_fmpq_mpoly(self.ctx)
1023+
1024+
fmpz_mpoly_inflate(res.val.zpoly, self.val.zpoly, shift.val, stride.val, self.ctx.val.zctx)
1025+
fmpq_set(res.val.content, self.val.content)
1026+
return res
1027+
1028+
def deflate(self, N: list[int]) -> fmpq_mpoly:
1029+
"""
1030+
Compute the deflation of ``self`` for a provided ``N``, that is return ``q``
1031+
such that ``q(X) = p(X^(1/N))``.
10011032

10021033
>>> from flint import Ordering
10031034
>>> ctx = fmpq_mpoly_ctx.get_context(2, Ordering.lex, nametup=('x', 'y'))
10041035
>>> x, y = ctx.gens()
10051036
>>> f = x**3 * y + x * y**4 + x * y
1006-
>>> f.deflation()
1007-
(x + y + 1, fmpz_vec(['2', '3'], 2))
1037+
>>> f.deflate([2, 3])
1038+
x + y + 1
10081039
"""
1040+
cdef slong nvars = self.ctx.nvars()
1041+
1042+
if nvars != len(N):
1043+
raise ValueError(f"expected list of length {nvars}, got {len(N)}")
1044+
10091045
cdef:
1010-
fmpz_vec shift = fmpz_vec(self.ctx.nvars())
1011-
fmpz_vec stride = fmpz_vec(self.ctx.nvars())
1046+
fmpz_vec shift = fmpz_vec(nvars)
1047+
fmpz_vec stride = fmpz_vec(N)
10121048
fmpq_mpoly res = create_fmpq_mpoly(self.ctx)
10131049

1014-
fmpz_mpoly_deflation(shift.val, stride.val, self.val.zpoly, self.ctx.val.zctx)
10151050
fmpz_mpoly_deflate(res.val.zpoly, self.val.zpoly, shift.val, stride.val, self.ctx.val.zctx)
1051+
fmpq_set(res.val.content, self.val.content)
1052+
return res
1053+
1054+
def deflation(self) -> tuple[fmpq_mpoly, list[int]]:
1055+
"""
1056+
Compute the deflation of ``self``, that is ``p(X^(1/N))`` for maximal
1057+
N. Returns ``q, N`` such that ``self == q.inflate(N)``.
1058+
1059+
>>> from flint import Ordering
1060+
>>> ctx = fmpq_mpoly_ctx.get_context(2, Ordering.lex, nametup=('x', 'y'))
1061+
>>> x, y = ctx.gens()
1062+
>>> f = x**3 * y + x * y**4 + x * y
1063+
>>> q, N = f.deflation()
1064+
>>> q, N
1065+
(x + y + 1, [2, 3])
1066+
"""
1067+
cdef:
1068+
fmpz_vec _shift = fmpz_vec(self.ctx.nvars())
1069+
fmpz_vec stride = fmpz_vec(self.ctx.nvars())
1070+
fmpq_mpoly res = create_fmpq_mpoly(self.ctx)
10161071

1072+
fmpz_mpoly_deflation(_shift.val, stride.val, self.val.zpoly, self.ctx.val.zctx)
1073+
1074+
cdef fmpz_vec zero_shift = fmpz_vec(self.ctx.nvars())
1075+
fmpz_mpoly_deflate(res.val.zpoly, self.val.zpoly, zero_shift.val, stride.val, self.ctx.val.zctx)
10171076
fmpq_set(res.val.content, self.val.content)
1018-
return res, stride
1077+
1078+
return res, list(stride)
1079+
1080+
def deflation_monom(self) -> tuple[list[int], fmpq_mpoly]:
1081+
"""
1082+
Compute the exponent vector ``N`` and monomial ``m`` such that ``p(X^(1/N))
1083+
= m * q(X^N)`` for maximal N. Importantly the deflation itself is not computed
1084+
here. The returned monomial allows the undo-ing of the deflation.
1085+
1086+
>>> from flint import Ordering
1087+
>>> ctx = fmpq_mpoly_ctx.get_context(2, Ordering.lex, nametup=('x', 'y'))
1088+
>>> x, y = ctx.gens()
1089+
>>> f = x**3 * y + x * y**4 + x * y
1090+
>>> N, m = f.deflation_monom()
1091+
>>> N, m
1092+
([2, 3], x*y)
1093+
>>> f_deflated = f.deflate(N)
1094+
>>> f_deflated
1095+
x + y + 1
1096+
>>> m * f_deflated.inflate(N)
1097+
x^3*y + x*y^4 + x*y
1098+
"""
1099+
cdef fmpq_mpoly monom = create_fmpq_mpoly(self.ctx)
1100+
1101+
stride, _shift = self.deflation_index()
1102+
1103+
fmpq_mpoly_push_term_ui_ffmpz(monom.val, 1, fmpz_vec(_shift).val, self.ctx.val)
1104+
return list(stride), monom
1105+
1106+
def deflation_index(self) -> tuple[list[int], list[int]]:
1107+
"""
1108+
Compute the exponent vectors ``N`` and ``I`` such that ``p(X^(1/N)) = X^I *
1109+
q(X^N)`` for maximal N. Importantly the deflation itself is not computed
1110+
here. The returned exponent vector ``I`` is the shift that was applied to the
1111+
exponents. It is the exponent vector of the monomial returned by
1112+
``deflation_monom``.
1113+
1114+
>>> from flint import Ordering
1115+
>>> ctx = fmpq_mpoly_ctx.get_context(2, Ordering.lex, nametup=('x', 'y'))
1116+
>>> x, y = ctx.gens()
1117+
>>> f = x**3 * y + x * y**4 + x * y
1118+
>>> N, I = f.deflation_index()
1119+
>>> N, I
1120+
([2, 3], [1, 1])
1121+
>>> f_deflated = f.deflate(N)
1122+
>>> f_deflated
1123+
x + y + 1
1124+
>>> m = ctx.term(exp_vec=I)
1125+
>>> m * f_deflated.inflate(N)
1126+
x^3*y + x*y^4 + x*y
1127+
"""
1128+
cdef:
1129+
slong nvars = self.ctx.nvars()
1130+
fmpz_vec shift = fmpz_vec(nvars)
1131+
fmpz_vec stride = fmpz_vec(nvars)
1132+
1133+
fmpz_mpoly_deflation(shift.val, stride.val, self.val.zpoly, self.ctx.val.zctx)
1134+
return list(stride), list(shift)
10191135

10201136

10211137
cdef class fmpq_mpoly_vec:

src/flint/types/fmpz_mod_mpoly.pyx

Lines changed: 123 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,15 @@ from flint.flintlib.fmpz_mod_mpoly cimport (
4040
fmpz_mod_mpoly_get_str_pretty,
4141
fmpz_mod_mpoly_get_term_coeff_fmpz,
4242
fmpz_mod_mpoly_get_term_exp_fmpz,
43+
fmpz_mod_mpoly_inflate,
4344
fmpz_mod_mpoly_is_one,
4445
fmpz_mod_mpoly_is_zero,
4546
fmpz_mod_mpoly_length,
4647
fmpz_mod_mpoly_mul,
4748
fmpz_mod_mpoly_neg,
4849
fmpz_mod_mpoly_pow_fmpz,
4950
fmpz_mod_mpoly_push_term_fmpz_ffmpz,
51+
fmpz_mod_mpoly_push_term_ui_ffmpz,
5052
fmpz_mod_mpoly_resultant,
5153
fmpz_mod_mpoly_scalar_mul_fmpz,
5254
fmpz_mod_mpoly_set,
@@ -1074,27 +1076,139 @@ cdef class fmpz_mod_mpoly(flint_mpoly):
10741076
fmpz_mod_mpoly_derivative(res.val, self.val, i, self.ctx.val)
10751077
return res
10761078

1077-
def deflation(self):
1079+
def inflate(self, N: list[int]) -> fmpz_mod_mpoly:
10781080
"""
1079-
Compute the deflation of ``self``. See Flint documentation for
1080-
details. Returns deflated polynomial and the stride vector.
1081+
Compute the inflation of ``self`` for a provided ``N``, that is return ``q``
1082+
such that ``q(X) = p(X^N)``.
1083+
1084+
>>> from flint import Ordering
1085+
>>> ctx = fmpz_mod_mpoly_ctx.get_context(2, Ordering.lex, 11, nametup=('x', 'y'))
1086+
>>> x, y = ctx.gens()
1087+
>>> f = x + y + 1
1088+
>>> f.inflate([2, 3])
1089+
x^2 + y^3 + 1
1090+
"""
1091+
1092+
cdef nvars = self.ctx.nvars()
1093+
1094+
if nvars != len(N):
1095+
raise ValueError(f"expected list of length {nvars}, got {len(N)}")
1096+
elif any(n < 0 for n in N):
1097+
raise ValueError("all inflate strides must be non-negative")
1098+
1099+
cdef:
1100+
fmpz_vec shift = fmpz_vec(nvars)
1101+
fmpz_vec stride = fmpz_vec(N)
1102+
fmpz_mod_mpoly res = create_fmpz_mod_mpoly(self.ctx)
1103+
1104+
fmpz_mod_mpoly_inflate(res.val, self.val, shift.val, stride.val, self.ctx.val)
1105+
return res
1106+
1107+
def deflate(self, N: list[int]) -> fmpz_mod_mpoly:
1108+
"""
1109+
Compute the deflation of ``self`` for a provided ``N``, that is return ``q``
1110+
such that ``q(X) = p(X^(1/N))``.
10811111

10821112
>>> from flint import Ordering
10831113
>>> ctx = fmpz_mod_mpoly_ctx.get_context(2, Ordering.lex, 11, nametup=('x', 'y'))
10841114
>>> x, y = ctx.gens()
10851115
>>> f = x**3 * y + x * y**4 + x * y
1086-
>>> f.deflation()
1087-
(x + y + 1, fmpz_vec(['2', '3'], 2))
1116+
>>> f.deflate([2, 3])
1117+
x + y + 1
10881118
"""
1119+
cdef slong nvars = self.ctx.nvars()
1120+
1121+
if nvars != len(N):
1122+
raise ValueError(f"expected list of length {nvars}, got {len(N)}")
1123+
10891124
cdef:
1090-
fmpz_vec shift = fmpz_vec(self.ctx.nvars())
1091-
fmpz_vec stride = fmpz_vec(self.ctx.nvars())
1125+
fmpz_vec shift = fmpz_vec(nvars)
1126+
fmpz_vec stride = fmpz_vec(N)
10921127
fmpz_mod_mpoly res = create_fmpz_mod_mpoly(self.ctx)
10931128

1094-
fmpz_mod_mpoly_deflation(shift.val, stride.val, self.val, self.ctx.val)
10951129
fmpz_mod_mpoly_deflate(res.val, self.val, shift.val, stride.val, self.ctx.val)
1130+
return res
1131+
1132+
def deflation(self) -> tuple[fmpz_mod_mpoly, list[int]]:
1133+
"""
1134+
Compute the deflation of ``self``, that is ``p(X^(1/N))`` for maximal
1135+
N. Returns ``q, N`` such that ``self == q.inflate(N)``.
1136+
1137+
>>> from flint import Ordering
1138+
>>> ctx = fmpz_mod_mpoly_ctx.get_context(2, Ordering.lex, 11, nametup=('x', 'y'))
1139+
>>> x, y = ctx.gens()
1140+
>>> f = x**3 * y + x * y**4 + x * y
1141+
>>> q, N = f.deflation()
1142+
>>> q, N
1143+
(x + y + 1, [2, 3])
1144+
"""
1145+
cdef:
1146+
fmpz_vec _shift = fmpz_vec(self.ctx.nvars())
1147+
fmpz_vec stride = fmpz_vec(self.ctx.nvars())
1148+
fmpz_mod_mpoly res = create_fmpz_mod_mpoly(self.ctx)
1149+
1150+
fmpz_mod_mpoly_deflation(_shift.val, stride.val, self.val, self.ctx.val)
1151+
1152+
cdef fmpz_vec zero_shift = fmpz_vec(self.ctx.nvars())
1153+
fmpz_mod_mpoly_deflate(res.val, self.val, zero_shift.val, stride.val, self.ctx.val)
1154+
1155+
return res, list(stride)
1156+
1157+
def deflation_monom(self) -> tuple[list[int], fmpz_mod_mpoly]:
1158+
"""
1159+
Compute the exponent vector ``N`` and monomial ``m`` such that ``p(X^(1/N))
1160+
= m * q(X^N)`` for maximal N. Importantly the deflation itself is not computed
1161+
here. The returned monomial allows the undo-ing of the deflation.
1162+
1163+
>>> from flint import Ordering
1164+
>>> ctx = fmpz_mod_mpoly_ctx.get_context(2, Ordering.lex, 11, nametup=('x', 'y'))
1165+
>>> x, y = ctx.gens()
1166+
>>> f = x**3 * y + x * y**4 + x * y
1167+
>>> N, m = f.deflation_monom()
1168+
>>> N, m
1169+
([2, 3], x*y)
1170+
>>> f_deflated = f.deflate(N)
1171+
>>> f_deflated
1172+
x + y + 1
1173+
>>> m * f_deflated.inflate(N)
1174+
x^3*y + x*y^4 + x*y
1175+
"""
1176+
cdef fmpz_mod_mpoly monom = create_fmpz_mod_mpoly(self.ctx)
10961177

1097-
return res, stride
1178+
stride, _shift = self.deflation_index()
1179+
1180+
fmpz_mod_mpoly_push_term_ui_ffmpz(monom.val, 1, fmpz_vec(_shift).val, self.ctx.val)
1181+
return list(stride), monom
1182+
1183+
def deflation_index(self) -> tuple[list[int], list[int]]:
1184+
"""
1185+
Compute the exponent vectors ``N`` and ``I`` such that ``p(X^(1/N)) = X^I *
1186+
q(X^N)`` for maximal N. Importantly the deflation itself is not computed
1187+
here. The returned exponent vector ``I`` is the shift that was applied to the
1188+
exponents. It is the exponent vector of the monomial returned by
1189+
``deflation_monom``.
1190+
1191+
>>> from flint import Ordering
1192+
>>> ctx = fmpz_mod_mpoly_ctx.get_context(2, Ordering.lex, 11, nametup=('x', 'y'))
1193+
>>> x, y = ctx.gens()
1194+
>>> f = x**3 * y + x * y**4 + x * y
1195+
>>> N, I = f.deflation_index()
1196+
>>> N, I
1197+
([2, 3], [1, 1])
1198+
>>> f_deflated = f.deflate(N)
1199+
>>> f_deflated
1200+
x + y + 1
1201+
>>> m = ctx.term(exp_vec=I)
1202+
>>> m * f_deflated.inflate(N)
1203+
x^3*y + x*y^4 + x*y
1204+
"""
1205+
cdef:
1206+
slong nvars = self.ctx.nvars()
1207+
fmpz_vec shift = fmpz_vec(nvars)
1208+
fmpz_vec stride = fmpz_vec(nvars)
1209+
1210+
fmpz_mod_mpoly_deflation(shift.val, stride.val, self.val, self.ctx.val)
1211+
return list(stride), list(shift)
10981212

10991213

11001214
cdef class fmpz_mod_mpoly_vec:

0 commit comments

Comments
 (0)