790-matrix-chain-multiplication — Matrix Chain Multiplication
Tutorial Video
Text description (accessibility)
This video demonstrates the "790-matrix-chain-multiplication — Matrix Chain Multiplication" functional Rust example. Difficulty level: Advanced. Key concepts covered: Functional Programming. The matrix chain multiplication problem asks: in what order should a sequence of matrices be multiplied to minimize the total number of scalar multiplications? Key difference from OCaml: 1. **Interval DP pattern**: Both languages use the same outer
Tutorial
The Problem
The matrix chain multiplication problem asks: in what order should a sequence of matrices be multiplied to minimize the total number of scalar multiplications? Different association orders can differ by orders of magnitude: (A × B) × C might cost 1000 operations while A × (B × C) costs 100. The O(n³) DP solution, from Godbole (1973), is a textbook example of interval DP and is used in query optimization in databases (join reordering) and deep learning compilers (operation fusion).
🎯 Learning Outcomes
dims: &[usize] where dims[i] × dims[i+1] is the size of matrix idp[i][j] = min cost to multiply matrices i through jk in i..j as split pointsCode Example
#![allow(clippy::all)]
//! # Matrix Chain Multiplication
pub fn matrix_chain(dims: &[usize]) -> usize {
let n = dims.len() - 1;
if n <= 1 {
return 0;
}
let mut dp = vec![vec![0; n]; n];
for len in 2..=n {
for i in 0..=n - len {
let j = i + len - 1;
dp[i][j] = usize::MAX;
for k in i..j {
let cost = dp[i][k] + dp[k + 1][j] + dims[i] * dims[k + 1] * dims[j + 1];
dp[i][j] = dp[i][j].min(cost);
}
}
}
dp[0][n - 1]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_matrix_chain() {
assert_eq!(matrix_chain(&[10, 20, 30, 40, 30]), 30000);
}
#[test]
fn test_two() {
assert_eq!(matrix_chain(&[10, 20, 30]), 6000);
}
}Key Differences
dp[i][j] = usize::MAX as infinity; OCaml uses max_int — same concept.OCaml Approach
OCaml implements interval DP with Array.make_matrix n n 0 and nested for loops. The outer loop is over chain length, not indices directly, to ensure smaller subproblems are solved before larger ones. OCaml's min function and imperative array updates make this direct. The reconstruction uses a separate split: int array array table storing optimal split points.
Full Source
#![allow(clippy::all)]
//! # Matrix Chain Multiplication
pub fn matrix_chain(dims: &[usize]) -> usize {
let n = dims.len() - 1;
if n <= 1 {
return 0;
}
let mut dp = vec![vec![0; n]; n];
for len in 2..=n {
for i in 0..=n - len {
let j = i + len - 1;
dp[i][j] = usize::MAX;
for k in i..j {
let cost = dp[i][k] + dp[k + 1][j] + dims[i] * dims[k + 1] * dims[j + 1];
dp[i][j] = dp[i][j].min(cost);
}
}
}
dp[0][n - 1]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_matrix_chain() {
assert_eq!(matrix_chain(&[10, 20, 30, 40, 30]), 30000);
}
#[test]
fn test_two() {
assert_eq!(matrix_chain(&[10, 20, 30]), 6000);
}
}#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_matrix_chain() {
assert_eq!(matrix_chain(&[10, 20, 30, 40, 30]), 30000);
}
#[test]
fn test_two() {
assert_eq!(matrix_chain(&[10, 20, 30]), 6000);
}
}
Deep Comparison
OCaml vs Rust: Matrix Chain Multiplication
Overview
See the example.rs and example.ml files for detailed implementations.
Key Differences
| Aspect | OCaml | Rust |
|---|---|---|
| Type system | Hindley-Milner | Ownership + traits |
| Memory | GC | Zero-cost abstractions |
| Mutability | Explicit ref | mut keyword |
| Error handling | Option/Result | Result<T, E> |
See README.md for detailed comparison.
Exercises
matrix_chain_order(dims) function that returns the optimal parenthesization as a string like "((A(BC))D)".