├── .gitignore ├── META ├── Makefile ├── README.md ├── lib ├── Makefile └── numcaml │ ├── error.ml │ ├── math.ml │ ├── matrix.ml │ ├── type.ml │ └── vector.ml ├── syntax ├── Makefile └── pa_numcaml.ml └── tests ├── Makefile ├── README.md ├── floats.ml ├── ints.ml ├── matrices.ml ├── numcaml-notebook.ipynb ├── suite.ml ├── tests.ml └── vectors.ml /.gitignore: -------------------------------------------------------------------------------- 1 | *.cmo 2 | *.cmi 3 | *.cmx 4 | *.o 5 | *~ 6 | .*.swp 7 | -------------------------------------------------------------------------------- /META: -------------------------------------------------------------------------------- 1 | version = "0.1.0" 2 | description = "Scientific Computing Tools For OCaml" 3 | archive(byte) = "numcaml.cmo" 4 | archive(native) = "numcaml.cmx" 5 | 6 | 7 | package "syntax" ( 8 | version = "0.1.0" 9 | requires = "numcaml,camlp4" 10 | archive(syntax,preprocessor) = "pa_numcaml.cmo" 11 | archive(syntax,toploop) = "pa_numcaml.cmo" 12 | ) 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean lib syntax tests 2 | 3 | all: lib syntax 4 | @ 5 | 6 | lib: 7 | $(MAKE) -C lib 8 | 9 | syntax: 10 | $(MAKE) -C syntax 11 | 12 | tests: all 13 | $(MAKE) -C tests 14 | 15 | install: 16 | ocamlfind install numcaml \ 17 | META \ 18 | lib/numcaml.cmi lib/numcaml.cmo lib/numcaml.o lib/numcaml.cmx \ 19 | syntax/pa_numcaml.cmo 20 | 21 | uninstall: 22 | ocamlfind remove numcaml 23 | 24 | clean: 25 | $(MAKE) -C lib clean 26 | $(MAKE) -C syntax clean 27 | $(MAKE) -C tests clean 28 | - find . -name "*~" | xargs rm 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WARNING : numcaml is in early prototype stage. Any contribution/feedback is welcome! 2 | 3 | The goal of numcaml is to be able to deal with numerical computations more easily in Objective Caml. 4 | More precisly, it consists of 3 parts : 5 | 6 | * a camlp4 syntax extension; 7 | * a complete and efficient library; and 8 | * a collection of visualisation tools. 9 | 10 | Numcaml is mainly inspired from the great [numpy](numpy.scipy.org/) library for python. 11 | The static types of Objective Caml (and the lack of automatic upcasting) makes it difficult to port 12 | numpy directly as a library. For example : 13 | 14 | 1 + 2.3 15 | 16 | is valid in python because the integer `1` can be upcasted to the float `1.`, and `+` looks dynamically 17 | at the type of its arguments to know which code to execute. In Objective Caml, the expression is 18 | rejected because `+` is a function which *must* takes two integers as arguments. 19 | 20 | The syntax extension of numcaml let you write : 21 | 22 | $(1 + 2.3) 23 | 24 | inside your Objective Caml programm. This expression is translated, at pre-processing stage, into : 25 | 26 | Math.add (Math.Int 1) (Math.Float 2.3) 27 | 28 | and `Math.add` will do the same dynamic dispatch as python is doing for `+`. 29 | 30 | You can see more complete examples of using the numcaml library in the `tests/` directory. 31 | 32 | -------------------------------------------------------------------------------- /lib/Makefile: -------------------------------------------------------------------------------- 1 | FILES = \ 2 | type \ 3 | error \ 4 | vector \ 5 | matrix \ 6 | math 7 | 8 | CMX = $(FILES:%=numcaml/%.cmx) 9 | CMO = $(FILES:%=numcaml/%.cmo) 10 | 11 | %.cmx: %.ml 12 | ocamlopt -c -for-pack Numcaml -I numcaml $*.ml 13 | 14 | %.cmo: %.ml 15 | ocamlc -c -for-pack Numcaml -I numcaml $*.ml 16 | 17 | .PHONY: all clean 18 | all: $(CMX) $(CMO) 19 | ocamlopt -pack -o numcaml.cmx $(CMX) 20 | ocamlc -pack -o numcaml.cmo $(CMO) 21 | 22 | clean: 23 | rm -f *.cmx *.o *.cmi *.cmo 24 | rm -f numcaml/*.cmx numcaml/*.o numcaml/*.cmi numcaml/*.cmo 25 | -------------------------------------------------------------------------------- /lib/numcaml/error.ml: -------------------------------------------------------------------------------- 1 | (* 2 | * Copyright (c) 2011 Thomas Gazagnaire 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | *) 16 | 17 | type t = 18 | | No_attribute of Type.t * string (* 'int' has no attribute 'shape' *) 19 | | Not_aligned (* objects are not aligned *) 20 | | Unsupported of string * Type.t * Type.t (* unsupported operand type(s) for +: 'int' and 'str' *) 21 | | Uncastable of Type.t * Type.t 22 | 23 | let sf = Printf.sprintf 24 | 25 | let fail = function 26 | | No_attribute (t, a) -> failwith (sf "'%s' has no attribute '%s'" (Type.to_string t) a) 27 | | Not_aligned -> failwith "objects are not aligned" 28 | | Unsupported (s,t,u) -> 29 | let msg = 30 | sf "unsupported operand type(s) for %s: '%s' and '%s'" 31 | s (Type.to_string t) (Type.to_string u) in 32 | failwith msg 33 | | Uncastable (t1,t2) -> 34 | failwith (sf "'%s' cannot be upcasted to '%s'" (Type.to_string t1) (Type.to_string t2)) 35 | 36 | let no_attribute t a = fail (No_attribute (t, a)) 37 | let not_aligned () = fail Not_aligned 38 | let unsupported s t u = fail (Unsupported (s,t,u)) 39 | let uncastable t1 t2 = fail (Uncastable (t1,t2)) 40 | -------------------------------------------------------------------------------- /lib/numcaml/math.ml: -------------------------------------------------------------------------------- 1 | (* 2 | * Copyright (c) 2011 Thomas Gazagnaire 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | *) 16 | 17 | module T = Type 18 | 19 | type t = 20 | | Int of int 21 | | Int32 of int32 22 | | Int64 of int64 23 | | Float of float 24 | | Complex of Complex.t 25 | | Vector of t Vector.t 26 | | Matrix of t Matrix.t 27 | 28 | let rec type_of_t = function 29 | | Int _ -> T.Int 30 | | Int32 _ -> T.Int32 31 | | Int64 _ -> T.Int64 32 | | Float _ -> T.Float 33 | | Complex _ -> T.Complex 34 | | Vector x -> 35 | T.Vector { 36 | T.v_t = type_of_t x.(0); 37 | v_n = Array.length x; 38 | } 39 | | Matrix x -> 40 | T.Matrix { 41 | T.m_t = type_of_t x.(0).(0); 42 | m_n = Array.length x; 43 | m_m = Array.length x.(0); 44 | } 45 | 46 | let rec upcast v t = match (v, t) with 47 | 48 | (* Int *) 49 | | Int _, T.Int -> v 50 | | Int x, T.Int32 -> Int32 (Int32.of_int x) 51 | | Int x, T.Int64 -> Int64 (Int64.of_int x) 52 | | Int x, T.Float -> Float (float x) 53 | | Int x, T.Complex -> Complex { Complex.re = float x; im = 0. } 54 | 55 | (* Int32 *) 56 | | Int32 _, T.Int32 -> v 57 | | Int32 x, T.Int64 -> Int64 (Int64.of_int32 x) 58 | | Int32 x, T.Float -> Float (Int32.to_float x) 59 | | Int32 x, T.Complex -> Complex { Complex.re = Int32.to_float x; im = 0. } 60 | 61 | (* Int64 *) 62 | | Int64 _, T.Int64 -> v 63 | | Int64 x, T.Float -> Float (Int64.to_float x) 64 | | Int64 x, T.Complex -> Complex { Complex.re = Int64.to_float x; im = 0. } 65 | 66 | (* Float *) 67 | | Float _, T.Float -> v 68 | | Float x, T.Complex -> Complex { Complex.re = x; im = 0. } 69 | 70 | (* Complex *) 71 | | Complex x, T.Complex -> v 72 | 73 | (* Vector *) 74 | | Vector _, T.Vector u when u.T.v_t=t -> v 75 | | Vector x, T.Vector u -> Vector (Vector.map (fun e -> upcast e u.T.v_t) x) 76 | | Vector x, T.Matrix u -> 77 | begin 78 | match type_of_t x.(0) with 79 | | T.Vector y -> 80 | let aux = function 81 | | Vector x -> x 82 | | _ -> assert false in 83 | let xx = Array.map aux x in 84 | Matrix (Matrix.map (fun e -> upcast e u.T.m_t) xx) 85 | | _ -> 86 | Matrix (Vector.map (fun e -> [| upcast e u.T.m_t |]) x) 87 | end 88 | 89 | (* Matrix *) 90 | | Matrix _, T.Matrix u when u.T.m_t=t -> v 91 | | Matrix x, T.Matrix u -> Matrix (Matrix.map (fun e -> upcast e u.T.m_t) x) 92 | 93 | | _, T.Vector u -> Vector (Vector.make u.T.v_n (upcast v u.T.v_t)) 94 | | _, T.Matrix u -> Matrix (Matrix.make u.T.m_n u.T.m_m (upcast v u.T.m_t)) 95 | 96 | | _ -> Error.uncastable (type_of_t v) t 97 | 98 | let upcast_apply fn x y = 99 | let tx = type_of_t x in 100 | let ty = type_of_t y in 101 | let t = T.top tx ty in 102 | fn (upcast x t) (upcast y t) 103 | 104 | let rec add x y = match (x, y) with 105 | | Int x, Int y -> Int (x+y) 106 | | Int32 x, Int32 y -> Int32 (Int32.add x y) 107 | | Int64 x, Int64 y -> Int64 (Int64.add x y) 108 | | Float x, Float y -> Float (x +. y) 109 | | Complex x, Complex y -> Complex (Complex.add x y) 110 | | Vector x, Vector y -> 111 | Vector.check_size x y; 112 | Vector (Vector.map2 add x y) 113 | | Matrix x, Matrix y -> 114 | Matrix.check_size x y; 115 | Matrix (Matrix.map2 add x y) 116 | | _ , _ -> upcast_apply add x y 117 | 118 | let rec mul x y = match (x, y) with 119 | | Int x, Int y -> Int (x * y) 120 | | Int32 x, Int32 y -> Int32 (Int32.mul x y) 121 | | Int64 x, Int64 y -> Int64 (Int64.mul x y) 122 | | Float x, Float y -> Float (x *. y) 123 | | Complex x, Complex y -> Complex (Complex.add x y) 124 | | Vector x, Vector y -> 125 | Vector.check_size x y; 126 | Vector (Vector.map2 mul x y) 127 | | Matrix x, Matrix y -> Matrix (Matrix.mul add mul x y) 128 | | _ , _ -> upcast_apply mul x y 129 | 130 | let shape x = 131 | let rec aux = function 132 | | Vector x -> Array.length x :: aux x.(0) 133 | | Matrix x -> Array.length x :: Array.length x.(0) :: aux x.(0).(0) 134 | | _ -> [] in 135 | match x with 136 | | Vector x -> Array.length x :: aux x.(0) 137 | | Matrix x -> Array.length x :: Array.length x.(0) :: aux x.(0).(0) 138 | | _ -> Error.no_attribute (type_of_t x) "shape" 139 | 140 | let rec zeros = function 141 | | [] -> Vector [| Int 0 |] 142 | | [i] -> Vector (Array.init i (fun _ -> Int 0)) 143 | | i::t -> Vector (Array.init i (fun _ -> zeros t)) 144 | 145 | let rec ones = function 146 | | [] -> Vector [| Int 1 |] 147 | | [i] -> Vector (Array.init i (fun _ -> Int 1)) 148 | | i::t -> Vector (Array.init i (fun _ -> ones t)) 149 | 150 | let id n = 151 | let m = Matrix.make n n (Int 0) in 152 | for i = 0 to n-1 do 153 | m.(i).(i) <- Int 1 154 | done; 155 | Matrix m 156 | 157 | let vector v = Vector v 158 | let matrix m = Matrix m 159 | 160 | let mathjax x = 161 | let rec mathjax = function 162 | | Int x -> string_of_int x 163 | | Int32 x -> Int32.to_string x ^ "_{l}" 164 | | Int64 x -> Int64.to_string x ^ "_{L}" 165 | | Float x -> string_of_float x 166 | | Complex x -> string_of_float x.Complex.re ^ "+" ^ string_of_float x.Complex.im ^ "i" 167 | | Vector x -> 168 | let x = Array.map (fun x -> mathjax x ^ "\\\\") x in 169 | String.concat "\n" ("\\begin{pmatrix}" :: Array.to_list x @ ["\\end{pmatrix}"]) 170 | 171 | | Matrix x -> 172 | let x = 173 | Array.map 174 | (fun x -> 175 | let x = Array.to_list x in 176 | let rec f = function 177 | | [] -> " \\\\" 178 | | [x] -> mathjax x ^ " \\\\" 179 | | x::y -> mathjax x ^ " & " ^ f y 180 | in 181 | f x 182 | ) x 183 | in 184 | String.concat "\n" ("\\begin{bmatrix}" :: Array.to_list x @ ["\\end{bmatrix}"]) 185 | in 186 | String.concat "" [ "$$"; mathjax x; "$$" ] 187 | 188 | -------------------------------------------------------------------------------- /lib/numcaml/matrix.ml: -------------------------------------------------------------------------------- 1 | (* 2 | * Copyright (c) 2011 Thomas Gazagnaire 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | *) 16 | 17 | type 'a t = 'a array array 18 | 19 | let make = Array.make_matrix 20 | 21 | let check_size x y = 22 | Vector.check_size x y; 23 | Vector.check_size x.(0) y.(0) 24 | 25 | let map fn x = 26 | Array.map (fun x0 -> 27 | Array.map (fun e -> fn e) x0 28 | ) x 29 | 30 | let map2 fn x y = 31 | Array.mapi (fun i x0 -> 32 | Array.mapi (fun j e -> fn e y.(i).(j)) x0 33 | ) y 34 | 35 | let shape x = 36 | Array.length x, Array.length x.(0) 37 | 38 | let mul _add _mul x y = 39 | let a, m = shape x in 40 | let n, b = shape y in 41 | 42 | if m <> n then 43 | Error.not_aligned (); 44 | 45 | let c = Array.create_matrix a b x.(0).(0) in 46 | 47 | (* XXX: use C/Fortran bindings here *) 48 | for i = 0 to a-1 do 49 | for j = 0 to b-1 do 50 | c.(i).(j) <- _mul x.(i).(0) y.(0).(j); 51 | for k = 1 to n-1 do 52 | c.(i).(j) <- _add c.(i).(j) (_mul x.(i).(k) y.(k).(j)) 53 | done 54 | done 55 | done; 56 | 57 | c 58 | -------------------------------------------------------------------------------- /lib/numcaml/type.ml: -------------------------------------------------------------------------------- 1 | (* 2 | * Copyright (c) 2011 Thomas Gazagnaire 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | *) 16 | 17 | let sf = Printf.sprintf 18 | 19 | type t = 20 | | Int 21 | | Int32 22 | | Int64 23 | | Float 24 | | Complex 25 | | Vector of vector 26 | | Matrix of matrix 27 | 28 | (* XXX: we can optimize representation of 'a vector ... vector *) 29 | and vector = { 30 | v_t : t; 31 | v_n : int; (* XXX: in this case, this should be v_shape: int list *) 32 | } 33 | 34 | and matrix = { 35 | m_t : t; 36 | m_n : int; 37 | m_m : int; 38 | } 39 | 40 | let rec to_string = function 41 | | Int -> "int" 42 | | Int32 -> "int32" 43 | | Int64 -> "int64" 44 | | Float -> "float" 45 | | Complex -> "complex" 46 | | Vector v -> sf "%s vector[%d]" (to_string v.v_t) v.v_n 47 | | Matrix m -> sf "%s matrix[%d,%d]" (to_string m.m_t) m.m_m m.m_n 48 | 49 | (* Find the smallest type consistent with t1 and t2 *) 50 | let rec top t1 t2 = 51 | if t1=t2 then t1 else 52 | match (t1, t2) with 53 | (* Vector/Matrix *) 54 | | Vector x, Vector y -> Vector { v_t = top x.v_t y.v_t; v_n = 0 } 55 | | Vector x, Matrix y 56 | | Matrix y, Vector x -> Matrix { m_t = top x.v_t y.m_t; m_n = 0; m_m = 0 } 57 | | Matrix x, Matrix y -> Matrix { m_t = top x.m_t y.m_t; m_n = 0; m_m = 0 } 58 | | Vector x, t 59 | | t , Vector x -> Vector { x with v_t = top t x.v_t } 60 | | Matrix x, t 61 | | t , Matrix x -> Matrix { x with m_t = top t x.m_t } 62 | 63 | (* Complex *) 64 | | Complex, Int 65 | | Complex, Int32 66 | | Complex, Int64 67 | | Complex, Float 68 | | Int , Complex 69 | | Int32 , Complex 70 | | Int64 , Complex 71 | | Float , Complex -> Complex 72 | 73 | (* Float *) 74 | | Float, Int 75 | | Float, Int32 76 | | Float, Int64 77 | | Int , Float 78 | | Int32, Float 79 | | Int64, Float -> Float 80 | 81 | (* Int64 *) 82 | | Int64, Int 83 | | Int64, Int32 84 | | Int , Int64 85 | | Int32, Int64 -> Int64 86 | 87 | (* Int32 *) 88 | | Int32, Int 89 | | Int , Int32 -> Int32 90 | 91 | | _ -> assert false 92 | 93 | -------------------------------------------------------------------------------- /lib/numcaml/vector.ml: -------------------------------------------------------------------------------- 1 | (* 2 | * Copyright (c) 2011 Thomas Gazagnaire 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | *) 16 | 17 | type 'a t = 'a array 18 | 19 | let make = Array.make 20 | 21 | let check_size x y = 22 | if Array.length x <> Array.length y then 23 | Error.not_aligned () 24 | 25 | let map = Array.map 26 | 27 | let map2 fn x y = 28 | Array.mapi (fun i e -> fn e y.(i)) x 29 | -------------------------------------------------------------------------------- /syntax/Makefile: -------------------------------------------------------------------------------- 1 | P4_INC = $(shell ocamlc -where)/camlp4 2 | PP = camlp4o -I $(P4_INC) \ 3 | -parser Camlp4GrammarParser \ 4 | -parser Camlp4QuotationCommon \ 5 | -parser Camlp4OCamlRevisedQuotationExpander 6 | 7 | .PHONY: all clean 8 | all: 9 | ocamlc -I $(P4_INC) -pp "$(PP)" -c pa_numcaml.ml 10 | 11 | clean: 12 | rm -f *.cmo *.cmi 13 | -------------------------------------------------------------------------------- /syntax/pa_numcaml.ml: -------------------------------------------------------------------------------- 1 | (* 2 | * Copyright (c) 2011 Thomas Gazagnaire 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | *) 16 | 17 | open Camlp4 18 | 19 | module Id : Sig.Id = 20 | struct 21 | let name = "numcaml" 22 | let version = "0.1" 23 | end 24 | 25 | module Make (Syntax : Sig.Camlp4Syntax) = 26 | struct 27 | open Sig 28 | include Syntax 29 | 30 | let map = object (self) 31 | inherit Ast.map as super 32 | 33 | method expr e = 34 | let _loc = Ast.loc_of_expr e in 35 | match super#expr e with 36 | 37 | | <:expr< $int:i$ >> -> <:expr< Math.Int $int:i$ >> 38 | | <:expr< $int32:i$ >> -> <:expr< Math.Int32 $int32:i$ >> 39 | | <:expr< $int64:i$ >> -> <:expr< Math.Int64 $int64:i$ >> 40 | | <:expr< $flo:i$ >> -> <:expr< Math.Float $flo:i$ >> 41 | 42 | | <:expr< $e1$ + $e2$ >> -> <:expr< Math.add $e1$ $e2$ >> 43 | | <:expr< $e1$ * $e2$ >> -> <:expr< Math.mul $e1$ $e2$ >> 44 | 45 | | <:expr< ( $e1$ : int ) >> -> <:expr< Math.Int $e1$ >> 46 | | <:expr< ( $e1$ : int32 ) >> -> <:expr< Math.Int32 $e1$ >> 47 | | <:expr< ( $e1$ : int64 ) >> -> <:expr< Math.Int64 $e1$ >> 48 | | <:expr< ( $e1$ : float ) >> -> <:expr< Math.Float $e1$ >> 49 | 50 | | <:expr< ( $e1$ : vector $lid:t$) >> -> 51 | let constr = String.capitalize t in 52 | <:expr< Math.Vector (Array.map (fun e -> Math.$uid:constr$ e) $e1$) >> 53 | | <:expr< ( $e1$ : matrix $lid:t$) >> -> <:expr< Math.Matrix $e1$ >> 54 | 55 | | e -> e 56 | 57 | end 58 | 59 | EXTEND Gram 60 | expr: LEVEL "top" 61 | [ 62 | [ "$"; "("; e = expr; ")" -> map#expr e ] 63 | ]; 64 | END 65 | end 66 | 67 | module M = Register.OCamlSyntaxExtension(Id)(Make) 68 | 69 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | P4_INC = $(shell ocamlc -where)/camlp4 2 | 3 | TESTS = \ 4 | tests \ 5 | ints \ 6 | floats \ 7 | vectors \ 8 | matrices \ 9 | suite 10 | 11 | CMX = $(TESTS:%=%.cmx) 12 | 13 | PP = camlp4o -I $(P4_INC) ../syntax/pa_numcaml.cmo 14 | 15 | .PHONY: all rebuild clean 16 | all: tests ../lib/numcaml.cmx ../syntax/pa_numcaml.cmo 17 | ./tests 18 | 19 | clean: 20 | rm -f tests *.cmx *.cmi *.o 21 | 22 | rebuild: 23 | $(MAKE) clean 24 | $(MAKE) all 25 | 26 | tests: $(CMX) 27 | ocamlopt -I ../lib numcaml.cmx $(CMX) -o tests 28 | 29 | %.cmx: %.ml ../syntax/pa_numcaml.cmo 30 | ocamlopt -pp "$(PP)" -I ../lib -c $*.ml 31 | 32 | %_exp.ml: %.ml ../syntax/pa_numcaml.cmo 33 | camlp4o -printer o -I $(P4_INC) ../syntax/pa_numcaml.cmo $*.ml 34 | 35 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | You can have a look at the files content after the syntax extension step. Just write : 2 | 3 | make ints_epx.ml 4 | 5 | to see the content of `ints.ml` for instance. 6 | -------------------------------------------------------------------------------- /tests/floats.ml: -------------------------------------------------------------------------------- 1 | open Tests 2 | open Numcaml 3 | 4 | let test_add () = 5 | let x = $(1.4 + 2) in 6 | let y = $(3.4) in 7 | "values match" @? (x=y) 8 | 9 | let test_mul () = 10 | let x = $(1.3+2*3.1) in 11 | let y = Math.Float (1.3 +. 2. *. 3.1) in 12 | "value match" @? (x=y) 13 | 14 | let suite = [ 15 | "float_add" >:: test_add; 16 | "float_mul" >:: test_mul; 17 | ] 18 | -------------------------------------------------------------------------------- /tests/ints.ml: -------------------------------------------------------------------------------- 1 | open Tests 2 | open Numcaml 3 | 4 | let test_add () = 5 | let x = $(1 + 2) in 6 | let y = $(3) in 7 | "values match" @? (x=y) 8 | 9 | let test_mul () = 10 | let x = $(1+2*3) in 11 | let y = $(7) in 12 | "value match" @? (x=y) 13 | 14 | let test_aq () = 15 | let x = 3 in 16 | let y = $(4 + (x:int)) in 17 | let z = 7 in 18 | "value match" @? (y = $( (z:int) )) 19 | 20 | let suite = [ 21 | "int_add" >:: test_add; 22 | "int_mul" >:: test_mul; 23 | "int_aq" >:: test_aq; 24 | ] 25 | -------------------------------------------------------------------------------- /tests/matrices.ml: -------------------------------------------------------------------------------- 1 | open Tests 2 | open Numcaml 3 | 4 | let id = Math.id 2 5 | let ones = Math.ones [2;2] 6 | 7 | let test_mul () = 8 | let x = $( 2.4 * id ) in 9 | let y = $( Math.matrix [| [| 2;3 |]; [| 4;5 |] |] ) in 10 | let _ : Math.t = $( x*y + ones*4l ) in 11 | () 12 | 13 | let suite = [ 14 | "matrix_mul" >:: test_mul; 15 | ] 16 | -------------------------------------------------------------------------------- /tests/numcaml-notebook.ipynb: -------------------------------------------------------------------------------- 1 | {"metadata":{"name":"","language":"ocaml"},"worksheets":[{"cells":[{"metadata":{},"cell_type":"heading","source":"IOCaml support for numcaml","level":1},{"metadata":{},"input":"#require \"numcaml.syntax\";;\n#require \"iocaml-kernel.notebook\";;","cell_type":"code","prompt_number":1,"outputs":[{"output_type":"stream","text":"\tCamlp4 Parsing version 4.01.0\n\n","stream":"stdout"},{"output_type":"stream","text":"/home/andyman/.opam/4.01.0-test/lib/numcaml: added to search path\n/home/andyman/.opam/4.01.0-test/lib/numcaml/numcaml.cmo: loaded\n/home/andyman/.opam/4.01.0-test/lib/numcaml/pa_numcaml.cmo: loaded\n","stream":"stderr"},{"output_type":"stream","text":"/home/andyman/.opam/4.01.0-test/lib/iocaml-kernel: added to search path\n","stream":"stderr"}],"language":"python","collapsed":false},{"metadata":{},"cell_type":"markdown","source":"Setup numcaml for the notebook (this could be done with a .iocamlinit file). Open the library and install a printer for `Numcaml.Math.t`."},{"metadata":{},"input":"open Numcaml","cell_type":"code","prompt_number":2,"outputs":[],"language":"python","collapsed":false},{"metadata":{},"input":"let numcaml_printer fmt x = \n Iocaml.display \"text/html\" (Math.mathjax x);\n Format.fprintf fmt \"\"","cell_type":"code","prompt_number":3,"outputs":[{"output_type":"pyout","prompt_number":3,"html":"
val numcaml_printer : Format.formatter -> Numcaml.Math.t -> unit = <fun>\n
","metadata":{}}],"language":"python","collapsed":false},{"metadata":{},"input":"#install_printer numcaml_printer","cell_type":"code","prompt_number":4,"outputs":[],"language":"python","collapsed":false},{"metadata":{},"cell_type":"markdown","source":"Different types of display"},{"metadata":{},"input":"$(23)","cell_type":"code","prompt_number":5,"outputs":[{"output_type":"display_data","html":"$$23$$","metadata":{}},{"output_type":"pyout","prompt_number":5,"html":"
- : Numcaml.Math.t = <mathjax>\n
","metadata":{}}],"language":"python","collapsed":false},{"metadata":{},"input":"$(23l)","cell_type":"code","prompt_number":6,"outputs":[{"output_type":"display_data","html":"$$23_{l}$$","metadata":{}},{"output_type":"pyout","prompt_number":6,"html":"
- : Numcaml.Math.t = <mathjax>\n
","metadata":{}}],"language":"python","collapsed":false},{"metadata":{},"input":"$(23L)","cell_type":"code","prompt_number":7,"outputs":[{"output_type":"display_data","html":"$$23_{L}$$","metadata":{}},{"output_type":"pyout","prompt_number":7,"html":"
- : Numcaml.Math.t = <mathjax>\n
","metadata":{}}],"language":"python","collapsed":false},{"metadata":{},"input":"$(23.1)","cell_type":"code","prompt_number":8,"outputs":[{"output_type":"display_data","html":"$$23.1$$","metadata":{}},{"output_type":"pyout","prompt_number":8,"html":"
- : Numcaml.Math.t = <mathjax>\n
","metadata":{}}],"language":"python","collapsed":false},{"metadata":{},"input":"let x = $(Math.vector [| 1;2l;3L;4. |]);;","cell_type":"code","prompt_number":9,"outputs":[{"output_type":"display_data","html":"$$\\begin{pmatrix}\n1\\\\\n2_{l}\\\\\n3_{L}\\\\\n4.\\\\\n\\end{pmatrix}$$","metadata":{}},{"output_type":"pyout","prompt_number":9,"html":"
val x : Numcaml.Math.t = <mathjax>\n
","metadata":{}}],"language":"python","collapsed":false},{"metadata":{},"input":"let y = $(Math.matrix [| [| 2l;1 |]; [| 3; 9. |] |])","cell_type":"code","prompt_number":10,"outputs":[{"output_type":"display_data","html":"$$\\begin{bmatrix}\n2_{l} & 1 \\\\\n3 & 9. \\\\\n\\end{bmatrix}$$","metadata":{}},{"output_type":"pyout","prompt_number":10,"html":"
val y : Numcaml.Math.t = <mathjax>\n
","metadata":{}}],"language":"python","collapsed":false},{"metadata":{},"input":"let ones,id = Math.ones [2;2], Math.id 2","cell_type":"code","prompt_number":11,"outputs":[{"output_type":"display_data","html":"$$\\begin{pmatrix}\n\\begin{pmatrix}\n1\\\\\n1\\\\\n\\end{pmatrix}\\\\\n\\begin{pmatrix}\n1\\\\\n1\\\\\n\\end{pmatrix}\\\\\n\\end{pmatrix}$$","metadata":{}},{"output_type":"display_data","html":"$$\\begin{bmatrix}\n1 & 0 \\\\\n0 & 1 \\\\\n\\end{bmatrix}$$","metadata":{}},{"output_type":"pyout","prompt_number":11,"html":"
val ones : Numcaml.Math.t = <mathjax>\nval id : Numcaml.Math.t = <mathjax>\n
","metadata":{}}],"language":"python","collapsed":false},{"metadata":{},"cell_type":"markdown","source":"A little bit of oddness. Not sure why Math.ones gives a vector of vectors. Definitely not sure what the following means."},{"metadata":{},"input":"$(id+ones)","cell_type":"code","prompt_number":12,"outputs":[{"output_type":"display_data","html":"$$\\begin{bmatrix}\n\\begin{pmatrix}\n2\\\\\n2\\\\\n\\end{pmatrix} & \\begin{pmatrix}\n2\\\\\n2\\\\\n\\end{pmatrix} \\\\\n\\begin{pmatrix}\n2\\\\\n2\\\\\n\\end{pmatrix} & \\begin{pmatrix}\n2\\\\\n2\\\\\n\\end{pmatrix} \\\\\n\\end{bmatrix}$$","metadata":{}},{"output_type":"pyout","prompt_number":12,"html":"
- : Numcaml.Math.t = <mathjax>\n
","metadata":{}}],"language":"python","collapsed":false},{"metadata":{},"cell_type":"markdown","source":"Typeing is a little strange as well. The types in the matrix `y` are mixed, but it seems to use the type of the first element. I think it should be some sort of upper bound on the required type instead."},{"metadata":{},"input":"Math.type_of_t y","cell_type":"code","prompt_number":13,"outputs":[{"output_type":"pyout","prompt_number":13,"html":"
- : Numcaml.Math.T.t =\nNumcaml.Math.T.Matrix\n {Numcaml.Math.T.m_t = Numcaml.Math.T.Int32; m_n = 2; m_m = 2}\n
","metadata":{}}],"language":"python","collapsed":false},{"metadata":{},"input":"","cell_type":"code","prompt_number":14,"outputs":[{"output_type":"pyout","prompt_number":14,"html":"
Syntax error.
","metadata":{}}],"language":"python","collapsed":false}],"metadata":{}}],"nbformat":3,"nbformat_minor":0} -------------------------------------------------------------------------------- /tests/suite.ml: -------------------------------------------------------------------------------- 1 | let suites = [ 2 | Ints.suite; 3 | Floats.suite; 4 | Vectors.suite; 5 | Matrices.suite; 6 | ] 7 | 8 | let _ = 9 | Tests.run "numcaml" (List.flatten suites) 10 | -------------------------------------------------------------------------------- /tests/tests.ml: -------------------------------------------------------------------------------- 1 | exception Fail of string 2 | 3 | let (@?) msg b = 4 | if not b then 5 | raise (Fail msg) 6 | 7 | let (>::) name test main = 8 | try 9 | test (); 10 | Printf.eprintf "%s %-20s OK\n" main name 11 | with Fail msg -> 12 | Printf.eprintf "%s %-20s FAIL(%s)\n" main name msg 13 | 14 | let run main suites = 15 | List.iter (fun s -> s main) suites 16 | -------------------------------------------------------------------------------- /tests/vectors.ml: -------------------------------------------------------------------------------- 1 | open Tests 2 | open Numcaml 3 | 4 | let one = Math.ones [10] 5 | 6 | let test_add () = 7 | let x = $(3.3 + one) in 8 | let y = Math.Vector (Array.create 10 (Math.Float 4.3)) in 9 | "values match" @? (x=y) 10 | 11 | let test_mul () = 12 | let x = $(7l * one) in 13 | let y = Math.Vector (Array.create 10 (Math.Int32 7l)) in 14 | "value match" @? (x=y) 15 | 16 | let test_q () = 17 | let x = $(Math.vector [| 1; 2l; 3; 4 |] ) in 18 | let y = $( x + 0l ) in 19 | let z = Math.Vector (Array.init 4 (fun i -> Math.Int32 (Int32.of_int (i+1)))) in 20 | "value match" @? (y = z) 21 | 22 | let test_aq () = 23 | let x = Array.init 10 (fun i -> i) in 24 | let y = $( 10.5 + (x : int vector)) in 25 | let z = Array.init 10 (fun i -> float i +. 10.5) in 26 | "value match" @? (y = $( (z : float vector) ) ) 27 | 28 | let suite = [ 29 | "vector_add" >:: test_add; 30 | "vector_mul" >:: test_mul; 31 | "vector_aq" >:: test_aq; 32 | "vector_q" >:: test_q; 33 | ] 34 | --------------------------------------------------------------------------------