Zulip Chat Archive

Stream: new members

Topic: error with (zmod p)


Lucas Allen (Oct 05 2020 at 04:24):

Hello, I've been doing some stuff relating to computing things with polynomials. For this I defined a class poly and algorithms for adding, multiplying, dividing, gcd, etc. Now I want to do some stuff with zmop p (where p is prime), and I'm getting the error,

type mismatch at application
  poly_gcd f
term
  f
has type
  poly (zmod p)
but is expected to have type
  poly ?m_1"

when I try to do division or gcd. I think the problem might be that division and gcd want zmod p to be a field. All the operations which want zmod p to be a ring work. Unfortunately, I don't know how to get Lean to figure out that zmod p is a field. When I try,

import tactic
import data.zmod.basic
import Poly

open zmod
open tactic

#check zmod.field
instance xxx (p : ) [fact (prime p)] : field (zmod p) := infer_instance
instance ttt : field (zmod 7) := infer_instance

I get the error "failed to synthesize type class instance for ⊢ field (zmod 7)". How can I get this to work?

Johan Commelin (Oct 05 2020 at 05:32):

https://github.com/leanprover-community/mathlib/blob/master/src/data/zmod/basic.lean#L787

Johan Commelin (Oct 05 2020 at 05:33):

I have no idea why this is failing for you....

Mario Carneiro (Oct 05 2020 at 05:40):

It says right there - you need an instance of fact (prime 7) to satisfy the instance

Lucas Allen (Oct 05 2020 at 05:49):

Ok, instance ttt [fact (prime 7)] : field (zmod 7) := infer_instance works, but why doesn't instance xxx (p : ℕ) [fact (prime p)] : field (zmod p) := infer_instance work?

Markus Himmel (Oct 05 2020 at 05:50):

prime is not the same as nat.prime

Lucas Allen (Oct 05 2020 at 05:51):

Also, I still get the error,

type mismatch at application
  poly_div_quot_rem p
term
  p
has type
  poly (zmod 7)
but is expected to have type
  poly ?m_1"

when attempting division or gcd.

Lucas Allen (Oct 05 2020 at 05:51):

(deleted)

Lucas Allen (Oct 05 2020 at 05:51):

Markus Himmel said:

prime is not the same as nat.prime

oh.

Lucas Allen (Oct 05 2020 at 05:54):

instance xxx (p : ℕ) [fact (nat.prime p)] : field (zmod p) := infer_instance works. But I still get the error.

Markus Himmel (Oct 05 2020 at 05:57):

Would you mind posting the code that generates the error?

Lucas Allen (Oct 05 2020 at 06:02):

So #eval poly_gcd p q gives the error, and poly_gcd is

def poly_gcd_aux {α : Type} [field α] [decidable_eq α] [inhabited α] :
    poly α  poly α  poly α
| 0     P Q := P
| (n+1) P Q := if Q = 0 then P else poly_gcd_aux n Q (P %ₚ Q)

def poly_gcd {α : Type} [field α] [decidable_eq α] [inhabited α] (P Q : poly α) :
  poly α := poly_gcd_aux (deg P) P Q

I'm not sure where to stop posting code. Should I just post the whole file?

Lucas Allen (Oct 05 2020 at 06:03):

And

def p : poly (zmod 7) := ⟨[1,2,3]⟩
def q : poly (zmod 7) := ⟨[1,1]⟩

Also, poly_gcd isn't finished yet, the higher degree poly goes first, so don't judge me too harshly.

Markus Himmel (Oct 05 2020 at 06:11):

Does #eval poly_gcd p q give you the error about poly_div_quot_rem you posted earlier or a different error?

Lucas Allen (Oct 05 2020 at 06:14):

Yeah, same thing

type mismatch at application
  poly_gcd p
term
  p
has type
  poly (zmod 7)
but is expected to have type
  poly ?m_1

Lucas Allen (Oct 05 2020 at 06:15):

I thought it was something to do with defining poly_div_quot_rem and poly_gcd using [field \a] instead of [ring \a], since the operations with [ring \a] work and the operations with [field \a] don't.

Lucas Allen (Oct 05 2020 at 06:16):

I'll just post all the code...

Lucas Allen (Oct 05 2020 at 06:17):

Here's the Poly file

import tactic
import algebra.ring.basic

/--
Let's make polynomials lists!
so [1,2,3] represents the polynomial
1 + 2x + 3x²
-/
class poly (α : Type) [ring α] :=
(cofs : list α)

lemma poly_eq_iff {α : Type} [ring α] [decidable_eq α] (P Q : poly α) : P = Q  P.cofs = Q.cofs :=
begin
  split,
  { intro,
    tactic.unfreeze_local_instances,
    cases P, cases Q,
    exact congr_arg _ a, },
  { intro,
    tactic.unfreeze_local_instances,
    cases P, cases Q,
    exact congr_arg poly.mk a, }
end

def poly_eq {α : Type} [ring α] [decidable_eq α] (P Q : poly α) : Prop := P.cofs = Q.cofs
def poly_eq_bool {α : Type} [ring α] [decidable_eq α] (P Q : poly α) : bool := P.cofs = Q.cofs

instance {α : Type} [ring α] [decidable_eq α] [inhabited α] : has_equiv (poly α) := poly_eq

instance {α : Type} [ring α] [decidable_eq α] [inhabited α] : decidable_eq (poly α) :=
begin
  intros a b,
  rw poly_eq_iff,
  cases a, cases b,
  haveI j : decidable (a = b) := infer_instance,
  exact j,
end

/-- `X` is the polynomial variable (aka indeterminant). Lifted from polynomial.basic in mathlib-/
def X {α : Type} [ring α] [has_one α] [has_zero α] : poly α :=
begin
  apply poly.mk,
  exact [0,1],
end

def list_remove_leading_zeros {α : Type} [ring α] [has_zero α] [decidable_eq α] : list α  list α
| []     := [0]
| (h::t) := if h = 0 then list_remove_leading_zeros t else h::t

def remove_leading_zeros {α : Type} [ring α] [has_zero α] [decidable_eq α] (P : poly α) : poly α :=
begin
  apply poly.mk,
  exact (list_remove_leading_zeros P.cofs.reverse).reverse,
end

def deg {α : Type} [ring α] [decidable_eq α] (P : poly α) :  :=
  (list_remove_leading_zeros P.cofs.reverse).length - 1

/--The zero polynomial-/
instance {α : Type} [ring α] [has_zero α] : has_zero (poly α) :=
begin
  apply has_zero.mk,
  apply poly.mk,
  exact [0],
end

/--The one polynomial-/
instance {α : Type} [ring α] [has_one α] : has_one (poly α) :=
begin
  apply has_one.mk,
  apply poly.mk,
  exact [1],
end

/-- Representation of polynomials -/
def list_to_string {α : Type} [ring α] [has_repr α] [decidable_eq α] : list α  string
| []     := ""
| [h]    := repr h
| (h::t) := if h = 0
            then list_to_string t
            else (repr h ++ "X^" ++ (repr t.length) ++ " + ") ++ (list_to_string t)

instance {α : Type} [ring α] [has_repr α] [decidable_eq α] : has_repr (poly α) :=
λ p, list_to_string p.cofs.reverse

/--returns the leading cof-/
def list_lead {α : Type} [ring α] [inhabited α] (a : list α) : α := a.reverse.head

def lead {α : Type} [ring α] [inhabited α] (P : poly α) : α := list_lead P.cofs

/--return the negative Poly-/
def list_poly_neg {α : Type} [ring α] : list α  list α
| []     := []
| (h::t) := (-h) :: list_poly_neg t

def poly_neg {α : Type} [ring α] (P : poly α) : poly α :=
begin
  apply poly.mk,
  exact list_poly_neg P.cofs,
end

instance {α : Type} [ring α] : has_neg (poly α) := poly_neg

/--adds two Polys together-/
def list_poly_add {α : Type} [ring α] : list α  list α  list α
| []     Q      := Q
| P      []     := P
| (h::t) (u::v) := (h + u) :: (list_poly_add t v)

def poly_add {α : Type} [ring α] [decidable_eq α] (P Q : poly α) : poly α :=
begin
  apply remove_leading_zeros,
  apply poly.mk,
  exact (list_poly_add P.cofs Q.cofs),
end

instance {α : Type} [ring α] [decidable_eq α] : has_add (poly α) := poly_add
instance {α : Type} [ring α] [decidable_eq α] : has_sub (poly α) :=
begin
  apply has_sub.mk,
  intros P Q,
  exact P + -Q,
end

/--Scalar multiplication-/
def list_poly_scalar_mul {α : Type} [ring α] (t : α) (P : list α) : list α :=
P.map (λ c, t * c)

def poly_scalar_mul {α : Type} [ring α] [decidable_eq α] (t : α) (P : poly α) : poly α :=
begin
  apply remove_leading_zeros,
  apply poly.mk,
  exact (list_poly_scalar_mul t P.cofs),
end

/--The derivative-/
def list_poly_deriv {α : Type} [ring α] : list α  list α
| []     := []
| [a]    := []
| (h::t) := (h * (t.length)) :: list_poly_deriv t

def poly_deriv {α : Type} [ring α] (P : poly α) : poly α :=
begin
  apply poly.mk,
  exact (list_poly_deriv P.cofs.reverse).reverse,
end

/--polynomial modulo some number-/
def list_poly_mod {α : Type} [ring α] [has_mod α] (n : α) : list α  list α
| []     := []
| (h::t) := (h % n) :: list_poly_mod t

def poly_mod {α : Type} [ring α] [decidable_eq α] [has_mod α] (n : α) (P : poly α) : poly α :=
begin
  apply remove_leading_zeros,
  apply poly.mk,
  exact list_poly_mod n P.cofs,
end

infix ` •ₚ `:88 := poly_scalar_mul
prefix ` dₚ `:80 := poly_deriv

/--Polynomial multiplication-/
def list_poly_mul {α : Type} [ring α] (P Q : list α) : list α :=
begin
  induction P,
  { use ([]), },
  { have Qxp : list α, from list_poly_scalar_mul P_hd Q,
    exact list_poly_add (0::P_ih) Qxp },
end

def poly_mul {α : Type} [ring α] [decidable_eq α] (P Q : poly α) : poly α :=
begin
  apply remove_leading_zeros,
  apply poly.mk,
  exact (list_poly_mul P.cofs.reverse Q.cofs.reverse).reverse,
end

instance {α : Type} [ring α] [decidable_eq α] : has_mul (poly α) := poly_mul

-- instance {α : Type} [ring α] : ring (poly α) :=
-- begin
--   apply ring.mk,
--   repeat {sorry},
-- end

/--Polynomial division-/
--Note: Polynomial division works only for polynomials over a field.

def list_Xn {α : Type} [ring α] [has_one α] [has_zero α] :   list α
| 0     := [1]
| (n+1) := 0 :: list_Xn n

def Xn {α : Type} [ring α] [has_one α] [has_zero α] (n : ) : poly α := poly.mk (list_Xn n)

def list_poly_div {α : Type} [field α] [decidable_eq α] [inhabited α] (Q : poly α) :
    poly α  poly α  poly α × poly α
| 0     q r := (q,r)
| (n+1) q r := if deg r < deg Q then (q,r)
               else do let rol := lead r / lead Q,
                       list_poly_div n (q + (rol •ₚ Xn (deg r - deg Q))) (r - (rol •ₚ Q * Xn (deg r - deg Q)))

def poly_div_quot_rem {α : Type} [field α] [decidable_eq α] [inhabited α] (P Q : poly α) : poly α × poly α :=
list_poly_div Q (deg P - deg Q + 1) 0 P

def poly_quot {α : Type} [field α] [decidable_eq α] [inhabited α] (P Q : poly α) : poly α :=
(poly_div_quot_rem P Q).1

def poly_rem {α : Type} [field α] [decidable_eq α] [inhabited α] (P Q : poly α) : poly α :=
(poly_div_quot_rem P Q).2

infix ` /ₚ `:87 := poly_quot
infix ` %ₚ `:88 := poly_rem

/--Polynomial GCD-/
--Note: this computes the gcd of polynomials over a field.
def poly_gcd_aux {α : Type} [field α] [decidable_eq α] [inhabited α] :
    poly α  poly α  poly α
| 0     P Q := P
| (n+1) P Q := if Q = 0 then P else poly_gcd_aux n Q (P %ₚ Q)

def poly_gcd {α : Type} [field α] [decidable_eq α] [inhabited α] (P Q : poly α) :
  poly α := poly_gcd_aux (deg P) P Q

And here's an MWE with the error

import tactic
import data.zmod.basic
import Poly

open zmod
open tactic

#check zmod.field
instance xxx (p : ) [fact (nat.prime p)] : field (zmod p) := infer_instance
instance ttt [fact (nat.prime 7)] : field (zmod 7) := infer_instance

def p : poly (zmod 7) := ⟨[1,2,3]⟩
def q : poly (zmod 7) := ⟨[1,1]⟩

#eval poly_add p q  --works
#eval poly_neg p    --works
#eval poly_deriv p  --works
#eval poly_mul p q  --works
#eval poly_div_quot_rem p q --FAILS!
#eval poly_gcd p q  --FAILS!

Kevin Buzzard (Oct 05 2020 at 06:19):

Do you need to put fact (nat.prime 7) into the type class inference system? It won't be there automatically

Kevin Buzzard (Oct 05 2020 at 06:21):

ie instance : fact (nat.prime 7) := by unfold fact; norm_num?

Lucas Allen (Oct 05 2020 at 06:22):

Yes! that fixed it. Thanks.


Last updated: Dec 20 2023 at 11:08 UTC