(* Sparse or dense matrices *)

open Lacaml.D

type t

(** {1 Accessors} *)

val is_sparse : t -> bool
(** True is the matrix is sparse. *)

val is_dense : t -> bool
(** True is the matrix is dense. *)

val dim1 : t -> int
(** First dimension of the matrix *)

val dim2 : t -> int
(** Secons dimension of the matrix *)

val get : t -> int -> int -> float
(** [get m i j] returns {% $\mathbf{m}_{ij}$ %}. *)


(** {1 Converters } *)

val to_mat : t -> Mat.t
(** Convert into a Lacaml Mat. *)

val to_vector_array : ?threshold:float -> t -> Vector.t array
(** Convert the matrix into an array of column vectors. *)

val of_fun : int -> int -> (int -> int -> float) -> t
(** [of_fun m n f] creates a computed matrix of dimension m times n, where the function 
    [f i j] is called to evaluate element [i j] *)

val sparse_of_dense : ?threshold:float -> t -> t
(** Creates a sparse matrix from a dense matrix. Default threshold is {!Constants.epsilon}. *)

val sparse_of_computed : ?threshold:float -> t -> t
(** Creates a sparse matrix from a computed matrix. *)

val dense_of_computed : t -> t
(** Creates a dense matrix from a computed matrix. *)

val dense_of_sparse : t -> t
(** Creates a dense matrix from a sparse matrix. *)

val dense_of_mat : Mat.t -> t
(** Create a dense matrix from a Lacaml Mat *)

val sparse_of_mat : ?threshold:float -> Lacaml.D.Mat.t -> t
(** Create a sparse matrix from a Lacaml Mat. Default threshold is {!Constants.epsilon}. *)

val sparse_of_vector_array : Vector.t array -> t
(** Create a sparse matrix from an array of column vectors. *)

val transpose : t -> t
(** Returns the transposed matrix. *)

val split_cols : int -> t -> t list
(** [split_cols n m_M] Split the matrix [m_M] by packs of [n] columns *)

val join_cols : t list -> t
(** [join_cols l] Joins the list of matrices into a single matrix (along columns). *)


(** {1 Operations} *)

val outer_product : ?threshold:float -> Vector.t -> Vector.t -> t
(** Creates the matrix formed by the outer product of two vectors. *)

val mm : ?transa:trans3 -> ?transb:trans3 -> ?threshold:float -> t -> t -> t
(** Matrix multiplication *)

val mv : ?sparse:bool -> ?trans:trans3 -> ?threshold:float -> t -> Vector.t -> Vector.t
(** Matrix Vector product *)

val ax_eq_b : ?trans:trans3 -> t -> t -> t
(** Solves A.X = B or A'.X = B *)

val add : t -> t -> t
(** Add two matrices *)

val sub : t -> t -> t
(** Subtract two matrices *)


(** {1 Parallel routines } *)

val parallel_mm : ?transa:trans3 -> ?transb:trans3 -> ?threshold:float -> t -> t -> t
(** Matrix multiplication, parallelized by splitting b along the columns. *)

(** {1 Printers } *)

val pp : Format.formatter -> t -> unit


(** {1 Unit testing} *)

val test_case : unit -> (string * [> `Quick ] * (unit -> unit)) list
