@@ -2782,6 +2782,12 @@ def _all_mpolys():
27822782def test_mpolys ():
27832783 for P , get_context , S , is_field in _all_mpolys ():
27842784
2785+ # Division under modulo will raise a flint exception if something is not invertible, crashing the program. We
2786+ # can't tell before what is invertible and what is not before hand so we always raise an exception, except for
2787+ # fmpz_mpoly, that returns an bool noting if the division is exact or not.
2788+ division_not_supported = P is not flint .fmpz_mpoly and not is_field
2789+ characteristic_zero = not (P is flint .fmpz_mod_mpoly or P is flint .nmod_mpoly )
2790+
27852791 ctx = get_context (nvars = 2 )
27862792
27872793 assert raises (lambda : get_context (nvars = 2 , ordering = "bad" ), TypeError )
@@ -3045,7 +3051,7 @@ def quick_poly():
30453051 assert raises (lambda : quick_poly ().imul (P (ctx = ctx1 )), IncompatibleContextError )
30463052 assert raises (lambda : quick_poly ().imul (None ), NotImplementedError )
30473053
3048- if ( P is flint . fmpz_mod_mpoly or P is flint . nmod_mpoly ) and not ctx . is_prime () :
3054+ if division_not_supported :
30493055 assert raises (lambda : quick_poly () // mpoly ({(1 , 1 ): 1 }), DomainError )
30503056 assert raises (lambda : quick_poly () % mpoly ({(1 , 1 ): 1 }), DomainError )
30513057 assert raises (lambda : divmod (quick_poly (), mpoly ({(1 , 1 ): 1 })), DomainError )
@@ -3056,9 +3062,6 @@ def quick_poly():
30563062 assert divmod (quick_poly (), mpoly ({(1 , 1 ): 1 })) \
30573063 == (mpoly ({(1 , 1 ): 4 }), mpoly ({(1 , 0 ): 3 , (0 , 1 ): 2 , (0 , 0 ): 1 }))
30583064
3059- if (P is flint .fmpz_mod_mpoly or P is flint .nmod_mpoly ) and not ctx .is_prime ():
3060- pass
3061- else :
30623065 assert 1 / P (1 , ctx = ctx ) == P (1 , ctx = ctx )
30633066 assert quick_poly () / 1 == quick_poly ()
30643067 assert quick_poly () // 1 == quick_poly ()
@@ -3078,9 +3081,7 @@ def quick_poly():
30783081
30793082 f = mpoly ({(1 , 1 ): 4 , (0 , 0 ): 1 })
30803083 g = mpoly ({(0 , 1 ): 2 , (1 , 0 ): 2 })
3081- if (P is flint .fmpz_mod_mpoly or P is flint .nmod_mpoly ) and not ctx .is_prime ():
3082- pass
3083- else :
3084+ if not division_not_supported :
30843085 assert 1 // quick_poly () == P (ctx = ctx )
30853086 assert 1 % quick_poly () == P (1 , ctx = ctx )
30863087 assert divmod (1 , quick_poly ()) == (P (ctx = ctx ), P (1 , ctx = ctx ))
@@ -3089,43 +3090,44 @@ def quick_poly():
30893090 assert S (1 ) % quick_poly () == P (1 , ctx = ctx )
30903091 assert divmod (S (1 ), quick_poly ()) == (P (ctx = ctx ), P (1 , ctx = ctx ))
30913092
3092- assert raises (lambda : quick_poly () / None , TypeError )
3093- assert raises (lambda : quick_poly () // None , TypeError )
3094- assert raises (lambda : quick_poly () % None , TypeError )
3095- assert raises (lambda : divmod (quick_poly (), None ), TypeError )
3096-
3097- assert raises (lambda : None / quick_poly (), TypeError )
3098- assert raises (lambda : None // quick_poly (), TypeError )
3099- assert raises (lambda : None % quick_poly (), TypeError )
3100- assert raises (lambda : divmod (None , quick_poly ()), TypeError )
3101-
3102- assert raises (lambda : quick_poly () / 0 , ZeroDivisionError )
3103- assert raises (lambda : quick_poly () // 0 , ZeroDivisionError )
3104- assert raises (lambda : quick_poly () % 0 , ZeroDivisionError )
3105- assert raises (lambda : divmod (quick_poly (), 0 ), ZeroDivisionError )
3106-
3107- assert raises (lambda : 1 / P (ctx = ctx ), ZeroDivisionError )
3108- assert raises (lambda : 1 // P (ctx = ctx ), ZeroDivisionError )
3109- assert raises (lambda : 1 % P (ctx = ctx ), ZeroDivisionError )
3110- assert raises (lambda : divmod (1 , P (ctx = ctx )), ZeroDivisionError )
3111-
3112- assert raises (lambda : quick_poly () / P (ctx = ctx ), ZeroDivisionError )
3113- assert raises (lambda : quick_poly () // P (ctx = ctx ), ZeroDivisionError )
3114- assert raises (lambda : quick_poly () % P (ctx = ctx ), ZeroDivisionError )
3115- assert raises (lambda : divmod (quick_poly (), P (ctx = ctx )), ZeroDivisionError )
3116-
3117- assert raises (lambda : quick_poly () / P (1 , ctx = ctx1 ), IncompatibleContextError )
3118- assert raises (lambda : quick_poly () // P (1 , ctx = ctx1 ), IncompatibleContextError )
3119- assert raises (lambda : quick_poly () % P (1 , ctx = ctx1 ), IncompatibleContextError )
3120- assert raises (lambda : divmod (quick_poly (), P (1 , ctx = ctx1 )), IncompatibleContextError )
3121-
31223093 assert f * g / mpoly ({(0 , 1 ): 1 , (1 , 0 ): 1 }) \
31233094 == mpoly ({(1 , 1 ): 8 , (0 , 0 ): 2 })
31243095
31253096 if not is_field :
31263097 assert raises (lambda : 1 / quick_poly (), DomainError )
31273098 assert raises (lambda : quick_poly () / P (2 , ctx = ctx ), DomainError )
31283099
3100+ # We prefer various other errors to the "division not supported" domain error so these are safe.
3101+ assert raises (lambda : quick_poly () / None , TypeError )
3102+ assert raises (lambda : quick_poly () // None , TypeError )
3103+ assert raises (lambda : quick_poly () % None , TypeError )
3104+ assert raises (lambda : divmod (quick_poly (), None ), TypeError )
3105+
3106+ assert raises (lambda : None / quick_poly (), TypeError )
3107+ assert raises (lambda : None // quick_poly (), TypeError )
3108+ assert raises (lambda : None % quick_poly (), TypeError )
3109+ assert raises (lambda : divmod (None , quick_poly ()), TypeError )
3110+
3111+ assert raises (lambda : quick_poly () / 0 , ZeroDivisionError )
3112+ assert raises (lambda : quick_poly () // 0 , ZeroDivisionError )
3113+ assert raises (lambda : quick_poly () % 0 , ZeroDivisionError )
3114+ assert raises (lambda : divmod (quick_poly (), 0 ), ZeroDivisionError )
3115+
3116+ assert raises (lambda : 1 / P (ctx = ctx ), ZeroDivisionError )
3117+ assert raises (lambda : 1 // P (ctx = ctx ), ZeroDivisionError )
3118+ assert raises (lambda : 1 % P (ctx = ctx ), ZeroDivisionError )
3119+ assert raises (lambda : divmod (1 , P (ctx = ctx )), ZeroDivisionError )
3120+
3121+ assert raises (lambda : quick_poly () / P (ctx = ctx ), ZeroDivisionError )
3122+ assert raises (lambda : quick_poly () // P (ctx = ctx ), ZeroDivisionError )
3123+ assert raises (lambda : quick_poly () % P (ctx = ctx ), ZeroDivisionError )
3124+ assert raises (lambda : divmod (quick_poly (), P (ctx = ctx )), ZeroDivisionError )
3125+
3126+ assert raises (lambda : quick_poly () / P (1 , ctx = ctx1 ), IncompatibleContextError )
3127+ assert raises (lambda : quick_poly () // P (1 , ctx = ctx1 ), IncompatibleContextError )
3128+ assert raises (lambda : quick_poly () % P (1 , ctx = ctx1 ), IncompatibleContextError )
3129+ assert raises (lambda : divmod (quick_poly (), P (1 , ctx = ctx1 )), IncompatibleContextError )
3130+
31293131 assert quick_poly () ** 0 == P (1 , ctx = ctx )
31303132 assert quick_poly () ** 1 == quick_poly ()
31313133 assert quick_poly () ** 2 == mpoly ({
@@ -3146,29 +3148,34 @@ def quick_poly():
31463148 # # XXX: Not sure what this should do in general:
31473149 assert raises (lambda : pow (P (1 , ctx = ctx ), 2 , 3 ), NotImplementedError )
31483150
3149- if (P is not flint .fmpz_mod_mpoly and P is not flint .nmod_mpoly ) or f .context ().is_prime ():
3151+ if division_not_supported :
3152+ assert raises (lambda : (f * g ).gcd (f ), DomainError )
3153+ else :
31503154 if is_field :
31513155 assert (f * g ).gcd (f ) == f / 4
31523156 else :
31533157 assert (f * g ).gcd (f ) == f
31543158 assert raises (lambda : quick_poly ().gcd (None ), TypeError )
31553159 assert raises (lambda : quick_poly ().gcd (P (ctx = ctx1 )), IncompatibleContextError )
3156- else :
3157- assert raises (lambda : (f * g ).gcd (f ), DomainError )
31583160
3159- if P is flint .fmpz_mod_mpoly or P is flint .nmod_mpoly :
3160- if is_field :
3161- assert (f * g ).factor () == (S (8 ), [(mpoly ({(0 , 1 ): 1 , (1 , 0 ): 1 }), 1 ), (f / 4 , 1 )])
3161+ if division_not_supported :
3162+ # Factorisation not allowed over Z/nZ for n not prime.
3163+ # Flint would abort so we raise an exception instead:
3164+ assert raises (lambda : (f * g ).factor (), DomainError )
3165+ elif characteristic_zero :
3166+ # Primitive factors over Z for fmpz_mpoly and fmpq_mpoly
3167+ assert (f * g ).factor () == (S (2 ), [(g / 2 , 1 ), (f , 1 )])
3168+ elif is_field :
3169+ # Monic polynomials over Z/pZ for nmod_mpoly and fmpz_mod_mpoly
3170+ assert (f * g ).factor () == (S (8 ), [(g / 2 , 1 ), (f / 4 , 1 )])
3171+
3172+ if division_not_supported :
3173+ assert raises (lambda : (f * g ).sqrt (), DomainError )
31623174 else :
3163- assert (f * g ).factor () == (S (2 ), [(mpoly ({(0 , 1 ): 1 , (1 , 0 ): 1 }), 1 ), (f , 1 )])
3164-
3165- if (P is not flint .fmpz_mod_mpoly and P is not flint .nmod_mpoly ) or f .context ().is_prime ():
31663175 assert (f * f ).sqrt () == f
31673176 if P is flint .fmpz_mpoly :
31683177 assert (f * f ).sqrt (assume_perfect_square = True ) == f
31693178 assert raises (lambda : quick_poly ().sqrt (), ValueError )
3170- else :
3171- assert raises (lambda : (f * g ).sqrt (), DomainError )
31723179
31733180 p = quick_poly ()
31743181 assert p .derivative (0 ) == p .derivative ("x0" ) == mpoly ({(0 , 0 ): 3 , (1 , 2 ): 8 })
0 commit comments