@@ -680,17 +680,19 @@ cdef class fmpz_mpoly(flint_mpoly):
680
680
fmpz vres
681
681
fmpz_mpoly_struct ** C
682
682
ulong * exponents
683
- slong i, prev_i, nvars = self .ctx.nvars(), nargs = len (args)
683
+ slong i, nvars = self .ctx.nvars(), nargs = len (args)
684
684
685
- if args and kwargs:
686
- raise ValueError (" only supply positional or keyword arguments" )
687
- elif not args and not kwargs:
685
+ if not args and not kwargs:
688
686
return self
687
+ elif args and kwargs:
688
+ raise ValueError (" only supply positional or keyword arguments" )
689
+ elif len (args) < nvars and not kwargs:
690
+ raise ValueError (" partial application requires keyword arguments" )
689
691
690
692
if kwargs:
691
693
# Sort and filter the provided keyword args to only valid ones
692
- args = tuple ((i, kwargs[x]) for i, x in enumerate (self .ctx.names()) if x in kwargs)
693
- nargs = len (args )
694
+ partial_args = tuple ((i, kwargs[x]) for i, x in enumerate (self .ctx.names()) if x in kwargs)
695
+ nargs = len (partial_args )
694
696
695
697
# If we've been provided with an invalid keyword arg then the length of our filter
696
698
# args will be less than what we've been provided with.
@@ -699,25 +701,20 @@ cdef class fmpz_mpoly(flint_mpoly):
699
701
if nargs < len (kwargs):
700
702
raise ValueError (" unknown keyword argument provided" )
701
703
elif nargs == nvars:
702
- args = tuple (x for _, x in args)
703
- partial = False
704
- else :
705
- partial = True
704
+ args = tuple (arg for _, arg in partial_args)
705
+ kwargs = None
706
706
elif nargs > nvars:
707
707
raise ValueError (" more arguments provided than variables" )
708
- elif nargs < nvars:
709
- # Positional partial application
710
- args = tuple ((i, x) for i, x in enumerate (args))
711
- partial = True
712
708
713
- if partial :
714
- args_fmpz = tuple (any_as_fmpz(v) for _, v in args )
709
+ if kwargs :
710
+ args_fmpz = tuple (any_as_fmpz(v) for _, v in partial_args )
715
711
else :
716
712
args_fmpz = tuple (any_as_fmpz(v) for v in args)
717
713
718
714
all_fmpz = NotImplemented not in args_fmpz
719
715
720
- if not partial and all_fmpz:
716
+ if args and all_fmpz:
717
+ # Normal evaluation
721
718
try :
722
719
V = < fmpz_struct ** > libc.stdlib.malloc(nvars * sizeof(fmpz_struct * ))
723
720
for i in range (nvars):
@@ -728,19 +725,21 @@ cdef class fmpz_mpoly(flint_mpoly):
728
725
return vres
729
726
finally :
730
727
libc.stdlib.free(V)
731
- elif partial and all_fmpz:
728
+ elif kwargs and all_fmpz:
729
+ # Partial application with args in Z. We evaluate the polynomial one variable at a time
732
730
res = fmpz_mpoly.__new__ (fmpz_mpoly)
733
731
res2 = fmpz_mpoly.__new__ (fmpz_mpoly)
734
732
res.ctx = self .ctx
735
733
res2.ctx = self .ctx
736
734
737
735
fmpz_mpoly_set(res2.val, self .val, self .ctx.val)
738
- for (i, _), arg in zip (args , args_fmpz):
736
+ for (i, _), arg in zip (partial_args , args_fmpz):
739
737
if fmpz_mpoly_evaluate_one_fmpz(res.val, res2.val, i, (< fmpz> arg).val, self .ctx.val) == 0 :
740
738
raise ValueError (" unreasonably large polynomial" )
741
739
fmpz_mpoly_set(res2.val, res.val, self .ctx.val)
742
740
return res
743
- elif not partial and not all_fmpz:
741
+ elif args and not all_fmpz:
742
+ # Complete function composition
744
743
res_ctx = (< fmpz_mpoly> args[0 ]).ctx
745
744
if not all (typecheck(args[i], fmpz_mpoly) and (< fmpz_mpoly> args[i]).ctx is res_ctx for i in range (1 , len (args))):
746
745
raise ValueError (" all arguments must share the same context" )
@@ -757,11 +756,15 @@ cdef class fmpz_mpoly(flint_mpoly):
757
756
finally :
758
757
libc.stdlib.free(C)
759
758
else :
759
+ # Partial function composition. We do this by composing with all arguments, however the ones
760
+ # that have not be provided are set to the trivial monomial. This is why we require all the
761
+ # polynomial itself, and all arguments exist in the same context, otherwise we have no way of
762
+ # finding the correct monomial to use.
760
763
if not all (typecheck(arg, fmpz_mpoly) and (< fmpz_mpoly> arg).ctx is self .ctx for _, arg in args):
761
764
raise ValueError (" the mpoly and all arguments must share the same context" )
762
765
763
766
polys = [None ] * nvars
764
- for i, poly in args :
767
+ for i, poly in partial_args :
765
768
polys[i] = poly
766
769
767
770
for i in range (nvars):
0 commit comments