Initial data commit
This commit is contained in:
parent
72d218235f
commit
f23f22d71c
199087 changed files with 3378941 additions and 0 deletions
3
Task/Matrix-chain-multiplication/00-META.yaml
Normal file
3
Task/Matrix-chain-multiplication/00-META.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
from: http://rosettacode.org/wiki/Matrix_chain_multiplication
|
||||
note: Discrete math
|
||||
27
Task/Matrix-chain-multiplication/00-TASK.txt
Normal file
27
Task/Matrix-chain-multiplication/00-TASK.txt
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
;Problem
|
||||
Using the most straightfoward algorithm (which we assume here), computing the [[Matrix multiplication|product of two matrices]] of dimensions (n1,n2) and (n2,n3) requires n1*n2*n3 [[wp:Multiply–accumulate_operation|FMA]] operations. The number of operations required to compute the product of matrices A1, A2... An depends on the order of matrix multiplications, hence on where parens are put. Remember that the matrix product is associative, but not commutative, hence only the parens can be moved.
|
||||
|
||||
For instance, with four matrices, one can compute A(B(CD)), A((BC)D), (AB)(CD), (A(BC))D, (AB)C)D. The number of different ways to put the parens is a [[Catalan numbers|Catalan number]], and grows exponentially with the number of factors.
|
||||
|
||||
Here is an example of computation of the total cost, for matrices A(5,6), B(6,3), C(3,1):
|
||||
|
||||
* AB costs 5*6*3=90 and produces a matrix of dimensions (5,3), then (AB)C costs 5*3*1=15. The total cost is 105.
|
||||
* BC costs 6*3*1=18 and produces a matrix of dimensions (6,1), then A(BC) costs 5*6*1=30. The total cost is 48.
|
||||
|
||||
In this case, computing (AB)C requires more than twice as many operations as A(BC). The difference can be much more dramatic in real cases.
|
||||
|
||||
;Task
|
||||
|
||||
Write a function which, given a list of the successive dimensions of matrices A1, A2... An, of arbitrary length, returns the optimal way to compute the matrix product, and the total cost. Any sensible way to describe the optimal solution is accepted. The input list does not duplicate shared dimensions: for the previous example of matrices A,B,C, one will only pass the list [5,6,3,1] (and ''not'' [5,6,6,3,3,1]) to mean the matrix dimensions are respectively (5,6), (6,3) and (3,1). Hence, a product of n matrices is represented by a list of n+1 dimensions.
|
||||
|
||||
Try this function on the following two lists:
|
||||
|
||||
* [1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2]
|
||||
* [1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10]
|
||||
|
||||
To solve the task, it's possible, but not required, to write a function that enumerates all possible ways to parenthesize the product. This is not optimal because of the many duplicated computations, and this task is a classic application of [[:wp:Dynamic programming|dynamic programming]].
|
||||
|
||||
See also [[:wp:Matrix chain multiplication|Matrix chain multiplication]] on Wikipedia.
|
||||
|
||||
__TOC__
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
T Optimizer
|
||||
[Int] dims
|
||||
[[Int]] m, s
|
||||
|
||||
F (dims)
|
||||
.dims = dims
|
||||
|
||||
F findMatrixChainOrder()
|
||||
V n = .dims.len - 1
|
||||
.m = [[0] * n] * n
|
||||
.s = [[0] * n] * n
|
||||
|
||||
L(lg) 1 .< n
|
||||
L(i) 0 .< n - lg
|
||||
V j = i + lg
|
||||
.m[i][j] = 7FFF'FFFF
|
||||
L(k) i .< j
|
||||
V cost = .m[i][k] + .m[k + 1][j] + .dims[i] * .dims[k + 1] * .dims[j + 1]
|
||||
I cost < .m[i][j]
|
||||
.m[i][j] = cost
|
||||
.s[i][j] = k
|
||||
|
||||
F optimalChainOrder(i, j)
|
||||
I i == j
|
||||
R String(Char(code' i + ‘A’.code))
|
||||
E
|
||||
R ‘(’(.optimalChainOrder(i, .s[i][j]))‘’
|
||||
‘’(.optimalChainOrder(.s[i][j] + 1, j))‘)’
|
||||
|
||||
V Dims1 = [5, 6, 3, 1]
|
||||
V Dims2 = [1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2]
|
||||
V Dims3 = [1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10]
|
||||
|
||||
L(dims) [Dims1, Dims2, Dims3]
|
||||
V opt = Optimizer(dims)
|
||||
opt.findMatrixChainOrder()
|
||||
print(‘Dims: ’dims)
|
||||
print(‘Order: ’opt.optimalChainOrder(0, dims.len - 2))
|
||||
print(‘Cost: ’opt.m[0][dims.len - 2])
|
||||
print(‘’)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package mat_chain is
|
||||
type Vector is array (Natural range <>) of Integer;
|
||||
procedure Chain_Multiplication (Dims : Vector);
|
||||
end mat_chain;
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
with Ada.Text_IO; use Ada.Text_IO;
|
||||
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
|
||||
|
||||
package body mat_chain is
|
||||
type Result_Matrix is
|
||||
array (Positive range <>, Positive range <>) of Integer;
|
||||
|
||||
--------------------------
|
||||
-- Chain_Multiplication --
|
||||
--------------------------
|
||||
|
||||
procedure Chain_Multiplication (Dims : Vector) is
|
||||
n : Natural := Dims'Length - 1;
|
||||
S : Result_Matrix (1 .. n, 1 .. n);
|
||||
m : Result_Matrix (1 .. n, 1 .. n);
|
||||
procedure Print (Item : Vector) is
|
||||
begin
|
||||
Put ("Array Dimension = (");
|
||||
for I in Item'Range loop
|
||||
Put (Item (I)'Image);
|
||||
if I < Item'Last then
|
||||
Put (",");
|
||||
else
|
||||
Put (")");
|
||||
end if;
|
||||
end loop;
|
||||
New_Line;
|
||||
end Print;
|
||||
|
||||
procedure Chain_Order (Item : Vector) is
|
||||
J : Natural;
|
||||
Cost : Natural;
|
||||
Temp : Natural;
|
||||
|
||||
begin
|
||||
for idx in 1 .. n loop
|
||||
m (idx, idx) := 0;
|
||||
end loop;
|
||||
|
||||
for Len in 2 .. n loop
|
||||
for I in 1 .. n - Len + 1 loop
|
||||
J := I + Len - 1;
|
||||
m (I, J) := Integer'Last;
|
||||
for K in I .. J - 1 loop
|
||||
Temp := Item (I - 1) * Item (K) * Item (J);
|
||||
Cost := m (I, K) + m (K + 1, J) + Temp;
|
||||
if Cost < m (I, J) then
|
||||
m (I, J) := Cost;
|
||||
S (I, J) := K;
|
||||
end if;
|
||||
end loop;
|
||||
end loop;
|
||||
end loop;
|
||||
end Chain_Order;
|
||||
|
||||
function Optimal_Parens return String is
|
||||
function Construct
|
||||
(S : Result_Matrix; I : Natural; J : Natural)
|
||||
return Unbounded_String
|
||||
is
|
||||
Us : Unbounded_String := Null_Unbounded_String;
|
||||
Char_Order : Character;
|
||||
begin
|
||||
if I = J then
|
||||
Char_Order := Character'Val (I + 64);
|
||||
Append (Source => Us, New_Item => Char_Order);
|
||||
return Us;
|
||||
else
|
||||
Append (Source => Us, New_Item => '(');
|
||||
Append (Source => Us, New_Item => Construct (S, I, S (I, J)));
|
||||
Append (Source => Us, New_Item => '*');
|
||||
Append
|
||||
(Source => Us, New_Item => Construct (S, S (I, J) + 1, J));
|
||||
Append (Source => Us, New_Item => ')');
|
||||
return Us;
|
||||
end if;
|
||||
end Construct;
|
||||
|
||||
begin
|
||||
return To_String (Construct (S, 1, n));
|
||||
|
||||
end Optimal_Parens;
|
||||
|
||||
begin
|
||||
Chain_Order (Dims);
|
||||
Print (Dims);
|
||||
Put_Line ("Cost = " & Integer'Image (m (1, n)));
|
||||
Put_Line ("Optimal Multiply = " & Optimal_Parens);
|
||||
end Chain_Multiplication;
|
||||
|
||||
end mat_chain;
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
with Mat_Chain; use Mat_Chain;
|
||||
with Ada.Text_IO; use Ada.Text_IO;
|
||||
|
||||
procedure chain_main is
|
||||
V1 : Vector := (5, 6, 3, 1);
|
||||
V2 : Vector := (1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2);
|
||||
V3 : Vector := (1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10);
|
||||
begin
|
||||
Chain_Multiplication(V1);
|
||||
New_Line;
|
||||
Chain_Multiplication(V2);
|
||||
New_Line;
|
||||
Chain_Multiplication(V3);
|
||||
end chain_main;
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
|
||||
class MatrixChainOrderOptimizer {
|
||||
private int[,] m;
|
||||
private int[,] s;
|
||||
|
||||
void OptimalMatrixChainOrder(int[] dims) {
|
||||
int n = dims.Length - 1;
|
||||
m = new int[n, n];
|
||||
s = new int[n, n];
|
||||
for (int len = 1; len < n; ++len) {
|
||||
for (int i = 0; i < n - len; ++i) {
|
||||
int j = i + len;
|
||||
m[i, j] = Int32.MaxValue;
|
||||
for (int k = i; k < j; ++k) {
|
||||
int temp = dims[i] * dims[k + 1] * dims[j + 1];
|
||||
int cost = m[i, k] + m[k + 1, j] + temp;
|
||||
if (cost < m[i, j]) {
|
||||
m[i, j] = cost;
|
||||
s[i, j] = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrintOptimalChainOrder(int i, int j) {
|
||||
if (i == j)
|
||||
Console.Write((char)(i + 65));
|
||||
else {
|
||||
Console.Write("(");
|
||||
PrintOptimalChainOrder(i, s[i, j]);
|
||||
PrintOptimalChainOrder(s[i, j] + 1, j);
|
||||
Console.Write(")");
|
||||
}
|
||||
}
|
||||
|
||||
static void Main() {
|
||||
var mcoo = new MatrixChainOrderOptimizer();
|
||||
var dimsList = new int[3][];
|
||||
dimsList[0] = new int[4] {5, 6, 3, 1};
|
||||
dimsList[1] = new int[13] {1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2};
|
||||
dimsList[2] = new int[12] {1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10};
|
||||
for (int i = 0; i < dimsList.Length; ++i) {
|
||||
Console.Write("Dims : [");
|
||||
int n = dimsList[i].Length;
|
||||
for (int j = 0; j < n; ++j) {
|
||||
Console.Write(dimsList[i][j]);
|
||||
if (j < n - 1)
|
||||
Console.Write(", ");
|
||||
else
|
||||
Console.WriteLine("]");
|
||||
}
|
||||
mcoo.OptimalMatrixChainOrder(dimsList[i]);
|
||||
Console.Write("Order : ");
|
||||
mcoo.PrintOptimalChainOrder(0, n - 2);
|
||||
Console.WriteLine("\nCost : {0}\n", mcoo.m[0, n - 2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int **m;
|
||||
int **s;
|
||||
|
||||
void optimal_matrix_chain_order(int *dims, int n) {
|
||||
int len, i, j, k, temp, cost;
|
||||
n--;
|
||||
m = (int **)malloc(n * sizeof(int *));
|
||||
for (i = 0; i < n; ++i) {
|
||||
m[i] = (int *)calloc(n, sizeof(int));
|
||||
}
|
||||
|
||||
s = (int **)malloc(n * sizeof(int *));
|
||||
for (i = 0; i < n; ++i) {
|
||||
s[i] = (int *)calloc(n, sizeof(int));
|
||||
}
|
||||
|
||||
for (len = 1; len < n; ++len) {
|
||||
for (i = 0; i < n - len; ++i) {
|
||||
j = i + len;
|
||||
m[i][j] = INT_MAX;
|
||||
for (k = i; k < j; ++k) {
|
||||
temp = dims[i] * dims[k + 1] * dims[j + 1];
|
||||
cost = m[i][k] + m[k + 1][j] + temp;
|
||||
if (cost < m[i][j]) {
|
||||
m[i][j] = cost;
|
||||
s[i][j] = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_optimal_chain_order(int i, int j) {
|
||||
if (i == j)
|
||||
printf("%c", i + 65);
|
||||
else {
|
||||
printf("(");
|
||||
print_optimal_chain_order(i, s[i][j]);
|
||||
print_optimal_chain_order(s[i][j] + 1, j);
|
||||
printf(")");
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
int i, j, n;
|
||||
int a1[4] = {5, 6, 3, 1};
|
||||
int a2[13] = {1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2};
|
||||
int a3[12] = {1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10};
|
||||
int *dims_list[3] = {a1, a2, a3};
|
||||
int sizes[3] = {4, 13, 12};
|
||||
for (i = 0; i < 3; ++i) {
|
||||
printf("Dims : [");
|
||||
n = sizes[i];
|
||||
for (j = 0; j < n; ++j) {
|
||||
printf("%d", dims_list[i][j]);
|
||||
if (j < n - 1) printf(", "); else printf("]\n");
|
||||
}
|
||||
optimal_matrix_chain_order(dims_list[i], n);
|
||||
printf("Order : ");
|
||||
print_optimal_chain_order(0, n - 2);
|
||||
printf("\nCost : %d\n\n", m[0][n - 2]);
|
||||
for (j = 0; j <= n - 2; ++j) free(m[j]);
|
||||
free(m);
|
||||
for (j = 0; j <= n - 2; ++j) free(s[j]);
|
||||
free(s);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
module optim_mod
|
||||
implicit none
|
||||
contains
|
||||
subroutine optim(a)
|
||||
implicit none
|
||||
integer :: a(:), n, i, j, k
|
||||
integer, allocatable :: u(:, :)
|
||||
integer(8) :: c
|
||||
integer(8), allocatable :: v(:, :)
|
||||
|
||||
n = ubound(a, 1) - 1
|
||||
allocate (u(n, n), v(n, n))
|
||||
v = huge(v)
|
||||
u(:, 1) = -1
|
||||
v(:, 1) = 0
|
||||
do j = 2, n
|
||||
do i = 1, n - j + 1
|
||||
do k = 1, j - 1
|
||||
c = v(i, k) + v(i + k, j - k) + int(a(i), 8) * int(a(i + k), 8) * int(a(i + j), 8)
|
||||
if (c < v(i, j)) then
|
||||
u(i, j) = k
|
||||
v(i, j) = c
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
end do
|
||||
write (*, "(I0,' ')", advance="no") v(1, n)
|
||||
call aux(1, n)
|
||||
print *
|
||||
deallocate (u, v)
|
||||
contains
|
||||
recursive subroutine aux(i, j)
|
||||
integer :: i, j, k
|
||||
|
||||
k = u(i, j)
|
||||
if (k < 0) then
|
||||
write (*, "(I0)", advance="no") i
|
||||
else
|
||||
write (*, "('(')", advance="no")
|
||||
call aux(i, k)
|
||||
write (*, "('*')", advance="no")
|
||||
call aux(i + k, j - k)
|
||||
write (*, "(')')", advance="no")
|
||||
end if
|
||||
end subroutine
|
||||
end subroutine
|
||||
end module
|
||||
|
||||
program matmulchain
|
||||
use optim_mod
|
||||
implicit none
|
||||
|
||||
call optim([5, 6, 3, 1])
|
||||
call optim([1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2])
|
||||
call optim([1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10])
|
||||
end program
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
// PrintMatrixChainOrder prints the optimal order for chain
|
||||
// multiplying matrices.
|
||||
// Matrix A[i] has dimensions dims[i-1]×dims[i].
|
||||
func PrintMatrixChainOrder(dims []int) {
|
||||
n := len(dims) - 1
|
||||
m, s := newSquareMatrices(n)
|
||||
|
||||
// m[i,j] will be minimum number of scalar multiplactions
|
||||
// needed to compute the matrix A[i]A[i+1]…A[j] = A[i…j].
|
||||
// Note, m[i,i] = zero (no cost).
|
||||
// s[i,j] will be the index of the subsequence split that
|
||||
// achieved minimal cost.
|
||||
for lenMinusOne := 1; lenMinusOne < n; lenMinusOne++ {
|
||||
for i := 0; i < n-lenMinusOne; i++ {
|
||||
j := i + lenMinusOne
|
||||
m[i][j] = -1
|
||||
for k := i; k < j; k++ {
|
||||
cost := m[i][k] + m[k+1][j] + dims[i]*dims[k+1]*dims[j+1]
|
||||
if m[i][j] < 0 || cost < m[i][j] {
|
||||
m[i][j] = cost
|
||||
s[i][j] = k
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Format and print result.
|
||||
const MatrixNames = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
var subprint func(int, int)
|
||||
subprint = func(i, j int) {
|
||||
if i == j {
|
||||
return
|
||||
}
|
||||
k := s[i][j]
|
||||
subprint(i, k)
|
||||
subprint(k+1, j)
|
||||
fmt.Printf("%*s -> %s × %s%*scost=%d\n",
|
||||
n, MatrixNames[i:j+1],
|
||||
MatrixNames[i:k+1],
|
||||
MatrixNames[k+1:j+1],
|
||||
n+i-j, "", m[i][j],
|
||||
)
|
||||
}
|
||||
subprint(0, n-1)
|
||||
}
|
||||
|
||||
func newSquareMatrices(n int) (m, s [][]int) {
|
||||
// Allocates two n×n matrices as slices of slices but
|
||||
// using only one [2n][]int and one [2n²]int backing array.
|
||||
m = make([][]int, 2*n)
|
||||
m, s = m[:n:n], m[n:]
|
||||
tmp := make([]int, 2*n*n)
|
||||
for i := range m {
|
||||
m[i], tmp = tmp[:n:n], tmp[n:]
|
||||
}
|
||||
for i := range s {
|
||||
s[i], tmp = tmp[:n:n], tmp[n:]
|
||||
}
|
||||
return m, s
|
||||
}
|
||||
|
||||
func main() {
|
||||
cases := [...][]int{
|
||||
{1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2},
|
||||
{1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
fmt.Println("Dimensions:", tc)
|
||||
PrintMatrixChainOrder(tc)
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
import Data.List (elemIndex)
|
||||
import Data.Char (chr, ord)
|
||||
import Data.Maybe (fromJust)
|
||||
|
||||
mats :: [[Int]]
|
||||
mats =
|
||||
[ [5, 6, 3, 1]
|
||||
, [1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2]
|
||||
, [1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10]
|
||||
]
|
||||
|
||||
cost :: [Int] -> Int -> Int -> (Int, Int)
|
||||
cost a i j
|
||||
| i < j =
|
||||
let m =
|
||||
[ fst (cost a i k) + fst (cost a (k + 1) j) +
|
||||
(a !! i) * (a !! (j + 1)) * (a !! (k + 1))
|
||||
| k <- [i .. j - 1] ]
|
||||
mm = minimum m
|
||||
in (mm, fromJust (elemIndex mm m) + i)
|
||||
| otherwise = (0, -1)
|
||||
|
||||
optimalOrder :: [Int] -> Int -> Int -> String
|
||||
optimalOrder a i j
|
||||
| i < j =
|
||||
let c = cost a i j
|
||||
in "(" ++ optimalOrder a i (snd c) ++ optimalOrder a (snd c + 1) j ++ ")"
|
||||
| otherwise = [chr ((+ i) $ ord 'a')]
|
||||
|
||||
printBlock :: [Int] -> IO ()
|
||||
printBlock v =
|
||||
let c = cost v 0 (length v - 2)
|
||||
in putStrLn
|
||||
("for " ++
|
||||
show v ++
|
||||
" we have " ++
|
||||
show (fst c) ++
|
||||
" possibilities, z.B " ++ optimalOrder v 0 (length v - 2))
|
||||
|
||||
main :: IO ()
|
||||
main = mapM_ printBlock mats
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
moo =: verb define
|
||||
s =. m =. 0 $~ ,~ n=._1+#y
|
||||
for_lmo. 1+i.<:n do.
|
||||
for_i. i. n-lmo do.
|
||||
j =. i + lmo
|
||||
m =. _ (<i;j)} m
|
||||
for_k. i+i.j-i do.
|
||||
cost =. ((<i;k){m) + ((<(k+1);j){m) + */ y {~ i,(k+1),(j+1)
|
||||
if. cost < ((<i;j){m) do.
|
||||
m =. cost (<i;j)} m
|
||||
s =. k (<i;j)} s
|
||||
end.
|
||||
end.
|
||||
end.
|
||||
end.
|
||||
|
||||
m;s
|
||||
)
|
||||
|
||||
poco =: dyad define
|
||||
'i j' =. y
|
||||
if. i=j do.
|
||||
a. {~ 65 + i NB. 65 = a.i.'A'
|
||||
else.
|
||||
k =. x {~ <y NB. y = i,j
|
||||
'(' , (x poco i,k) , (x poco j ,~ 1+k) , ')'
|
||||
end.
|
||||
)
|
||||
|
||||
optMM =: verb define
|
||||
'M S' =. moo y
|
||||
smoutput 'Cost: ' , ": x: M {~ <0;_1
|
||||
smoutput 'Order: ', S poco 0 , <:#M
|
||||
)
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
optMM 5 6 3 1
|
||||
Cost: 48
|
||||
Order: (A(BC))
|
||||
|
||||
optMM 1 5 25 30 100 70 2 1 100 250 1 1000 2
|
||||
Cost: 38120
|
||||
Order: ((((((((AB)C)D)E)F)G)(H(IJ)))(KL))
|
||||
|
||||
optMM 1000 1 500 12 1 700 2500 3 2 5 14 10
|
||||
Cost: 1773740
|
||||
Order: (A((((((BC)D)(((EF)G)H))I)J)K))
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
import java.util.Arrays;
|
||||
|
||||
public class MatrixChainMultiplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
runMatrixChainMultiplication(new int[] {5, 6, 3, 1});
|
||||
runMatrixChainMultiplication(new int[] {1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2});
|
||||
runMatrixChainMultiplication(new int[] {1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10});
|
||||
}
|
||||
|
||||
private static void runMatrixChainMultiplication(int[] dims) {
|
||||
System.out.printf("Array Dimension = %s%n", Arrays.toString(dims));
|
||||
System.out.printf("Cost = %d%n", matrixChainOrder(dims));
|
||||
System.out.printf("Optimal Multiply = %s%n%n", getOptimalParenthesizations());
|
||||
}
|
||||
|
||||
private static int[][]cost;
|
||||
private static int[][]order;
|
||||
|
||||
public static int matrixChainOrder(int[] dims) {
|
||||
int n = dims.length - 1;
|
||||
cost = new int[n][n];
|
||||
order = new int[n][n];
|
||||
|
||||
for (int lenMinusOne = 1 ; lenMinusOne < n ; lenMinusOne++) {
|
||||
for (int i = 0; i < n - lenMinusOne; i++) {
|
||||
int j = i + lenMinusOne;
|
||||
cost[i][j] = Integer.MAX_VALUE;
|
||||
for (int k = i; k < j; k++) {
|
||||
int currentCost = cost[i][k] + cost[k+1][j] + dims[i]*dims[k+1]*dims[j+1];
|
||||
if (currentCost < cost[i][j]) {
|
||||
cost[i][j] = currentCost;
|
||||
order[i][j] = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cost[0][n-1];
|
||||
}
|
||||
|
||||
private static String getOptimalParenthesizations() {
|
||||
return getOptimalParenthesizations(order, 0, order.length - 1);
|
||||
}
|
||||
|
||||
private static String getOptimalParenthesizations(int[][]s, int i, int j) {
|
||||
if (i == j) {
|
||||
return String.format("%c", i+65);
|
||||
}
|
||||
else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(");
|
||||
sb.append(getOptimalParenthesizations(s, i, s[i][j]));
|
||||
sb.append(" * ");
|
||||
sb.append(getOptimalParenthesizations(s, s[i][j] + 1, j));
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# Input: array of dimensions
|
||||
# output: {m, s}
|
||||
def optimalMatrixChainOrder:
|
||||
. as $dims
|
||||
| (($dims|length) - 1) as $n
|
||||
| reduce range(1; $n) as $len ({m: [], s: []};
|
||||
reduce range(0; $n-$len) as $i (.;
|
||||
($i + $len) as $j
|
||||
| .m[$i][$j] = infinite
|
||||
| reduce range($i; $j) as $k (.;
|
||||
($dims[$i] * $dims [$k + 1] * $dims[$j + 1]) as $temp
|
||||
| (.m[$i][$k] + .m[$k + 1][$j] + $temp) as $cost
|
||||
| if $cost < .m[$i][$j]
|
||||
then .m[$i][$j] = $cost
|
||||
| .s[$i][$j] = $k
|
||||
else .
|
||||
end ) )) ;
|
||||
|
||||
# input: {s}
|
||||
def printOptimalChainOrder($i; $j):
|
||||
if $i == $j
|
||||
then [$i + 65] | implode #=> "A", "B", ...
|
||||
else "(" +
|
||||
printOptimalChainOrder($i; .s[$i][$j]) +
|
||||
printOptimalChainOrder(.s[$i][$j] + 1; $j) + ")"
|
||||
end;
|
||||
|
||||
def dimsList: [
|
||||
[5, 6, 3, 1],
|
||||
[1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2],
|
||||
[1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10]
|
||||
];
|
||||
|
||||
dimsList[]
|
||||
| "Dims : \(.)",
|
||||
(optimalMatrixChainOrder
|
||||
| "Order : \(printOptimalChainOrder(0; .s|length - 1))",
|
||||
"Cost : \(.m[0][.s|length - 1])\n" )
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
module MatrixChainMultiplications
|
||||
|
||||
using OffsetArrays
|
||||
|
||||
function optim(a)
|
||||
n = length(a) - 1
|
||||
u = fill!(OffsetArray{Int}(0:n, 0:n), 0)
|
||||
v = fill!(OffsetArray{Int}(0:n, 0:n), typemax(Int))
|
||||
u[:, 1] .= -1
|
||||
v[:, 1] .= 0
|
||||
for j in 2:n, i in 1:n-j+1, k in 1:j-1
|
||||
c = v[i, k] + v[i+k, j-k] + a[i] * a[i+k] * a[i+j]
|
||||
if c < v[i, j]
|
||||
u[i, j] = k
|
||||
v[i, j] = c
|
||||
end
|
||||
end
|
||||
return v[1, n], aux(u, 1, n)
|
||||
end
|
||||
|
||||
function aux(u, i, j)
|
||||
k = u[i, j]
|
||||
if k < 0
|
||||
return sprint(print, i)
|
||||
else
|
||||
return sprint(print, '(', aux(u, i, k), '×', aux(u, i + k, j - k), ")")
|
||||
end
|
||||
end
|
||||
|
||||
end # module MatrixChainMultiplications
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
println(MatrixChainMultiplications.optim([1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2]))
|
||||
println(MatrixChainMultiplications.optim([1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10]))
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// Version 1.2.31
|
||||
|
||||
lateinit var m: List<IntArray>
|
||||
lateinit var s: List<IntArray>
|
||||
|
||||
fun optimalMatrixChainOrder(dims: IntArray) {
|
||||
val n = dims.size - 1
|
||||
m = List(n) { IntArray(n) }
|
||||
s = List(n) { IntArray(n) }
|
||||
for (len in 1 until n) {
|
||||
for (i in 0 until n - len) {
|
||||
val j = i + len
|
||||
m[i][j] = Int.MAX_VALUE
|
||||
for (k in i until j) {
|
||||
val temp = dims[i] * dims [k + 1] * dims[j + 1]
|
||||
val cost = m[i][k] + m[k + 1][j] + temp
|
||||
if (cost < m[i][j]) {
|
||||
m[i][j] = cost
|
||||
s[i][j] = k
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun printOptimalChainOrder(i: Int, j: Int) {
|
||||
if (i == j)
|
||||
print("${(i + 65).toChar()}")
|
||||
else {
|
||||
print("(")
|
||||
printOptimalChainOrder(i, s[i][j])
|
||||
printOptimalChainOrder(s[i][j] + 1, j)
|
||||
print(")")
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val dimsList = listOf(
|
||||
intArrayOf(5, 6, 3, 1),
|
||||
intArrayOf(1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2),
|
||||
intArrayOf(1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10)
|
||||
)
|
||||
for (dims in dimsList) {
|
||||
println("Dims : ${dims.asList()}")
|
||||
optimalMatrixChainOrder(dims)
|
||||
print("Order : ")
|
||||
printOptimalChainOrder(0, s.size - 1)
|
||||
println("\nCost : ${m[0][s.size - 1]}\n")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
-- Matrix A[i] has dimension dims[i-1] x dims[i] for i = 1..n
|
||||
local function MatrixChainOrder(dims)
|
||||
local m = {}
|
||||
local s = {}
|
||||
local n = #dims - 1;
|
||||
-- m[i,j] = Minimum number of scalar multiplications (i.e., cost)
|
||||
-- needed to compute the matrix A[i]A[i+1]...A[j] = A[i..j]
|
||||
-- The cost is zero when multiplying one matrix
|
||||
for i = 1,n do
|
||||
m[i] = {}
|
||||
m[i][i] = 0
|
||||
s[i] = {}
|
||||
end
|
||||
|
||||
for len = 2,n do -- Subsequence lengths
|
||||
for i = 1,(n - len + 1) do
|
||||
local j = i + len - 1
|
||||
m[i][j] = math.maxinteger
|
||||
for k = i,(j - 1) do
|
||||
local cost = m[i][k] + m[k+1][j] + dims[i]*dims[k+1]*dims[j+1];
|
||||
if (cost < m[i][j]) then
|
||||
m[i][j] = cost;
|
||||
s[i][j] = k; --Index of the subsequence split that achieved minimal cost
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return m,s
|
||||
end
|
||||
|
||||
local function printOptimalChainOrder(s)
|
||||
local function find_path(start,finish)
|
||||
local chainOrder = ""
|
||||
if (start == finish) then
|
||||
chainOrder = chainOrder .."A"..start
|
||||
else
|
||||
chainOrder = chainOrder .."(" ..
|
||||
find_path(start,s[start][finish]) ..
|
||||
find_path(s[start][finish]+1,finish) .. ")"
|
||||
end
|
||||
return chainOrder
|
||||
end
|
||||
print("Order : "..find_path(1,#s))
|
||||
end
|
||||
|
||||
local dimsList = {{5, 6, 3, 1},{1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2},{1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10}}
|
||||
|
||||
for k,dim in ipairs(dimsList) do
|
||||
io.write("Dims : [")
|
||||
for v=1,(#dim-1) do
|
||||
io.write(dim[v]..", ")
|
||||
end
|
||||
print(dim[#dim].."]")
|
||||
local m,s = MatrixChainOrder(dim)
|
||||
printOptimalChainOrder(s)
|
||||
print("Cost : "..tostring(m[1][#s]).."\n")
|
||||
end
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
function [r,s] = optim(a)
|
||||
n = length(a)-1;
|
||||
u = zeros(n,n);
|
||||
v = ones(n,n)*inf;
|
||||
u(:,1) = -1;
|
||||
v(:,1) = 0;
|
||||
for j = 2:n
|
||||
for i = 1:n-j+1
|
||||
for k = 1:j-1
|
||||
c = v(i,k)+v(i+k,j-k)+a(i)*a(i+k)*a(i+j);
|
||||
if c<v(i,j)
|
||||
u(i,j) = k;
|
||||
v(i,j) = c;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
r = v(1,n);
|
||||
s = aux(u,1,n);
|
||||
end
|
||||
|
||||
function s = aux(u,i,j)
|
||||
k = u(i,j);
|
||||
if k<0
|
||||
s = sprintf("%d",i);
|
||||
else
|
||||
s = sprintf("(%s*%s)",aux(u,i,k),aux(u,i+k,j-k));
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
[r,s] = optim([1,5,25,30,100,70,2,1,100,250,1,1000,2])
|
||||
|
||||
r =
|
||||
|
||||
38120
|
||||
|
||||
|
||||
s =
|
||||
|
||||
"((((((((1*2)*3)*4)*5)*6)*7)*(8*(9*10)))*(11*12))"
|
||||
|
||||
|
||||
[r,s] = optim([1000,1,500,12,1,700,2500,3,2,5,14,10])
|
||||
|
||||
r =
|
||||
|
||||
1773740
|
||||
|
||||
|
||||
s =
|
||||
|
||||
"(1*((((((2*3)*4)*(((5*6)*7)*8))*9)*10)*11))"
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
ClearAll[optim, aux]
|
||||
optim[a_List] := Module[{u, v, n, c, r, s},
|
||||
n = Length[a] - 1;
|
||||
u = ConstantArray[0, {n, n}];
|
||||
v = ConstantArray[\[Infinity], {n, n}];
|
||||
u[[All, 1]] = -1;
|
||||
v[[All, 1]] = 0;
|
||||
Do[
|
||||
Do[
|
||||
Do[
|
||||
c =
|
||||
v[[i, k]] + v[[i + k, j - k]] + a[[i]] a[[i + k]] a[[i + j]];
|
||||
If[c < v[[i, j]],
|
||||
u[[i, j]] = k;
|
||||
v[[i, j]] = c;
|
||||
]
|
||||
,
|
||||
{k, 1, j - 1}
|
||||
]
|
||||
,
|
||||
{i, 1, n - j + 1}
|
||||
]
|
||||
,
|
||||
{j, 2, n}
|
||||
];
|
||||
r = v[[1, n]];
|
||||
s = aux[u, 1, n];
|
||||
{r, s}
|
||||
]
|
||||
aux[u_, i_, j_] := Module[{k},
|
||||
k = u[[i, j]];
|
||||
If[k < 0,
|
||||
i
|
||||
,
|
||||
Inactive[Times][aux[u, i, k], aux[u, i + k, j - k]]
|
||||
]
|
||||
]
|
||||
{r, s} = optim[{1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2}];
|
||||
r
|
||||
s
|
||||
{r, s} = optim[{1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10}];
|
||||
r
|
||||
s
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
import sequtils
|
||||
|
||||
type Optimizer = object
|
||||
dims: seq[int]
|
||||
m: seq[seq[Natural]]
|
||||
s: seq[seq[Natural]]
|
||||
|
||||
|
||||
proc initOptimizer(dims: openArray[int]): Optimizer =
|
||||
## Create an optimizer for the given dimensions.
|
||||
Optimizer(dims: @dims)
|
||||
|
||||
proc findMatrixChainOrder(opt: var Optimizer) =
|
||||
## Find the best order for matrix chain multiplication.
|
||||
|
||||
let n = opt.dims.high
|
||||
opt.m = newSeqWith(n, newSeq[Natural](n))
|
||||
opt.s = newSeqWith(n, newSeq[Natural](n))
|
||||
|
||||
for lg in 1..<n:
|
||||
for i in 0..<(n - lg):
|
||||
let j = i + lg
|
||||
opt.m[i][j] = Natural.high
|
||||
for k in i..<j:
|
||||
let cost = opt.m[i][k] + opt.m[k+1][j] + opt.dims[i] * opt.dims[k+1] * opt.dims[j+1]
|
||||
if cost < opt.m[i][j]:
|
||||
opt.m[i][j] = cost
|
||||
opt.s[i][j] = k
|
||||
|
||||
|
||||
proc optimalChainOrder(opt: Optimizer; i, j: Natural): string =
|
||||
## Return the optimal chain order as a string.
|
||||
if i == j:
|
||||
result.add chr(i + ord('A'))
|
||||
else:
|
||||
result.add '('
|
||||
result.add opt.optimalChainOrder(i, opt.s[i][j])
|
||||
result.add opt.optimalChainOrder(opt.s[i][j] + 1, j)
|
||||
result.add ')'
|
||||
|
||||
|
||||
when isMainModule:
|
||||
|
||||
const
|
||||
Dims1 = @[5, 6, 3, 1]
|
||||
Dims2 = @[1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2]
|
||||
Dims3 = @[1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10]
|
||||
|
||||
for dims in [Dims1, Dims2, Dims3]:
|
||||
var opt = initOptimizer(dims)
|
||||
opt.findMatrixChainOrder()
|
||||
echo "Dims: ", dims
|
||||
echo "Order: ", opt.optimalChainOrder(0, dims.len - 2)
|
||||
echo "Cost: ", opt.m[0][dims.len - 2]
|
||||
echo ""
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
use strict;
|
||||
use feature 'say';
|
||||
|
||||
sub matrix_mult_chaining {
|
||||
my(@dimensions) = @_;
|
||||
my(@cp,@path);
|
||||
|
||||
# a matrix never needs to be multiplied with itself, so it has cost 0
|
||||
$cp[$_][$_] = 0 for keys @dimensions;
|
||||
|
||||
my $n = $#dimensions;
|
||||
for my $chain_length (1..$n) {
|
||||
for my $start (0 .. $n - $chain_length - 1) {
|
||||
my $end = $start + $chain_length;
|
||||
$cp[$end][$start] = 10e10;
|
||||
for my $step ($start .. $end - 1) {
|
||||
my $new_cost = $cp[$step][$start]
|
||||
+ $cp[$end][$step + 1]
|
||||
+ $dimensions[$start] * $dimensions[$step+1] * $dimensions[$end+1];
|
||||
if ($new_cost < $cp[$end][$start]) {
|
||||
$cp[$end][$start] = $new_cost; # cost
|
||||
$cp[$start][$end] = $step; # path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$cp[$n-1][0] . ' ' . find_path(0, $n-1, @cp);
|
||||
}
|
||||
|
||||
sub find_path {
|
||||
my($start,$end,@cp) = @_;
|
||||
my $result;
|
||||
|
||||
if ($start == $end) {
|
||||
$result .= 'A' . ($start + 1);
|
||||
} else {
|
||||
$result .= '(' .
|
||||
find_path($start, $cp[$start][$end], @cp) .
|
||||
find_path($cp[$start][$end] + 1, $end, @cp) .
|
||||
')';
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
say matrix_mult_chaining(<1 5 25 30 100 70 2 1 100 250 1 1000 2>);
|
||||
say matrix_mult_chaining(<1000 1 500 12 1 700 2500 3 2 5 14 10>);
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
(phixonline)-->
|
||||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">optimal_chain_order</span><span style="color: #0000FF;">(</span><span style="color: #004080;">int</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">int</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">==</span><span style="color: #000000;">j</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #008000;">'A'</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #008000;">"("</span><span style="color: #0000FF;">&</span><span style="color: #000000;">optimal_chain_order</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">j</span><span style="color: #0000FF;">],</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #0000FF;">&</span><span style="color: #000000;">optimal_chain_order</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">j</span><span style="color: #0000FF;">,</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)&</span><span style="color: #008000;">")"</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">optimal_matrix_chain_order</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">dims</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dims</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">1</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">m</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">),</span><span style="color: #000000;">n</span><span style="color: #0000FF;">),</span>
|
||||
<span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">len</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #000000;">n</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">-</span><span style="color: #000000;">len</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">j</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">len</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span>
|
||||
<span style="color: #000000;">m</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">i</span> <span style="color: #008080;">to</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">atom</span> <span style="color: #000000;">cost</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">dims</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]*</span><span style="color: #000000;">dims</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]*</span><span style="color: #000000;">dims</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]<</span><span style="color: #000000;">0</span>
|
||||
<span style="color: #008080;">or</span> <span style="color: #000000;">cost</span><span style="color: #0000FF;"><</span><span style="color: #000000;">m</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">m</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cost</span><span style="color: #0000FF;">;</span>
|
||||
<span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">;</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">optimal_chain_order</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">s</span><span style="color: #0000FF;">),</span><span style="color: #000000;">m</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">]}</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">tests</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">25</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">30</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">100</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">70</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">100</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">250</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1000</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">1000</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">500</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">12</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">700</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2500</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">14</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">}}</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">ti</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tests</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Dims : %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #7060A8;">sprint</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">)})</span>
|
||||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Order : %s\nCost : %d\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">optimal_matrix_chain_order</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<!--
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
def parens(n):
|
||||
def aux(n, k):
|
||||
if n == 1:
|
||||
yield k
|
||||
elif n == 2:
|
||||
yield [k, k + 1]
|
||||
else:
|
||||
a = []
|
||||
for i in range(1, n):
|
||||
for u in aux(i, k):
|
||||
for v in aux(n - i, k + i):
|
||||
yield [u, v]
|
||||
yield from aux(n, 0)
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
for u in parens(4):
|
||||
print(u)
|
||||
|
||||
[0, [1, [2, 3]]]
|
||||
[0, [[1, 2], 3]]
|
||||
[[0, 1], [2, 3]]
|
||||
[[0, [1, 2]], 3]
|
||||
[[[0, 1], 2], 3]
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
def optim1(a):
|
||||
def cost(k):
|
||||
if type(k) is int:
|
||||
return 0, a[k], a[k + 1]
|
||||
else:
|
||||
s1, p1, q1 = cost(k[0])
|
||||
s2, p2, q2 = cost(k[1])
|
||||
assert q1 == p2
|
||||
return s1 + s2 + p1 * q1 * q2, p1, q2
|
||||
cmin = None
|
||||
n = len(a) - 1
|
||||
for u in parens(n):
|
||||
c, p, q = cost(u)
|
||||
if cmin is None or c < cmin:
|
||||
cmin = c
|
||||
umin = u
|
||||
return cmin, umin
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
def optim2(a):
|
||||
def aux(n, k):
|
||||
if n == 1:
|
||||
p, q = a[k:k + 2]
|
||||
return 0, p, q, k
|
||||
elif n == 2:
|
||||
p, q, r = a[k:k + 3]
|
||||
return p * q * r, p, r, [k, k + 1]
|
||||
else:
|
||||
m = None
|
||||
p = a[k]
|
||||
q = a[k + n]
|
||||
for i in range(1, n):
|
||||
s1, p1, q1, u1 = aux(i, k)
|
||||
s2, p2, q2, u2 = aux(n - i, k + i)
|
||||
assert q1 == p2
|
||||
s = s1 + s2 + p1 * q1 * q2
|
||||
if m is None or s < m:
|
||||
m = s
|
||||
u = [u1, u2]
|
||||
return m, p, q, u
|
||||
s, p, q, u = aux(len(a) - 1, 0)
|
||||
return s, u
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
def memoize(f):
|
||||
h = {}
|
||||
def g(*u):
|
||||
if u in h:
|
||||
return h[u]
|
||||
else:
|
||||
r = f(*u)
|
||||
h[u] = r
|
||||
return r
|
||||
return g
|
||||
|
||||
def optim3(a):
|
||||
@memoize
|
||||
def aux(n, k):
|
||||
if n == 1:
|
||||
p, q = a[k:k + 2]
|
||||
return 0, p, q, k
|
||||
elif n == 2:
|
||||
p, q, r = a[k:k + 3]
|
||||
return p * q * r, p, r, [k, k + 1]
|
||||
else:
|
||||
m = None
|
||||
p = a[k]
|
||||
q = a[k + n]
|
||||
for i in range(1, n):
|
||||
s1, p1, q1, u1 = aux(i, k)
|
||||
s2, p2, q2, u2 = aux(n - i, k + i)
|
||||
assert q1 == p2
|
||||
s = s1 + s2 + p1 * q1 * q2
|
||||
if m is None or s < m:
|
||||
m = s
|
||||
u = [u1, u2]
|
||||
return m, p, q, u
|
||||
s, p, q, u = aux(len(a) - 1, 0)
|
||||
return s, u
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import time
|
||||
|
||||
u = [[1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2],
|
||||
[1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10]]
|
||||
|
||||
for a in u:
|
||||
print(a)
|
||||
print()
|
||||
print("function time cost parens ")
|
||||
print("-" * 90)
|
||||
for f in [optim1, optim2, optim3]:
|
||||
t1 = time.clock()
|
||||
s, u = f(a)
|
||||
t2 = time.clock()
|
||||
print("%s %10.3f %10d %s" % (f.__name__, 1000 * (t2 - t1), s, u))
|
||||
print()
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
def optim4(a):
|
||||
global u
|
||||
n = len(a) - 1
|
||||
u = [None] * n
|
||||
u[0] = [[None, 0]] * n
|
||||
for j in range(1, n):
|
||||
v = [None] * (n - j)
|
||||
for i in range(n - j):
|
||||
m = None
|
||||
for k in range(j):
|
||||
s1, c1 = u[k][i]
|
||||
s2, c2 = u[j - k - 1][i + k + 1]
|
||||
c = c1 + c2 + a[i] * a[i + k + 1] * a[i + j + 1]
|
||||
if m is None or c < m:
|
||||
s = k
|
||||
m = c
|
||||
v[i] = [s, m]
|
||||
u[j] = v
|
||||
def aux(i, j):
|
||||
s, c = u[j][i]
|
||||
if s is None:
|
||||
return i
|
||||
else:
|
||||
return [aux(i, s), aux(i + s + 1, j - s - 1)]
|
||||
return u[n - 1][0][1], aux(0, n - 1)
|
||||
|
||||
|
||||
print(optim4([1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2]))
|
||||
print(optim4([1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10]))
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
aux <- function(i, j, u) {
|
||||
k <- u[[i, j]]
|
||||
if (k < 0) {
|
||||
i
|
||||
} else {
|
||||
paste0("(", Recall(i, k, u), "*", Recall(i + k, j - k, u), ")")
|
||||
}
|
||||
}
|
||||
|
||||
chain.mul <- function(a) {
|
||||
n <- length(a) - 1
|
||||
u <- matrix(0, n, n)
|
||||
v <- matrix(0, n, n)
|
||||
u[, 1] <- -1
|
||||
|
||||
for (j in seq(2, n)) {
|
||||
for (i in seq(n - j + 1)) {
|
||||
v[[i, j]] <- Inf
|
||||
for (k in seq(j - 1)) {
|
||||
s <- v[[i, k]] + v[[i + k, j - k]] + a[[i]] * a[[i + k]] * a[[i + j]]
|
||||
if (s < v[[i, j]]) {
|
||||
u[[i, j]] <- k
|
||||
v[[i, j]] <- s
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list(cost = v[[1, n]], solution = aux(1, n, u))
|
||||
}
|
||||
|
||||
chain.mul(c(5, 6, 3, 1))
|
||||
# $cost
|
||||
# [1] 48
|
||||
|
||||
# $solution
|
||||
# [1] "(1*(2*3))"
|
||||
|
||||
chain.mul(c(1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2))
|
||||
# $cost
|
||||
# [1] 38120
|
||||
|
||||
# $solution
|
||||
# [1] "((((((((1*2)*3)*4)*5)*6)*7)*(8*(9*10)))*(11*12))"
|
||||
|
||||
chain.mul(c(1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10))
|
||||
# $cost
|
||||
# [1] 1773740
|
||||
|
||||
# $solution
|
||||
# [1] "(1*((((((2*3)*4)*(((5*6)*7)*8))*9)*10)*11))"
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#lang racket
|
||||
|
||||
(define (memoize f)
|
||||
(define table (make-hash))
|
||||
(λ args (hash-ref! table args (thunk (apply f args)))))
|
||||
|
||||
(struct $ (cost expl))
|
||||
(define @ vector-ref)
|
||||
|
||||
(define (+: #:combine [combine (thunk* #f)] . xs)
|
||||
($ (apply + (map $-cost xs)) (apply combine (map $-expl xs))))
|
||||
|
||||
(define (min: . xs) (argmin $-cost xs))
|
||||
|
||||
(define (compute dims)
|
||||
(define loop
|
||||
(memoize
|
||||
(λ (left right)
|
||||
(cond
|
||||
[(= 1 (- right left)) ($ 0 left)]
|
||||
[else (for/fold ([ans ($ +inf.0 #f)]) ([mid (in-range (add1 left) right)])
|
||||
(min: ans (+: (loop left mid) (loop mid right)
|
||||
($ (* (@ dims left) (@ dims mid) (@ dims right)) #f)
|
||||
#:combine (λ (left-answer right-answer _)
|
||||
(list left-answer '× right-answer)))))]))))
|
||||
(loop 0 (sub1 (vector-length dims))))
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
(define-syntax-rule (echo <x> ...)
|
||||
(begin (printf "~a: ~a\n" (~a (quote <x>) #:min-width 12) <x>) ...))
|
||||
|
||||
(define (solve input)
|
||||
(match-define-values ((list ($ cost explanation)) _ time _) (time-apply compute (list input)))
|
||||
(echo input time cost explanation)
|
||||
(newline))
|
||||
|
||||
(solve #(1 5 25 30 100 70 2 1 100 250 1 1000 2))
|
||||
(solve #(1000 1 500 12 1 700 2500 3 2 5 14 10))
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
sub matrix-mult-chaining(@dimensions) {
|
||||
my @cp;
|
||||
# @cp has a dual function:
|
||||
# * the upper triangle of the diagonal matrix stores the cost (c) for
|
||||
# multiplying matrices $i and $j in @cp[$j][$i], where $j > $i
|
||||
# * the lower triangle stores the path (p) that was used for the lowest cost
|
||||
# multiplication to get from $i to $j.
|
||||
|
||||
# a matrix never needs to be multiplied with itself, so it has cost 0
|
||||
@cp[$_][$_] = 0 for @dimensions.keys;
|
||||
my @path;
|
||||
|
||||
my $n = @dimensions.end;
|
||||
for 1 .. $n -> $chain-length {
|
||||
for 0 .. $n - $chain-length - 1 -> $start {
|
||||
my $end = $start + $chain-length;
|
||||
@cp[$end][$start] = Inf; # until we find a better connection
|
||||
for $start .. $end - 1 -> $step {
|
||||
my $new-cost = @cp[$step][$start]
|
||||
+ @cp[$end][$step + 1]
|
||||
+ [*] @dimensions[$start, $step+1, $end+1];
|
||||
if $new-cost < @cp[$end][$start] {
|
||||
@cp[$end][$start] = $new-cost; # cost
|
||||
@cp[$start][$end] = $step; # path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub find-path(Int $start, Int $end) {
|
||||
if $start == $end {
|
||||
take 'A' ~ ($start + 1);
|
||||
} else {
|
||||
take '(';
|
||||
find-path($start, @cp[$start][$end]);
|
||||
find-path(@cp[$start][$end] + 1, $end);
|
||||
take ')';
|
||||
}
|
||||
}
|
||||
|
||||
return @cp[$n-1][0], gather { find-path(0, $n - 1) }.join;
|
||||
}
|
||||
|
||||
say matrix-mult-chaining(<1 5 25 30 100 70 2 1 100 250 1 1000 2>);
|
||||
say matrix-mult-chaining(<1000 1 500 12 1 700 2500 3 2 5 14 10>);
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
fn main() {
|
||||
println!("{}\n", mcm_display(vec![5, 6, 3, 1]));
|
||||
println!(
|
||||
"{}\n",
|
||||
mcm_display(vec![1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2])
|
||||
);
|
||||
println!(
|
||||
"{}\n",
|
||||
mcm_display(vec![1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10])
|
||||
);
|
||||
}
|
||||
|
||||
fn mcm_display(dims: Vec<i32>) -> String {
|
||||
let mut costs: HashMap<Vec<i32>, (i32, Vec<usize>)> = HashMap::new();
|
||||
let mut line = format!("Dims : {:?}\n", dims);
|
||||
let ans = mcm(dims, &mut costs);
|
||||
let mut mats = (1..=ans.1.len() + 1)
|
||||
.map(|x| x.to_string())
|
||||
.collect::<Vec<String>>();
|
||||
for i in 0..ans.1.len() {
|
||||
let mat_taken = mats[ans.1[i]].clone();
|
||||
mats.remove(ans.1[i]);
|
||||
mats[ans.1[i]] = "(".to_string() + &mat_taken + "*" + &mats[ans.1[i]] + ")";
|
||||
}
|
||||
line += &format!("Order: {}\n", mats[0]);
|
||||
line += &format!("Cost : {}", ans.0);
|
||||
line
|
||||
}
|
||||
|
||||
fn mcm(dims: Vec<i32>, costs: &mut HashMap<Vec<i32>, (i32, Vec<usize>)>) -> (i32, Vec<usize>) {
|
||||
match costs.get(&dims) {
|
||||
Some(c) => c.clone(),
|
||||
None => {
|
||||
let ans = if dims.len() == 3 {
|
||||
(dims[0] * dims[1] * dims[2], vec![0])
|
||||
} else {
|
||||
let mut min_cost = std::i32::MAX;
|
||||
let mut min_path = Vec::new();
|
||||
for i in 1..dims.len() - 1 {
|
||||
let taken = dims[(i - 1)..(i + 2)].to_vec();
|
||||
let mut rest = dims[..i].to_vec();
|
||||
rest.extend_from_slice(&dims[(i + 1)..]);
|
||||
let a1 = mcm(taken, costs);
|
||||
let a2 = mcm(rest, costs);
|
||||
if a1.0 + a2.0 < min_cost {
|
||||
min_cost = a1.0 + a2.0;
|
||||
min_path = vec![i - 1];
|
||||
min_path.extend_from_slice(&a2.1);
|
||||
}
|
||||
}
|
||||
(min_cost, min_path)
|
||||
};
|
||||
costs.insert(dims, ans.clone());
|
||||
ans
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
mata
|
||||
struct ans {
|
||||
real scalar p,q,s
|
||||
string scalar u
|
||||
}
|
||||
|
||||
struct ans scalar function aux(n,k) {
|
||||
external dim,opt
|
||||
struct ans scalar r,r1,r2
|
||||
real scalar s,i
|
||||
|
||||
if (n==1) {
|
||||
r.p = dim[k]
|
||||
r.q = dim[k+1]
|
||||
r.s = 0
|
||||
r.u = strofreal(k)
|
||||
return(r)
|
||||
} else if (n==2) {
|
||||
r.p = dim[k]
|
||||
r.q = dim[k+2]
|
||||
r.s = r.p*r.q*dim[k+1]
|
||||
r.u = sprintf("(%f*%f)",k,k+1)
|
||||
return(r)
|
||||
} else if (asarray_contains(opt,(n,k))) {
|
||||
return(asarray(opt,(n,k)))
|
||||
} else {
|
||||
r.p = dim[k]
|
||||
r.q = dim[k+n]
|
||||
r.s = .
|
||||
for (i=1; i<n; i++) {
|
||||
r1 = aux(i,k)
|
||||
r2 = aux(n-i,k+i)
|
||||
s = r1.s+r2.s+r1.p*r1.q*r2.q
|
||||
if (s<r.s) {
|
||||
r.s = s
|
||||
r.u = sprintf("(%s*%s)",r1.u,r2.u)
|
||||
}
|
||||
}
|
||||
asarray(opt,(n,k),r)
|
||||
return(r)
|
||||
}
|
||||
}
|
||||
|
||||
function optim(a) {
|
||||
external dim,opt
|
||||
struct ans scalar r
|
||||
real scalar t
|
||||
|
||||
timer_clear()
|
||||
dim = a
|
||||
opt = asarray_create("real",2)
|
||||
timer_on(1)
|
||||
r = aux(length(a)-1,1)
|
||||
timer_off(1)
|
||||
t = timer_value(1)[1]
|
||||
printf("%10.0f %10.0f %s\n",t*1000,r.s,r.u)
|
||||
}
|
||||
|
||||
optim((1,5,25,30,100,70,2,1,100,250,1,1000,2))
|
||||
optim((1000,1,500,12,1,700,2500,3,2,5,14,10))
|
||||
end
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
mata
|
||||
function aux(u,i,j) {
|
||||
k = u[i,j]
|
||||
if (k<0) {
|
||||
printf("%f",i)
|
||||
} else {
|
||||
printf("(")
|
||||
aux(u,i,k)
|
||||
printf("*")
|
||||
aux(u,i+k,j-k)
|
||||
printf(")")
|
||||
}
|
||||
}
|
||||
|
||||
function optim(a) {
|
||||
n = length(a)-1
|
||||
u = J(n,n,.)
|
||||
v = J(n,n,.)
|
||||
u[.,1] = J(n,1,-1)
|
||||
v[.,1] = J(n,1,0)
|
||||
for (j=2; j<=n; j++) {
|
||||
for (i=1; i<=n-j+1; i++) {
|
||||
for (k=1; k<j; k++) {
|
||||
c = v[i,k]+v[i+k,j-k]+a[i]*a[i+k]*a[i+j]
|
||||
if (c<v[i,j]) {
|
||||
u[i,j] = k
|
||||
v[i,j] = c
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("%f ",v[1,n])
|
||||
aux(u,1,n)
|
||||
printf("\n")
|
||||
}
|
||||
|
||||
optim((1,5,25,30,100,70,2,1,100,250,1,1000,2))
|
||||
optim((1000,1,500,12,1,700,2500,3,2,5,14,10))
|
||||
end
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
Option Explicit
|
||||
Option Base 1
|
||||
Dim N As Long, U() As Long, V() As Long
|
||||
Sub Optimize(A As Variant)
|
||||
Dim I As Long, J As Long, K As Long, C As Long
|
||||
N = UBound(A) - 1
|
||||
ReDim U(N, N), V(N, N)
|
||||
For I = 1 To N
|
||||
U(I, 1) = -1
|
||||
V(I, 1) = 0
|
||||
Next I
|
||||
|
||||
For J = 2 To N
|
||||
For I = 1 To N - J + 1
|
||||
V(I, J) = &H7FFFFFFF
|
||||
For K = 1 To J - 1
|
||||
C = V(I, K) + V(I + K, J - K) + A(I) * A(I + K) * A(I + J)
|
||||
If C < V(I, J) Then
|
||||
U(I, J) = K
|
||||
V(I, J) = C
|
||||
End If
|
||||
Next K
|
||||
Next I
|
||||
Next J
|
||||
|
||||
Debug.Print V(1, N);
|
||||
Call Aux(1, N)
|
||||
Debug.Print
|
||||
Erase U, V
|
||||
End Sub
|
||||
Sub Aux(I As Long, J As Long)
|
||||
Dim K As Long
|
||||
K = U(I, J)
|
||||
If K < 0 Then
|
||||
Debug.Print CStr(I);
|
||||
Else
|
||||
Debug.Print "(";
|
||||
Call Aux(I, K)
|
||||
Debug.Print "*";
|
||||
Call Aux(I + K, J - K)
|
||||
Debug.Print ")";
|
||||
End If
|
||||
End Sub
|
||||
Sub Test()
|
||||
Call Optimize(Array(5, 6, 3, 1))
|
||||
Call Optimize(Array(1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2))
|
||||
Call Optimize(Array(1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10))
|
||||
End Sub
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
var m = []
|
||||
var s = []
|
||||
|
||||
var optimalMatrixChainOrder = Fn.new { |dims|
|
||||
var n = dims.count - 1
|
||||
m = List.filled(n, null)
|
||||
s = List.filled(n, null)
|
||||
for (i in 0...n) {
|
||||
m[i] = List.filled(n, 0)
|
||||
s[i] = List.filled(n, 0)
|
||||
}
|
||||
for (len in 1...n) {
|
||||
for (i in 0...n-len) {
|
||||
var j = i + len
|
||||
m[i][j] = 1/0
|
||||
for (k in i...j) {
|
||||
var temp = dims[i] * dims [k + 1] * dims[j + 1]
|
||||
var cost = m[i][k] + m[k + 1][j] + temp
|
||||
if (cost < m[i][j]) {
|
||||
m[i][j] = cost
|
||||
s[i][j] = k
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var printOptimalChainOrder
|
||||
printOptimalChainOrder = Fn.new { |i, j|
|
||||
if (i == j) {
|
||||
System.write(String.fromByte(i + 65))
|
||||
} else {
|
||||
System.write("(")
|
||||
printOptimalChainOrder.call(i, s[i][j])
|
||||
printOptimalChainOrder.call(s[i][j] + 1, j)
|
||||
System.write(")")
|
||||
}
|
||||
}
|
||||
|
||||
var dimsList = [
|
||||
[5, 6, 3, 1],
|
||||
[1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2],
|
||||
[1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10]
|
||||
]
|
||||
for (dims in dimsList) {
|
||||
System.print("Dims : %(dims)")
|
||||
optimalMatrixChainOrder.call(dims)
|
||||
System.write("Order : ")
|
||||
printOptimalChainOrder.call(0, s.count - 1)
|
||||
System.print("\nCost : %(m[0][s.count - 1])\n")
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
fcn optim3(a){ // list --> (int,list)
|
||||
aux:=fcn(n,k,a){ // (int,int,list) --> (int,int,int,list)
|
||||
if(n==1){
|
||||
p,q := a[k,2];
|
||||
return(0,p,q,k);
|
||||
}
|
||||
if(n==2){
|
||||
p,q,r := a[k,3];
|
||||
return(p*q*r, p, r, T(k,k+1));
|
||||
}
|
||||
m,p,q,u := Void, a[k], a[k + n], Void;
|
||||
foreach i in ([1..n-1]){
|
||||
#if 0 // 0.70 sec for both tests
|
||||
s1,p1,q1,u1 := self.fcn(i,k,a);
|
||||
s2,p2,q2,u2 := self.fcn(n - i, k + i, a);
|
||||
#else // 0.33 sec for both tests
|
||||
s1,p1,q1,u1 := memoize(self.fcn, i,k,a);
|
||||
s2,p2,q2,u2 := memoize(self.fcn, n - i, k + i, a);
|
||||
#endif
|
||||
_assert_(q1==p2);
|
||||
s:=s1 + s2 + p1*q1*q2;
|
||||
if((Void==m) or (s<m)) m,u = s,T(u1,u2);
|
||||
}
|
||||
return(m,p,q,u);
|
||||
};
|
||||
|
||||
h=Dictionary(); // reset memoize
|
||||
s,_,_,u := aux(a.len() - 1, 0,a);
|
||||
return(s,u);
|
||||
}
|
||||
|
||||
var h; // a Dictionary, set/reset in optim3()
|
||||
fcn memoize(f,n,k,a){
|
||||
key:="%d,%d".fmt(n,k); // Lists make crappy keys
|
||||
if(r:=h.find(key)) return(r);
|
||||
r:=f(n,k,a);
|
||||
h[key]=r;
|
||||
return(r);
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
fcn pp(u){ // pretty print a list of lists
|
||||
var letters=["A".."Z"].pump(String);
|
||||
u.pump(String,
|
||||
fcn(n){ if(List.isType(n)) String("(",pp(n),")") else letters[n] })
|
||||
}
|
||||
fcn prnt(s,u){ "%-9,d %s\n\t-->%s\n".fmt(s,u.toString(*,*),pp(u)).println() }
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
s,u := optim3(T(1, 5, 25, 30, 100, 70, 2, 1, 100, 250, 1, 1000, 2));
|
||||
prnt(s,u);
|
||||
|
||||
s,u := optim3(T(1000, 1, 500, 12, 1, 700, 2500, 3, 2, 5, 14, 10));
|
||||
prnt(s,u);
|
||||
|
||||
optim3(T(5,6,3,1)) : prnt(_.xplode());
|
||||
Loading…
Add table
Add a link
Reference in a new issue