summaryrefslogtreecommitdiff
path: root/src/poly.ml
diff options
context:
space:
mode:
Diffstat (limited to 'src/poly.ml')
-rw-r--r--src/poly.ml186
1 files changed, 186 insertions, 0 deletions
diff --git a/src/poly.ml b/src/poly.ml
new file mode 100644
index 0000000..ed32263
--- /dev/null
+++ b/src/poly.ml
@@ -0,0 +1,186 @@
+
+
+(* Programmed by Jedidiah Barber *)
+(* Licensed under the Sunset License v1.0 *)
+
+
+module PolyMap = Map.Make(Z)
+
+type t = Z.t PolyMap.t
+
+
+
+let zero =
+ PolyMap.empty
+
+let one =
+ PolyMap.singleton Z.zero Z.one
+
+let singleton ~coeff ~expnt =
+ if coeff = Z.zero
+ then zero
+ else PolyMap.singleton expnt coeff
+
+let ( ~$ ) (a, b) =
+ singleton ~coeff:a ~expnt:b
+
+
+
+let of_int a =
+ PolyMap.singleton Z.zero (Z.of_int a)
+
+let of_zint a =
+ PolyMap.singleton Z.zero a
+
+
+
+let of_arraylist_helper p (coeff,expnt) =
+ if coeff = Z.zero then p
+ else if PolyMap.mem expnt p
+ then PolyMap.add expnt Z.((PolyMap.find expnt p) + coeff) p
+ else PolyMap.add expnt coeff p
+
+let to_list a =
+ List.rev_map (fun (expnt,coeff) -> (coeff,expnt)) (PolyMap.bindings a)
+
+let of_list a =
+ List.fold_left of_arraylist_helper zero a
+
+let to_array a =
+ Array.of_list (to_list a)
+
+let of_array a =
+ Array.fold_left of_arraylist_helper zero a
+
+
+
+let degree p =
+ match (PolyMap.max_binding_opt p) with
+ None -> Z.zero
+ | Some (k,v) -> k
+
+let get_coeff ~expnt p =
+ match (PolyMap.find_opt expnt p) with
+ None -> Z.zero
+ | Some v -> v
+
+
+
+let stringifier (coeff, expnt) =
+ let sign_str = if coeff < Z.zero then "-" else "+" in
+ let coeff_str =
+ if Z.abs coeff = Z.one && expnt <> Z.zero
+ then ""
+ else Z.to_string (Z.abs coeff) in
+ let expnt_str =
+ if expnt = Z.zero
+ then ""
+ else if expnt = Z.one
+ then "x"
+ else "x^" ^ (Z.to_string expnt) in
+ (sign_str, coeff_str ^ expnt_str)
+
+let to_string a =
+ let pieces = List.map stringifier (to_list a)
+ in if List.length pieces = 0
+ then "0"
+ else let first_term_sign = if fst (List.hd pieces) = "-" then "-" else "" in
+ let first_term = first_term_sign ^ (snd (List.hd pieces)) in
+ let term_concat s (x,y) = s ^ " " ^ x ^ " " ^ y in
+ let remaining_terms = List.fold_left term_concat "" (List.tl pieces) in
+ first_term ^ remaining_terms
+
+let print a =
+ print_string (to_string a)
+
+let output channel a =
+ output_string channel (to_string a)
+
+let pp_print format a =
+ let pieces = List.map stringifier (to_list a) in
+ let do_first item =
+ if fst item = "-" then Format.pp_print_string format "-";
+ Format.pp_print_string format (snd item) in
+ let do_rest item =
+ Format.pp_print_string format (" " ^ (fst item));
+ Format.pp_print_space format ();
+ Format.pp_print_string format (snd item) in
+ if List.length pieces = 0
+ then Format.pp_print_string format "0"
+ else (do_first (List.hd pieces); List.iter do_rest (List.tl pieces))
+
+
+
+let neg =
+ PolyMap.map Z.neg
+
+let add a b =
+ let f key x y =
+ if Z.(x + y) = Z.zero
+ then None
+ else Some Z.(x + y)
+ in PolyMap.union f a b
+
+let sub a b =
+ let f key x y =
+ match (x, y) with
+ (None, None) -> None
+ | (Some v, None) -> Some v
+ | (None, Some v) -> Some Z.(~- v)
+ | (Some v1, Some v2) ->
+ if Z.(v1 - v2) = Z.zero
+ then None
+ else Some Z.(v1 - v2)
+ in PolyMap.merge f a b
+
+let single_mul expnt coeff p =
+ let helper expnt2 coeff2 r =
+ PolyMap.add Z.(expnt + expnt2) Z.(coeff * coeff2) r
+ in PolyMap.fold helper p zero
+
+let mul a b =
+ PolyMap.fold (fun k v result -> add result (single_mul k v b)) a zero
+
+let div_rem a b =
+ let rec helper dividend quotient remainder =
+ if dividend = zero
+ then (quotient, remainder)
+ else if degree b > degree dividend
+ then (quotient, add dividend remainder)
+ else let (dsor_expnt, dsor_coeff) = PolyMap.max_binding b in
+ let (dend_expnt, dend_coeff) = PolyMap.max_binding dividend in
+ let (coeff_div, coeff_rem) = Z.div_rem dend_coeff dsor_coeff in
+ let expnt_diff = Z.(dend_expnt - dsor_expnt) in
+ let divisor_adjusted = single_mul expnt_diff coeff_div b in
+ let dividend_adjusted = sub dividend divisor_adjusted in
+ let new_dividend = PolyMap.remove dend_expnt dividend_adjusted in
+ let new_quotient =
+ if coeff_div <> Z.zero
+ then PolyMap.add expnt_diff coeff_div quotient
+ else quotient in
+ let new_remainder =
+ if coeff_rem <> Z.zero
+ then PolyMap.add dend_expnt coeff_rem remainder
+ else remainder in
+ helper new_dividend new_quotient new_remainder
+ in if b = zero
+ then raise Division_by_zero
+ else helper a zero zero
+
+let div a b =
+ fst (div_rem a b)
+
+let rem a b =
+ snd (div_rem a b)
+
+
+
+let ( + ) = add
+
+let ( - ) = sub
+
+let ( * ) = mul
+
+let ( / ) = div
+
+