(**************************************************************************) (* *) (* Copyright (C) Jean-Christophe Filliatre *) (* *) (* This software is free software; you can redistribute it and/or *) (* modify it under the terms of the GNU Library General Public *) (* License version 2.1, with the special exception on linking *) (* described in file LICENSE. *) (* *) (* This software is distributed in the hope that it will be useful, *) (* but WITHOUT ANY WARRANTY; without even the implied warranty of *) (* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *) (* *) (**************************************************************************) (* Polynomials over an abstract ring *) open Format module type Ring = sig type t val zero : t val one : t val add : t -> t -> t val neg : t -> t val mul : t -> t -> t val equal : t -> t -> bool val print : formatter -> t -> unit end let unknown = let u = ref (-1) in let rec gen u = if u < 26 then let c = if u < 3 then Char.code 'X' + u else Char.code 'A' + u - 3 in String.make 1 (Char.chr c) else gen (u / 26 - 1) ^ gen (u mod 26) in fun () -> incr u; gen !u module type Polynomial = sig type r include Ring val monomial : r -> int -> t val create: (r * int) list -> t val var : t val sub : t -> t -> t val deg : t -> int val leading_coeff : t -> r type monomial = private { coef : r; degree : int; } val view : t -> monomial list val eval : t -> r -> r end module Make(X : Ring) = struct type r = X.t type monomial = { coef : X.t; degree : int } (* coef <> X.zero *) type t = monomial list (* sorted in decr. degrees *) let view p = p let zero = [] let one = [ { coef = X.one; degree = 0 } ] let var = [ { coef = X.one; degree = 1 } ] let monomial c d = if X.equal c X.zero then [] else [{ coef = c; degree = d }] let deg = function [] -> -1 { degree = n } :: _ -> n let leading_coeff = function [] -> X.zero { coef = c } :: _ -> c let rec add p1 p2 = match p1, p2 with [], _ -> p2 _, [] -> p1 m1 :: r1, m2 :: r2 -> if m1.degree > m2.degree then m1 :: add r1 p2 else if m1.degree < m2.degree then m2 :: add p1 r2 else let c = X.add m1.coef m2.coef in if X.equal c X.zero then add r1 r2 else { coef = c; degree = m1.degree } :: add r1 r2 let create ml = List.fold_left (fun p (c, d) -> add (monomial c d) p) zero ml let neg = List.map (fun m -> { m with coef = X.neg m.coef }) let sub p1 p2 = add p1 (neg p2) let mul p1 p2 = let mul_monomial m p = List.fold_right (fun m' acc -> let c = X.mul m.coef m'.coef in if X.equal c X.zero then acc else { coef = c; degree = m.degree + m'.degree } :: acc) p [] in List.fold_left (fun p m -> add (mul_monomial m p2) p) zero p1 let rec power x n = if n == 0 then X.one else let y = power x (n / 2) in if n mod 2 == 0 then X.mul y y else X.mul x (X.mul y y) let rec eval p x = match p with [] -> X.zero m :: r -> X.add (X.mul m.coef (power x m.degree)) (eval r x) (* TODO: use a (tail-recursive) Horner schema *) let rec equal p1 p2 = match p1, p2 with [], [] -> true [], _ _, [] -> false m1 :: r1, m2 :: r2 -> m1.degree = m2.degree && X.equal m1.coef m2.coef && equal r1 r2 let var_name = unknown () let print fmt p = let rec print_aux = function [] -> () { coef = c; degree = n } :: r -> if not (X.equal c X.one) || n = 0 then fprintf fmt "(%a)" X.print c; if n <> 0 then fprintf fmt "%s" var_name; if n > 1 then fprintf fmt "^%d" n; if r <> [] then fprintf fmt " + "; print_aux r in match p with [] -> X.print fmt X.zero _ -> print_aux p end (** Polynomials over a field *) module type Field = sig include Ring val div : t -> t -> t end module type PolynomialF = sig include Polynomial val division : t -> t -> t * t end module MakeF(X : Field) = struct include Make(X) (* Knuth, vol 2, 4.6.1 *) let division u = function [] -> raise Division_by_zero { coef = vn; degree = n } :: v -> let rec loop k = function u when k < 0 -> [], u { coef = ui; degree = i } :: u when i = n + k -> let qk = X.div ui vn in let qkxk = monomial (X.neg qk) k in let q,r = loop (k - 1) (add u (mul qkxk v)) in { coef = qk; degree = k } :: q, r u -> loop (k - 1) u in loop (deg u - n) u end
This document was generated using caml2html