(* basic operations over arrays. *)

(* map a combinatorial function *)
let map(l)(f)(x) = z where
  rec forall i in 0 .. (l - 1), xi in x, zi out z
        do zi = f xi done

(* sum of two arrays [x] and [y] of size [l] *)
let sum(l)(x, y) = z where
    rec
      forall i in 0 .. (l - 1), xi in x, yi in y, zi out z
        do
         zi = xi +. yi
        done

(* sum of two matrices [m1] and [m2] of size [l1 * l2] *)
let msum(l1)(l2)(m1, m2) = m3 where
    rec
      forall i in 0 .. (l1 - 1), m1i in m1, m2i in m2, m3i out m3 do
        forall j in 0 .. (l2 - 1), m1ij in m1i, m2ij in m2i, m3ij out m3i do
          m3ij = m1ij +. m2ij
        done
      done

(* the same but calling [vsum] *)
let msum2(l1)(l2)(m1, m2) = m3 where
    rec
      forall i in 0 .. (l1 - 1), m1i in m1, m2i in m2, m3i out m3 do
        m3i = sum(l2)(m1i, m2i)
      done

(* constant vector *)
let const(l)(x0) = o where
  rec forall i in 0 .. (l - 1), oi out o do oi = x0 done

(* scalar product of two vectors *)
let vvproduct(l)(x, y) = acc where
    rec
      forall i in 0 .. (l - 1), xi in x, yi in y
        do
          acc = (xi *. yi) +. last acc
        initialize
          last acc = 0.0
        done

(* product of a matrix and a vector *)
let mvproduct(l)(c)(m, v) = o where
    rec
      forall i in 0 .. (l - 1), mi in m, oi out o
        do
          oi = vvproduct(c)(mi, v)
        done

(* the same with two nested loops *)
let mvproduct2(l)(c)(m, v) = o where
  rec
      forall i in 0 .. (l - 1), mi in m, oi out o do
        forall j in 0 ..(c - 1), mij in mi, vj in v do
	  oi = (mij *. vj) +. last oi
        initialize
	  last oi = 0.0
	done
      done
	    
(* product of a matrix and a matrix *)
let mmproduct(l)(c)(m1, m2) = m3 where
  rec
      forall i in 0 .. (l - 1), m2i in m2, m3i out m3 do
	m3i = mvproduct(l)(c)(m1, m2i)
      done