@@ -13,6 +13,8 @@ cimport libc.stdlib
13
13
from typing import Optional
14
14
from flint.utils.flint_exceptions import IncompatibleContextError
15
15
16
+ from flint.types.fmpz cimport fmpz, any_as_fmpz
17
+
16
18
17
19
FLINT_BITS = _FLINT_BITS
18
20
FLINT_VERSION = _FLINT_VERSION.decode(" ascii" )
@@ -404,6 +406,48 @@ cdef class flint_mpoly(flint_elem):
404
406
def _add_mpoly_ (self , other ):
405
407
return NotImplemented
406
408
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
+
407
451
def __add__ (self , other ):
408
452
if typecheck(other, type (self )):
409
453
self .context().compatible_context_check(other.context())
@@ -418,6 +462,123 @@ cdef class flint_mpoly(flint_elem):
418
462
def __radd__ (self , other ):
419
463
return self .__add__ (other)
420
464
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
+
421
582
def __divmod__ (self , other ):
422
583
if typecheck(other, type (self )):
423
584
self ._division_check(other)
@@ -441,6 +602,75 @@ cdef class flint_mpoly(flint_elem):
441
602
other = self .context().scalar_as_mpoly(other)
442
603
return other._divmod_mpoly_(self )
443
604
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
+
444
674
def __contains__ (self , x ):
445
675
"""
446
676
Returns True if `self` contains a term with exponent vector `x` and a non-zero coefficient.
0 commit comments