@@ -13,6 +13,8 @@ cimport libc.stdlib
1313from typing import Optional
1414from flint.utils.flint_exceptions import IncompatibleContextError
1515
16+ from flint.types.fmpz cimport fmpz, any_as_fmpz
17+
1618
1719FLINT_BITS = _FLINT_BITS
1820FLINT_VERSION = _FLINT_VERSION.decode(" ascii" )
@@ -404,6 +406,48 @@ cdef class flint_mpoly(flint_elem):
404406 def _add_mpoly_ (self , other ):
405407 return NotImplemented
406408
409+ def _iadd_scalar_ (self , other ):
410+ return NotImplemented
411+
412+ def _iadd_mpoly_ (self , other ):
413+ return NotImplemented
414+
415+ def _sub_scalar_ (self , other ):
416+ return NotImplemented
417+
418+ def _sub_mpoly_ (self , other ):
419+ return NotImplemented
420+
421+ def _isub_scalar_ (self , other ):
422+ return NotImplemented
423+
424+ def _isub_mpoly_ (self , other ):
425+ return NotImplemented
426+
427+ def _mul_scalar_ (self , other ):
428+ return NotImplemented
429+
430+ def _imul_mpoly_ (self , other ):
431+ return NotImplemented
432+
433+ def _imul_scalar_ (self , other ):
434+ return NotImplemented
435+
436+ def _mul_mpoly_ (self , other ):
437+ return NotImplemented
438+
439+ def _pow_ (self , other ):
440+ return NotImplemented
441+
442+ def _divmod_mpoly_ (self , other ):
443+ return NotImplemented
444+
445+ def _floordiv_mpoly_ (self , other ):
446+ return NotImplemented
447+
448+ def _truediv_mpoly_ (self , other ):
449+ return NotImplemented
450+
407451 def __add__ (self , other ):
408452 if typecheck(other, type (self )):
409453 self .context().compatible_context_check(other.context())
@@ -418,6 +462,123 @@ cdef class flint_mpoly(flint_elem):
418462 def __radd__ (self , other ):
419463 return self .__add__ (other)
420464
465+ def iadd (self , other ):
466+ """
467+ In-place addition, mutates self.
468+
469+ >>> from flint import Ordering, fmpz_mpoly_ctx
470+ >>> ctx = fmpz_mpoly_ctx.get_context(2, Ordering.lex, 'x')
471+ >>> f = ctx.from_dict({(1, 0): 2, (0, 1): 3, (1, 1): 4})
472+ >>> f
473+ 4*x0*x1 + 2*x0 + 3*x1
474+ >>> f.iadd(5)
475+ >>> f
476+ 4*x0*x1 + 2*x0 + 3*x1 + 5
477+
478+ """
479+ if typecheck(other, type (self )):
480+ self .context().compatible_context_check(other.context())
481+ self ._iadd_mpoly_(other)
482+ return
483+
484+ other_scalar = self .context().any_as_scalar(other)
485+ if other_scalar is NotImplemented :
486+ raise NotImplementedError (f" cannot add {type(self)} and {type(other)}" )
487+
488+ self ._iadd_scalar_(other_scalar)
489+
490+ def __sub__ (self , other ):
491+ if typecheck(other, type (self )):
492+ self .context().compatible_context_check(other.context())
493+ return self ._sub_mpoly_(other)
494+
495+ other = self .context().any_as_scalar(other)
496+ if other is NotImplemented :
497+ return NotImplemented
498+
499+ return self ._sub_scalar_(other)
500+
501+ def __rsub__ (self , other ):
502+ return - self .__sub__ (other)
503+
504+ def isub (self , other ):
505+ """
506+ In-place subtraction, mutates self.
507+
508+ >>> from flint import Ordering, fmpz_mpoly_ctx
509+ >>> ctx = fmpz_mpoly_ctx.get_context(2, Ordering.lex, 'x')
510+ >>> f = ctx.from_dict({(1, 0): 2, (0, 1): 3, (1, 1): 4})
511+ >>> f
512+ 4*x0*x1 + 2*x0 + 3*x1
513+ >>> f.isub(5)
514+ >>> f
515+ 4*x0*x1 + 2*x0 + 3*x1 - 5
516+
517+ """
518+ if typecheck(other, type (self )):
519+ self .context().compatible_context_check(other.context())
520+ self ._isub_mpoly_(other)
521+ return
522+
523+ other_scalar = self .context().any_as_scalar(other)
524+ if other_scalar is NotImplemented :
525+ raise NotImplementedError (f" cannot subtract {type(self)} and {type(other)}" )
526+
527+ self ._isub_scalar_(other_scalar)
528+
529+ def __mul__ (self , other ):
530+ if typecheck(other, type (self )):
531+ self .context().compatible_context_check(other.context())
532+ return self ._mul_mpoly_(other)
533+
534+ other = self .context().any_as_scalar(other)
535+ if other is NotImplemented :
536+ return NotImplemented
537+
538+ return self ._mul_scalar_(other)
539+
540+ def __rmul__ (self , other ):
541+ return self .__mul__ (other)
542+
543+ def imul (self , other ):
544+ """
545+ In-place multiplication, mutates self.
546+
547+ >>> from flint import Ordering, fmpz_mpoly_ctx
548+ >>> ctx = fmpz_mpoly_ctx.get_context(2, Ordering.lex, 'x')
549+ >>> f = ctx.from_dict({(1, 0): 2, (0, 1): 3, (1, 1): 4})
550+ >>> f
551+ 4*x0*x1 + 2*x0 + 3*x1
552+ >>> f.imul(2)
553+ >>> f
554+ 8*x0*x1 + 4*x0 + 6*x1
555+
556+ """
557+ if typecheck(other, type (self )):
558+ self .context().compatible_context_check(other.context())
559+ self ._imul_mpoly_(other)
560+ return
561+
562+ other_scalar = self .context().any_as_scalar(other)
563+ if other_scalar is NotImplemented :
564+ raise NotImplementedError (f" cannot multiply {type(self)} and {type(other)}" )
565+
566+ self ._imul_scalar_(other_scalar)
567+
568+ def __pow__ (self , other , modulus ):
569+ if modulus is not None :
570+ raise NotImplementedError (" cannot specify modulus outside of the context" )
571+ elif typecheck(other, fmpz):
572+ return self ._pow_(other)
573+
574+ other = any_as_fmpz(other)
575+ if other is NotImplemented :
576+ return NotImplemented
577+ elif other < 0 :
578+ raise ValueError (" cannot raise to a negative power" )
579+
580+ return self ._pow_(other)
581+
421582 def __divmod__ (self , other ):
422583 if typecheck(other, type (self )):
423584 self ._division_check(other)
@@ -441,6 +602,75 @@ cdef class flint_mpoly(flint_elem):
441602 other = self .context().scalar_as_mpoly(other)
442603 return other._divmod_mpoly_(self )
443604
605+ def __truediv__ (self , other ):
606+ if typecheck(other, type (self )):
607+ self ._division_check(other)
608+ self .context().compatible_context_check(other.context())
609+ return self ._truediv_mpoly_(other)
610+
611+ other = self .context().any_as_scalar(other)
612+ if other is NotImplemented :
613+ return NotImplemented
614+
615+ self ._division_check(other)
616+ other = self .context().scalar_as_mpoly(other)
617+ return self ._truediv_mpoly_(other)
618+
619+ def __rtruediv__ (self , other ):
620+ other = self .context().any_as_scalar(other)
621+ if other is NotImplemented :
622+ return NotImplemented
623+
624+ self ._division_check(self )
625+ other = self .context().scalar_as_mpoly(other)
626+ return other._truediv_mpoly_(self )
627+
628+ def __floordiv__ (self , other ):
629+ if typecheck(other, type (self )):
630+ self ._division_check(other)
631+ self .context().compatible_context_check(other.context())
632+ return self ._floordiv_mpoly_(other)
633+
634+ other = self .context().any_as_scalar(other)
635+ if other is NotImplemented :
636+ return NotImplemented
637+
638+ self ._division_check(other)
639+ other = self .context().scalar_as_mpoly(other)
640+ return self ._floordiv_mpoly_(other)
641+
642+ def __rfloordiv__ (self , other ):
643+ other = self .context().any_as_scalar(other)
644+ if other is NotImplemented :
645+ return NotImplemented
646+
647+ self ._division_check(self )
648+ other = self .context().scalar_as_mpoly(other)
649+ return other._floordiv_mpoly_(self )
650+
651+ def __mod__ (self , other ):
652+ if typecheck(other, type (self )):
653+ self ._division_check(other)
654+ self .context().compatible_context_check(other.context())
655+ return self ._mod_mpoly_(other)
656+
657+ other = self .context().any_as_scalar(other)
658+ if other is NotImplemented :
659+ return NotImplemented
660+
661+ self ._division_check(other)
662+ other = self .context().scalar_as_mpoly(other)
663+ return self ._mod_mpoly_(other)
664+
665+ def __rmod__ (self , other ):
666+ other = self .context().any_as_scalar(other)
667+ if other is NotImplemented :
668+ return NotImplemented
669+
670+ self ._division_check(self )
671+ other = self .context().scalar_as_mpoly(other)
672+ return other._mod_mpoly_(self )
673+
444674 def __contains__ (self , x ):
445675 """
446676 Returns True if `self` contains a term with exponent vector `x` and a non-zero coefficient.
0 commit comments