@@ -94,6 +94,22 @@ cdef class fmpq_mpoly_ctx(flint_mpoly_context):
9494 fmpq_mpoly_ctx_init(self .val, nvars, ordering_py_to_c(ordering))
9595 super ().__init__(nvars, names)
9696
97+ def any_as_scalar (self , other ):
98+ if isinstance (other, int ):
99+ return any_as_fmpq(other)
100+ elif typecheck(other, fmpz):
101+ return any_as_fmpq(other)
102+ elif typecheck(other, fmpq):
103+ res = fmpq.__new__ (fmpq)
104+ fmpq_set((< fmpq> res).val, (< fmpq> other).val)
105+ return res
106+ else :
107+ return NotImplemented
108+
109+ def scalar_as_mpoly (self , other: fmpq ):
110+ # non-fmpq scalars should first be converted via self.any_as_scalar
111+ return self .constant(< fmpq> other)
112+
97113 def nvars (self ):
98114 """
99115 Return the number of variables in the context
@@ -336,205 +352,77 @@ cdef class fmpq_mpoly(flint_mpoly):
336352 fmpq_mpoly_neg(res.val, (< fmpq_mpoly> self ).val, res.ctx.val)
337353 return res
338354
339- def __add__ (self , other ):
340- cdef fmpq_mpoly res
341- if typecheck(other, fmpq_mpoly):
342- if (< fmpq_mpoly> self ).ctx is not (< fmpq_mpoly> other).ctx:
343- raise IncompatibleContextError(f" {(<fmpq_mpoly>self).ctx} is not {(<fmpq_mpoly>other).ctx}" )
344- res = create_fmpq_mpoly(self .ctx)
345- fmpq_mpoly_add(res.val, (< fmpq_mpoly> self ).val, (< fmpq_mpoly> other).val, res.ctx.val)
346- return res
347- else :
348- other = any_as_fmpq(other)
349- if other is not NotImplemented :
350- res = create_fmpq_mpoly(self .ctx)
351- fmpq_mpoly_add_fmpq(res.val, (< fmpq_mpoly> self ).val, (< fmpq> other).val, res.ctx.val)
352- return res
353- return NotImplemented
354-
355- def __radd__ (self , other ):
356- cdef fmpq_mpoly res
357- other = any_as_fmpq(other)
358- if other is not NotImplemented :
359- res = create_fmpq_mpoly(self .ctx)
360- fmpq_mpoly_add_fmpq(res.val, (< fmpq_mpoly> self ).val, (< fmpq> other).val, res.ctx.val)
361- return res
362- return NotImplemented
363355
364- def __sub__ (self , other ):
365- cdef fmpq_mpoly res
366- if typecheck(other, fmpq_mpoly):
367- if (< fmpq_mpoly> self ).ctx is not (< fmpq_mpoly> other).ctx:
368- raise IncompatibleContextError(f" {(<fmpq_mpoly>self).ctx} is not {(<fmpq_mpoly>other).ctx}" )
369- res = create_fmpq_mpoly(self .ctx)
370- fmpq_mpoly_sub(res.val, (< fmpq_mpoly> self ).val, (< fmpq_mpoly> other).val, res.ctx.val)
371- return res
372- else :
373- other = any_as_fmpq(other)
374- if other is not NotImplemented :
375- res = create_fmpq_mpoly(self .ctx)
376- fmpq_mpoly_sub_fmpq(res.val, (< fmpq_mpoly> self ).val, (< fmpq> other).val, res.ctx.val)
377- return res
378- return NotImplemented
379-
380- def __rsub__ (self , other ):
381- cdef fmpq_mpoly res
382- other = any_as_fmpq(other)
383- if other is not NotImplemented :
384- res = create_fmpq_mpoly(self .ctx)
385- fmpq_mpoly_sub_fmpq(res.val, (< fmpq_mpoly> self ).val, (< fmpq> other).val, res.ctx.val)
386- return - res
387- return NotImplemented
388-
389- def __mul__ (self , other ):
390- cdef fmpq_mpoly res
391- if typecheck(other, fmpq_mpoly):
392- if (< fmpq_mpoly> self ).ctx is not (< fmpq_mpoly> other).ctx:
393- raise IncompatibleContextError(f" {(<fmpq_mpoly>self).ctx} is not {(<fmpq_mpoly>other).ctx}" )
394- res = create_fmpq_mpoly(self .ctx)
395- fmpq_mpoly_mul(res.val, (< fmpq_mpoly> self ).val, (< fmpq_mpoly> other).val, res.ctx.val)
396- return res
397- else :
398- other = any_as_fmpq(other)
399- if other is not NotImplemented :
400- res = create_fmpq_mpoly(self .ctx)
401- fmpq_mpoly_scalar_mul_fmpq(res.val, (< fmpq_mpoly> self ).val, (< fmpq> other).val, res.ctx.val)
402- return res
403- return NotImplemented
404-
405- def __rmul__ (self , other ):
356+ def _add_scalar_ (self , other: fmpq ):
406357 cdef fmpq_mpoly res
407- other = any_as_fmpq(other)
408- if other is not NotImplemented :
409- res = create_fmpq_mpoly(self .ctx)
410- fmpq_mpoly_scalar_mul_fmpq(res.val, (< fmpq_mpoly> self ).val, (< fmpq> other).val, res.ctx.val)
411- return res
412- return NotImplemented
358+ res = create_fmpq_mpoly(self .ctx)
359+ fmpq_mpoly_add_fmpq(res.val, self .val, other.val, self .ctx.val)
360+ return res
413361
414- def __pow__ (self , other , modulus ):
362+ def _add_mpoly_ (self , other: fmpq_mpoly ):
415363 cdef fmpq_mpoly res
416- if modulus is not None :
417- raise NotImplementedError
418- other = any_as_fmpz(other)
419- if other is NotImplemented :
420- return other
421- if other < 0 :
422- raise ValueError (" cannot raise fmpq_mpoly to negative power" )
423364 res = create_fmpq_mpoly(self .ctx)
424- if fmpq_mpoly_pow_fmpz(res.val, (< fmpq_mpoly> self ).val, (< fmpz> other).val, res.ctx.val) == 0 :
425- raise ValueError (" unreasonably large polynomial" ) # pragma: no cover
365+ fmpq_mpoly_add(res.val, self .val, other.val, res.ctx.val)
426366 return res
427367
428- def __divmod__ (self , other ):
429- cdef fmpq_mpoly res, res2
430- if typecheck(other, fmpq_mpoly):
431- if not other:
432- raise ZeroDivisionError (" fmpq_mpoly division by zero" )
433- elif (< fmpq_mpoly> self ).ctx is not (< fmpq_mpoly> other).ctx:
434- raise IncompatibleContextError(f" {(<fmpq_mpoly>self).ctx} is not {(<fmpq_mpoly>other).ctx}" )
435- res = create_fmpq_mpoly(self .ctx)
436- res2 = create_fmpq_mpoly(self .ctx)
437- fmpq_mpoly_divrem(res.val, res2.val, (< fmpq_mpoly> self ).val, (< fmpq_mpoly> other).val, res.ctx.val)
438- return (res, res2)
439- else :
440- other = any_as_fmpq(other)
441- if other is not NotImplemented :
442- other = fmpq_mpoly(other, self .ctx)
443- if not other:
444- raise ZeroDivisionError (" fmpq_mpoly division by zero" )
445- res = create_fmpq_mpoly(self .ctx)
446- res2 = create_fmpq_mpoly(self .ctx)
447- fmpq_mpoly_divrem(res.val, res2.val, (< fmpq_mpoly> self ).val, (< fmpq_mpoly> other).val, res.ctx.val)
448- return (res, res2)
449- return NotImplemented
450-
451- def __rdivmod__ (self , other ):
452- cdef fmpq_mpoly res, res2
453- if not self :
454- raise ZeroDivisionError (" fmpq_mpoly division by zero" )
455- other = any_as_fmpq(other)
456- if other is not NotImplemented :
457- other = fmpq_mpoly(other, self .ctx)
458- res = create_fmpq_mpoly(self .ctx)
459- res2 = create_fmpq_mpoly(self .ctx)
460- fmpq_mpoly_divrem(res.val, res2.val, (< fmpq_mpoly> other).val, (< fmpq_mpoly> self ).val, res.ctx.val)
461- return (res, res2)
462- return NotImplemented
463-
464- def __floordiv__ (self , other ):
368+ def _sub_scalar_ (self , other: fmpq ):
465369 cdef fmpq_mpoly res
466- if typecheck(other, fmpq_mpoly):
467- if not other:
468- raise ZeroDivisionError (" fmpq_mpoly division by zero" )
469- elif (< fmpq_mpoly> self ).ctx is not (< fmpq_mpoly> other).ctx:
470- raise IncompatibleContextError(f" {(<fmpq_mpoly>self).ctx} is not {(<fmpq_mpoly>other).ctx}" )
471- res = create_fmpq_mpoly(self .ctx)
472- fmpq_mpoly_div(res.val, (< fmpq_mpoly> self ).val, (< fmpq_mpoly> other).val, res.ctx.val)
473- return res
474- else :
475- other = any_as_fmpq(other)
476- if other is not NotImplemented :
477- if not other:
478- raise ZeroDivisionError (" fmpq_mpoly division by zero" )
479- other = fmpq_mpoly(other, self .ctx)
480- res = create_fmpq_mpoly(self .ctx)
481- fmpq_mpoly_div(res.val, (< fmpq_mpoly> self ).val, (< fmpq_mpoly> other).val, res.ctx.val)
482- return res
483- return NotImplemented
484-
485- def __rfloordiv__ (self , other ):
486- cdef fmpq_mpoly res
487- if not self :
488- raise ZeroDivisionError (" fmpq_mpoly division by zero" )
489- other = any_as_fmpq(other)
490- if other is not NotImplemented :
491- other = fmpq_mpoly(other, self .ctx)
492- res = create_fmpq_mpoly(self .ctx)
493- fmpq_mpoly_div(res.val, (< fmpq_mpoly> other).val, self .val, res.ctx.val)
494- return res
495- return NotImplemented
370+ res = create_fmpq_mpoly(self .ctx)
371+ fmpq_mpoly_sub_fmpq(res.val, self .val, other.val, self .ctx.val)
372+ return res
496373
497- def __truediv__ (self , other ):
498- cdef:
499- fmpq_mpoly res
374+ def _sub_mpoly_ (self , other: fmpq_mpoly ):
375+ cdef fmpq_mpoly res
376+ res = create_fmpq_mpoly(self .ctx)
377+ fmpq_mpoly_sub(res.val, self .val, other.val, res.ctx.val)
378+ return res
500379
501- if typecheck(other, fmpq_mpoly ):
502- if not other:
503- raise ZeroDivisionError ( " fmpq_mpoly division by zero " )
504- elif self .ctx is not ( < fmpq_mpoly > other). ctx:
505- raise IncompatibleContextError(f " {self.ctx} is not {(<fmpq_mpoly>other).ctx} " )
380+ def _mul_scalar_ ( self , other: fmpq ):
381+ cdef fmpq_mpoly res
382+ res = create_fmpq_mpoly( self .ctx )
383+ fmpq_mpoly_scalar_mul_fmpq(res.val, self .val, other.val, self . ctx.val)
384+ return res
506385
507- res = create_fmpq_mpoly(self .ctx)
508- if fmpq_mpoly_divides(res.val, self .val, (< fmpq_mpoly> other).val, self .ctx.val):
509- return res
510- else :
511- raise DomainError(" fmpq_mpoly division is not exact" )
512- else :
513- o = any_as_fmpq(other)
514- if o is NotImplemented :
515- return NotImplemented
516- elif not o:
517- raise ZeroDivisionError (" fmpq_mpoly division by zero" )
518- res = create_fmpq_mpoly(self .ctx)
519- fmpq_mpoly_scalar_div_fmpq(res.val, self .val, (< fmpq> o).val, self .ctx.val)
520- return res
386+ def _mul_mpoly_ (self , other: fmpq_mpoly ):
387+ cdef fmpq_mpoly res
388+ res = create_fmpq_mpoly(self .ctx)
389+ fmpq_mpoly_mul(res.val, self .val, other.val, res.ctx.val)
390+ return res
521391
522- def __rtruediv__ (self , other ):
392+ def _pow_ (self , other: fmpz ):
523393 cdef fmpq_mpoly res
524- if not self :
525- raise ZeroDivisionError (" fmpq_mpoly division by zero" )
526- o = any_as_fmpq(other)
527- if o is NotImplemented :
528- return NotImplemented
529394 res = create_fmpq_mpoly(self .ctx)
530- fmpq_mpoly_set_fmpq(res.val, (< fmpq> o).val, self .ctx.val)
531- return res / self
395+ if fmpq_mpoly_pow_fmpz(res.val, self .val, other.val, res.ctx.val) == 0 :
396+ raise ValueError (" unreasonably large polynomial" ) # pragma: no cover
397+ return res
532398
533- def __mod__ (self , other ):
534- return divmod (self , other)[1 ]
399+ def _divmod_mpoly_ (self , other: fmpq_mpoly ):
400+ cdef fmpq_mpoly quotient, remainder
401+ quotient = create_fmpq_mpoly(self .ctx)
402+ remainder = create_fmpq_mpoly(self .ctx)
403+ fmpq_mpoly_divrem(quotient.val, remainder.val, self .val, other.val, self .ctx.val)
404+ return (quotient, remainder)
405+
406+ def _floordiv_mpoly_ (self , other: fmpq_mpoly ):
407+ cdef fmpq_mpoly quotient
408+ quotient = create_fmpq_mpoly(self .ctx)
409+ fmpq_mpoly_div(quotient.val, self .val, other.val, self .ctx.val)
410+ return quotient
411+
412+ def _truediv_mpoly_ (self , other: fmpq_mpoly ):
413+ cdef fmpq_mpoly quotient
414+ quotient = create_fmpq_mpoly(self .ctx)
415+ if fmpq_mpoly_divides(quotient.val, self .val, other.val, self .ctx.val):
416+ return quotient
417+ else :
418+ raise DomainError(" fmpq_mpoly division is not exact" )
535419
536- def __rmod__ (self , other ):
537- return divmod (other, self )[1 ]
420+ def _mod_mpoly_ (self , other: fmpq_mpoly ):
421+ cdef fmpq_mpoly quotient, remainder
422+ quotient = create_fmpq_mpoly(self .ctx)
423+ remainder = create_fmpq_mpoly(self .ctx)
424+ fmpq_mpoly_divrem(quotient.val, remainder.val, self .val, other.val, self .ctx.val)
425+ return remainder
538426
539427 def __call__ (self , *args ) -> fmpq:
540428 cdef:
@@ -551,83 +439,23 @@ cdef class fmpq_mpoly(flint_mpoly):
551439 raise ValueError("unreasonably large polynomial") # pragma: no cover
552440 return vres
553441
554- def iadd(self , other ):
555- """
556- In-place addition, mutates self.
442+ def _iadd_scalar_(self , other: fmpq ):
443+ fmpq_mpoly_add_fmpq(self .val, self .val, other.val, self .ctx.val)
557444
558- >>> from flint import Ordering
559- >>> ctx = fmpq_mpoly_ctx.get_context(2, Ordering.lex, 'x')
560- >>> f = ctx.from_dict({(1, 0): 2, (0, 1): 3, (1, 1): 4})
561- >>> f
562- 4*x0*x1 + 2*x0 + 3*x1
563- >>> f.iadd(5)
564- >>> f
565- 4*x0*x1 + 2*x0 + 3*x1 + 5
445+ def _iadd_mpoly_ (self , other: fmpq_mpoly ):
446+ fmpq_mpoly_add(self .val, self .val, other.val, self .ctx.val)
566447
567- """
568- if typecheck(other, fmpq_mpoly):
569- if (< fmpq_mpoly> self ).ctx is not (< fmpq_mpoly> other).ctx:
570- raise IncompatibleContextError(f" {(<fmpq_mpoly>self).ctx} is not {(<fmpq_mpoly>other).ctx}" )
571- fmpq_mpoly_add((< fmpq_mpoly> self ).val, (< fmpq_mpoly> self ).val, (< fmpq_mpoly> other).val, self .ctx.val)
572- return
573- else :
574- other = any_as_fmpq(other)
575- if other is not NotImplemented :
576- fmpq_mpoly_add_fmpq((< fmpq_mpoly> self ).val, (< fmpq_mpoly> self ).val, (< fmpq> other).val, self .ctx.val)
577- return
578- raise NotImplementedError (f" in-place addition not implemented between {type(self)} and {type(other)}" )
579-
580- def isub (self , other ):
581- """
582- In-place subtraction, mutates self.
583-
584- >>> from flint import Ordering
585- >>> ctx = fmpq_mpoly_ctx.get_context(2, Ordering.lex, 'x')
586- >>> f = ctx.from_dict({(1, 0): 2, (0, 1): 3, (1, 1): 4})
587- >>> f
588- 4*x0*x1 + 2*x0 + 3*x1
589- >>> f.isub(5)
590- >>> f
591- 4*x0*x1 + 2*x0 + 3*x1 - 5
592-
593- """
594- if typecheck(other, fmpq_mpoly):
595- if (< fmpq_mpoly> self ).ctx is not (< fmpq_mpoly> other).ctx:
596- raise IncompatibleContextError(f" {(<fmpq_mpoly>self).ctx} is not {(<fmpq_mpoly>other).ctx}" )
597- fmpq_mpoly_sub((< fmpq_mpoly> self ).val, (< fmpq_mpoly> self ).val, (< fmpq_mpoly> other).val, self .ctx.val)
598- return
599- else :
600- other = any_as_fmpq(other)
601- if other is not NotImplemented :
602- fmpq_mpoly_sub_fmpq((< fmpq_mpoly> self ).val, (< fmpq_mpoly> self ).val, (< fmpq> other).val, self .ctx.val)
603- return
604- raise NotImplementedError (f" in-place subtraction not implemented between {type(self)} and {type(other)}" )
448+ def _isub_scalar_ (self , other: fmpq ):
449+ fmpq_mpoly_sub_fmpq(self .val, self .val, other.val, self .ctx.val)
605450
606- def imul (self , other ):
607- """
608- In-place multiplication, mutates self.
451+ def _isub_mpoly_ (self , other: fmpq_mpoly ):
452+ fmpq_mpoly_sub(self .val, self .val, other.val, self .ctx.val)
609453
610- >>> from flint import Ordering
611- >>> ctx = fmpq_mpoly_ctx.get_context(2, Ordering.lex, 'x')
612- >>> f = ctx.from_dict({(1, 0): 2, (0, 1): 3, (1, 1): 4})
613- >>> f
614- 4*x0*x1 + 2*x0 + 3*x1
615- >>> f.imul(2)
616- >>> f
617- 8*x0*x1 + 4*x0 + 6*x1
454+ def _imul_scalar_ (self , other: fmpq ):
455+ fmpq_mpoly_scalar_mul_fmpq(self .val, self .val, other.val, self .ctx.val)
618456
619- """
620- if typecheck(other, fmpq_mpoly):
621- if (< fmpq_mpoly> self ).ctx is not (< fmpq_mpoly> other).ctx:
622- raise IncompatibleContextError(f" {(<fmpq_mpoly>self).ctx} is not {(<fmpq_mpoly>other).ctx}" )
623- fmpq_mpoly_mul((< fmpq_mpoly> self ).val, (< fmpq_mpoly> self ).val, (< fmpq_mpoly> other).val, self .ctx.val)
624- return
625- else :
626- other = any_as_fmpq(other)
627- if other is not NotImplemented :
628- fmpq_mpoly_scalar_mul_fmpq(self .val, (< fmpq_mpoly> self ).val, (< fmpq> other).val, self .ctx.val)
629- return
630- raise NotImplementedError (f" in-place multiplication not implemented between {type(self)} and {type(other)}" )
457+ def _imul_mpoly_ (self , other: fmpq_mpoly ):
458+ fmpq_mpoly_mul(self .val, self .val, other.val, self .ctx.val)
631459
632460 def monoms (self ):
633461 """
0 commit comments