Разработка на коленке

"тут должна быть красивая цитата о программировании"

Умножение матриц на OCaml (с модулями)

2016-08-19 01:53

У меня новое развлечение - курс Нейронные сети. Сейчас у меня ликбез по линейной алгебре, а конкретно - умножение матриц. В одном уроке нужно было перемножить матрицы, что мне показалось неплохой возможностью написать кусок кода на OCaml.

Задача

Перемножить матрицы

    [1 0 0 0]   [1  2  3]   [3 0 0]
2 * [0 1 0 0] * [5  6  7] * [0 3 0] =
    [0 0 1 0]   [9 10 11]   [0 0 3]
    [0 0 0 1]   [4  8 12]

Решение

В этот раз мне хотелось сделать отдельный модуль с сигнатурой и без конкретных типов в сигнатурах.

matrix.mli

open Core.Std

type t

val of_list: int list list -> t

val of_array: int array array -> t

val mult_to_matrix: t -> t -> t

val mult_to_int: t -> int -> t

val to_string: t -> string

matrix.ml

open Core.Std


type t = int array array


let of_array a =
    Array.map a ~f: Array.copy


let of_list lst =
    List.to_array (List.map lst ~f: List.to_array)


let mult_to_matrix m1 m2 =
    let dimx = Array.length m1 in
    let dimy = Array.length m2.(0) in

    let vector_length = Array.length m2 in
    let mult_lines line_number column_number =
        List.range 0 vector_length
        |> List.map ~f:(fun k -> m1.(line_number).(k) * m2.(k).(column_number))
        |> List.reduce ~f:(+)
        |> Option.value ~default:0
    in

    let product = Array.make_matrix ~dimx ~dimy 0 in
    for i = 0 to dimx - 1 do
        for j = 0 to dimy - 1 do
            product.(i).(j) <- mult_lines i j
        done;
    done;

    product


let mult_to_int matrix multiplier =
    matrix |> Array.map ~f:(fun line -> Array.map line ~f:(fun i -> i * multiplier))


let to_string matrix =
    Array.map matrix ~f:(fun line ->
        Array.map line ~f:Int.to_string |> String.concat_array ~sep:", "
    ) |> String.concat_array ~sep: "; "

product.ml

open Core.Std


let () =
    let a = Matrix.of_array [|
        [|1; 0; 0; 0|];
        [|0; 1; 0; 0|];
        [|0; 0; 1; 0|];
        [|0; 0; 0; 1|];
    |] in
    let b = Matrix.of_list [
        [1; 2;  3];
        [5; 6;  7];
        [9; 10; 11];
        [4; 8;  12]
    ] in
    let c = Matrix.of_list [
        [3; 0; 0];
        [0; 3; 0];
        [0; 0; 3];
    ] in

    Matrix.mult_to_int (Matrix.mult_to_matrix (Matrix.mult_to_matrix a b) c) 2
    |> Matrix.to_string
    |> printf "%s\n"

Заключение

Результат прошёл проверку задания, хотя решить задачу вручную на листе бумаги было бы гораздо быстрее, потому что достаточно было из третьей матрицы сделать единичную, а потом умножить матрицу b на 6. Но сейчас мне важно практиковаться в разработке на OCaml.

Записи процесса разработки в этот раз не будет, во-первых, разработка была не в один присест, а во-вторых, ничего интересного там нет.