在 SML 中将两个矩阵相乘
Multiply two matrices in SML
我想在 SML/NJ 中编写一个函数,它将 2 个矩阵作为参数并将它们相乘。
我只能用:
函数点,取2个向量并计算标量积:
fun dot (xs: int list, ys: int list): int =
List.foldl (fn (x,y) => x+y)
0
(ListPair.map (fn (x,y) => x*y) (xs, ys))
函数转置,取1个矩阵并计算该矩阵的转置:
fun transpose (m: 'a list list): 'a list list =
List.tabulate (List.length (List.nth (m, 0)),
fn x => List.map (fn y => (List.nth (y, x))) m)
匿名函数
结构列表、列表对和数学
我要写的函数应该是这样的:
fun multiply (a: int list list, b: int list list): int list list
到目前为止我已经这样做了:
fun multiply (a: int list list, b: int list list): int list list =
case a of
[] => []
| g::rep => [(List.map (fn y => dot(g, y)) transpose(b))] @ (multiply(rep, b))
但是我得到了这个错误:
test.sml:66.21-66.62 Error: operator and operand do not agree [tycon mismatch]
operator domain: int list list
operand: 'Z list list -> 'Z list list
in expression:
(List.map (fn y => dot <exp>)) transpose
如果在函数乘法的最后一行我写 b 而不是 tranpose(b),我没有得到任何错误,但是当然,如果我这样做,我不会得到我想要的结果:
fun multiply (a: int list list, b: int list list): int list list =
case a of
[] => []
| g::rep => [(List.map (fn y => dot(g, y)) b)] @ (multiply(rep, b))
我不知道我还应该做什么。有人可以帮我吗?
存在 a solution for OCaml on RosettaCode 可以翻译。
鉴于插图,
| [ a, [ c,
| b ] d ]
---------+-------------
[ 1, 2 ] | w x
[ 3, 4 ] | y z
然后对第一个矩阵的每一行,计算与第二个矩阵列相同的dot
乘积。 IE。 w = dot ([1, 2], [a, b])
。提取第一个矩阵的行很容易,因为您可以使用列表递归。
提取第二个矩阵的列不太容易,因为它们与列表表示正交(即 a
是第一行的第一个元素,b
是第二行,c
是第一行的第二个元素,d
是第二行的第二个元素。
您可以通过执行 transpose
来简化从第二个矩阵中提取列,在这种情况下,提取列等同于提取行。此时,您可以采用 "rows" 的成对 dot
乘积(即第一个矩阵中的行和第二个矩阵中的转置列 ("rows"))。
我鼓励对此类操作使用 Array2
,因为当您的 "matrices"(列表)参差不齐(具有不同的行长度)时,您也可以避免错误处理。
至少我用你的方案成功了
exception dim_Error;
fun listPair (l1:int list) (l2:int list): (int * int) List.list =
`if not (List.length l1 = List.length l2) then raise dim_Error
else List.tabulate (List.length l1, fn i => (List.nth(l1, i),List.nth(l2, i)));`
fun dotprod (l1:int list) (l2:int list): int =
List.foldl (fn (x,y) => x+y) 0 (map (fn (x,y) => x*y) (listPair l1 l2));
fun transpose (matrix: int list list):int list list =
List.tabulate (List.length (List.nth (matrix, 0)), fn i => List.map (fn j => List.nth (j, i)) matrix);
fun multiply (matrix1: int list list) (matrix2: int list list): int list list =
case matrix1 of
[] => []
| x::xr => [List.map (fn y => dotprod x y) (transpose matrix2)] @ (multiply xr matrix2);
val A = [[ 21, ~2, 3, ~1], [ 2, 115, 6, 7], [ ~6, 9, 210, 11], [ 13, 14, ~19, 15], [ ~2, 21, ~99, 3], [ 5, ~4, ~1, 9]];
val B = [[2, ~6, 0, 3, 9], [~4, ~1, 2, 1, ~2], [~6, 5, 3, ~5, 1], [10, 9, ~4, 9, ~7]];
val C = [[~4, ~3, 7], [1, ~1, ~2], [~5, 3, 7], [8, ~7, 2], [~8, 3, 6]];
multiply (multiply A B) C;
我想在 SML/NJ 中编写一个函数,它将 2 个矩阵作为参数并将它们相乘。
我只能用:
函数点,取2个向量并计算标量积:
fun dot (xs: int list, ys: int list): int = List.foldl (fn (x,y) => x+y) 0 (ListPair.map (fn (x,y) => x*y) (xs, ys))
函数转置,取1个矩阵并计算该矩阵的转置:
fun transpose (m: 'a list list): 'a list list = List.tabulate (List.length (List.nth (m, 0)), fn x => List.map (fn y => (List.nth (y, x))) m)
匿名函数
结构列表、列表对和数学
我要写的函数应该是这样的:
fun multiply (a: int list list, b: int list list): int list list
到目前为止我已经这样做了:
fun multiply (a: int list list, b: int list list): int list list =
case a of
[] => []
| g::rep => [(List.map (fn y => dot(g, y)) transpose(b))] @ (multiply(rep, b))
但是我得到了这个错误:
test.sml:66.21-66.62 Error: operator and operand do not agree [tycon mismatch]
operator domain: int list list
operand: 'Z list list -> 'Z list list
in expression:
(List.map (fn y => dot <exp>)) transpose
如果在函数乘法的最后一行我写 b 而不是 tranpose(b),我没有得到任何错误,但是当然,如果我这样做,我不会得到我想要的结果:
fun multiply (a: int list list, b: int list list): int list list =
case a of
[] => []
| g::rep => [(List.map (fn y => dot(g, y)) b)] @ (multiply(rep, b))
我不知道我还应该做什么。有人可以帮我吗?
存在 a solution for OCaml on RosettaCode 可以翻译。
鉴于插图,
| [ a, [ c,
| b ] d ]
---------+-------------
[ 1, 2 ] | w x
[ 3, 4 ] | y z
然后对第一个矩阵的每一行,计算与第二个矩阵列相同的dot
乘积。 IE。 w = dot ([1, 2], [a, b])
。提取第一个矩阵的行很容易,因为您可以使用列表递归。
提取第二个矩阵的列不太容易,因为它们与列表表示正交(即 a
是第一行的第一个元素,b
是第二行,c
是第一行的第二个元素,d
是第二行的第二个元素。
您可以通过执行 transpose
来简化从第二个矩阵中提取列,在这种情况下,提取列等同于提取行。此时,您可以采用 "rows" 的成对 dot
乘积(即第一个矩阵中的行和第二个矩阵中的转置列 ("rows"))。
我鼓励对此类操作使用 Array2
,因为当您的 "matrices"(列表)参差不齐(具有不同的行长度)时,您也可以避免错误处理。
至少我用你的方案成功了
exception dim_Error;
fun listPair (l1:int list) (l2:int list): (int * int) List.list =
`if not (List.length l1 = List.length l2) then raise dim_Error
else List.tabulate (List.length l1, fn i => (List.nth(l1, i),List.nth(l2, i)));`
fun dotprod (l1:int list) (l2:int list): int =
List.foldl (fn (x,y) => x+y) 0 (map (fn (x,y) => x*y) (listPair l1 l2));
fun transpose (matrix: int list list):int list list =
List.tabulate (List.length (List.nth (matrix, 0)), fn i => List.map (fn j => List.nth (j, i)) matrix);
fun multiply (matrix1: int list list) (matrix2: int list list): int list list =
case matrix1 of
[] => []
| x::xr => [List.map (fn y => dotprod x y) (transpose matrix2)] @ (multiply xr matrix2);
val A = [[ 21, ~2, 3, ~1], [ 2, 115, 6, 7], [ ~6, 9, 210, 11], [ 13, 14, ~19, 15], [ ~2, 21, ~99, 3], [ 5, ~4, ~1, 9]];
val B = [[2, ~6, 0, 3, 9], [~4, ~1, 2, 1, ~2], [~6, 5, 3, ~5, 1], [10, 9, ~4, 9, ~7]];
val C = [[~4, ~3, 7], [1, ~1, ~2], [~5, 3, 7], [8, ~7, 2], [~8, 3, 6]];
multiply (multiply A B) C;