Skip to content

Commit fbc6854

Browse files
committed
Make fmpq_mpoly and fmpz_mpoly more dict-like
1 parent faa1fb2 commit fbc6854

4 files changed

Lines changed: 115 additions & 7 deletions

File tree

src/flint/flint_base/flint_base.pyx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ cdef class flint_mpoly(flint_elem):
248248
"""
249249
Returns True if `self` contains a term with exponent vector `x` and a non-zero coefficient.
250250
251-
>>> from flint import Ordering
251+
>>> from flint import fmpq_mpoly_ctx, Ordering
252252
>>> ctx = fmpq_mpoly_ctx.get_context(2, Ordering.lex, 'x')
253253
>>> p = ctx.from_dict({(0, 1): 2, (1, 1): 3})
254254
>>> (1, 1) in p
@@ -259,6 +259,25 @@ cdef class flint_mpoly(flint_elem):
259259
"""
260260
return bool(self[x])
261261

262+
def __iter__(self):
263+
return iter(self.keys())
264+
265+
def __pos__(self):
266+
return self
267+
268+
def items(self):
269+
"""
270+
Return the exponent vectors and coefficient of each term.
271+
272+
>>> from flint import fmpq_mpoly_ctx, Ordering
273+
>>> ctx = fmpq_mpoly_ctx.get_context(2, Ordering.lex, 'x')
274+
>>> f = ctx.from_dict({(0, 0): 1, (1, 0): 2, (0, 1): 3, (1, 1): 4})
275+
>>> list(f.items())
276+
[((1, 1), 4), ((1, 0), 2), ((0, 1), 3), ((0, 0), 1)]
277+
278+
"""
279+
return zip(self.keys(), self.values())
280+
262281

263282
cdef class flint_series(flint_elem):
264283
"""

src/flint/test/test_all.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2790,6 +2790,11 @@ def quick_poly():
27902790
assert p(0, 0) == p(0, S(0)) == p(S(0), S(0)) == S(1) == 1
27912791
assert p(1, 1) == S(10) == 10
27922792

2793+
p = quick_poly()
2794+
assert p.keys() == [(2, 2), (1, 0), (0, 1), (0, 0)]
2795+
assert p.values() == [4, 3, 2, 1]
2796+
assert list(p.items()) == list(zip([(2, 2), (1, 0), (0, 1), (0, 0)], [4, 3, 2, 1]))
2797+
27932798
assert p.subs({"x1": S(0), "x0": S(0)}) == ctx.from_dict({(0, 0): 1})
27942799
assert p.compose(p.subs({"x1": 0}), ctx.from_dict({(0, 1): 1})) == mpoly({
27952800
(2, 2): 36,

src/flint/types/fmpq_mpoly.pyx

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,6 @@ cdef class fmpq_mpoly(flint_mpoly):
317317
exp_vec = fmpz_vec(x, double_indirect=True)
318318
fmpq_mpoly_set_coeff_fmpq_fmpz(self.val, (<fmpq>coeff).val, exp_vec.double_indirect, self.ctx.val)
319319

320-
def __pos__(self):
321-
return self
322-
323320
def __neg__(self):
324321
cdef fmpq_mpoly res
325322
res = create_fmpq_mpoly(self.ctx)
@@ -587,6 +584,51 @@ cdef class fmpq_mpoly(flint_mpoly):
587584
raise ValueError("Unreasonably large polynomial") # pragma: no cover
588585
return vres
589586

587+
def keys(self):
588+
"""
589+
Return the exponent vectors of each term as a tuple of fmpz.
590+
591+
>>> from flint import Ordering
592+
>>> ctx = fmpq_mpoly_ctx.get_context(2, Ordering.lex, 'x')
593+
>>> f = ctx.from_dict({(0, 0): 1, (1, 0): 2, (0, 1): 3, (1, 1): 4})
594+
>>> f.keys()
595+
[(1, 1), (1, 0), (0, 1), (0, 0)]
596+
597+
"""
598+
cdef:
599+
slong i, nvars = self.ctx.nvars()
600+
fmpz_vec vec = fmpz_vec(nvars, double_indirect=True)
601+
602+
res = []
603+
for i in range(len(self)):
604+
fmpq_mpoly_get_term_exp_fmpz(vec.double_indirect, self.val, i, self.ctx.val)
605+
res.append(vec.to_tuple())
606+
607+
return res
608+
609+
def values(self):
610+
"""
611+
Return the coefficients of each term as a fmpq.
612+
613+
>>> from flint import Ordering
614+
>>> ctx = fmpq_mpoly_ctx.get_context(2, Ordering.lex, 'x')
615+
>>> f = ctx.from_dict({(0, 0): 1, (1, 0): 2, (0, 1): 3, (1, 1): 4})
616+
>>> f.values()
617+
[4, 2, 3, 1]
618+
619+
"""
620+
cdef:
621+
fmpq coeff
622+
slong i
623+
624+
res = []
625+
for i in range(len(self)):
626+
coeff = fmpq.__new__(fmpq)
627+
fmpq_mpoly_get_term_coeff_fmpq(coeff.val, self.val, i, self.ctx.val)
628+
res.append(coeff)
629+
630+
return res
631+
590632
def subs(self, dict_args) -> fmpq_mpoly:
591633
"""
592634
Partial evaluate this polynomial.

src/flint/types/fmpz_mpoly.pyx

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,6 @@ cdef class fmpz_mpoly(flint_mpoly):
297297
exp_vec = fmpz_vec(x, double_indirect=True)
298298
fmpz_mpoly_set_coeff_fmpz_fmpz(self.val, (<fmpz>coeff).val, exp_vec.double_indirect, self.ctx.val)
299299

300-
def __pos__(self):
301-
return self
302-
303300
def __neg__(self):
304301
cdef fmpz_mpoly res
305302
res = create_fmpz_mpoly(self.ctx)
@@ -569,6 +566,51 @@ cdef class fmpz_mpoly(flint_mpoly):
569566
raise ValueError("Unreasonably large polynomial") # pragma: no cover
570567
return vres
571568

569+
def keys(self):
570+
"""
571+
Return the exponent vectors of each term as a tuple of fmpz.
572+
573+
>>> from flint import Ordering
574+
>>> ctx = fmpz_mpoly_ctx.get_context(2, Ordering.lex, 'x')
575+
>>> f = ctx.from_dict({(0, 0): 1, (1, 0): 2, (0, 1): 3, (1, 1): 4})
576+
>>> f.keys()
577+
[(1, 1), (1, 0), (0, 1), (0, 0)]
578+
579+
"""
580+
cdef:
581+
slong i, nvars = self.ctx.nvars()
582+
fmpz_vec vec = fmpz_vec(nvars, double_indirect=True)
583+
584+
res = []
585+
for i in range(len(self)):
586+
fmpz_mpoly_get_term_exp_fmpz(vec.double_indirect, self.val, i, self.ctx.val)
587+
res.append(vec.to_tuple())
588+
589+
return res
590+
591+
def values(self):
592+
"""
593+
Return the coefficients of each term as a fmpz
594+
595+
>>> from flint import Ordering
596+
>>> ctx = fmpz_mpoly_ctx.get_context(2, Ordering.lex, 'x')
597+
>>> f = ctx.from_dict({(0, 0): 1, (1, 0): 2, (0, 1): 3, (1, 1): 4})
598+
>>> f.values()
599+
[4, 2, 3, 1]
600+
601+
"""
602+
cdef:
603+
fmpz coeff
604+
slong i
605+
606+
res = []
607+
for i in range(len(self)):
608+
coeff = fmpz.__new__(fmpz)
609+
fmpz_mpoly_get_term_coeff_fmpz(coeff.val, self.val, i, self.ctx.val)
610+
res.append(coeff)
611+
612+
return res
613+
572614
def subs(self, dict_args) -> fmpz_mpoly:
573615
"""
574616
Partial evaluate this polynomial with select constants. All arguments must be fmpz.

0 commit comments

Comments
 (0)