From 97a29c6baca1beadd29e5e79f36381440b126952 Mon Sep 17 00:00:00 2001 From: giles Date: Mon, 11 May 2026 03:44:40 +0000 Subject: [PATCH] ocaml: phase 5.1 stock_two.ml baseline (best of 2 transactions = 6) Two-pass partition DP for max profit with at most 2 transactions: left[i] = max single-trans profit in prices[0..i] (forward scan tracking running min) right[i] = max single-trans profit in prices[i..n-1] (backward scan tracking running max) answer = max over i of (left[i] + right[i]) For [3; 3; 5; 0; 0; 3; 1; 4]: optimal partition i = 2: left[2] = sell@5 after buy@3 = 2 right[2] = sell@4 after buy@0 in [2..7] = 4 total = 6 Tests parallel forward + backward passes on parallel DP arrays, mixed ref + array state, for downto + for ascending scans on the same data. 190 baseline programs total. --- lib/ocaml/baseline/expected.json | 1 + lib/ocaml/baseline/stock_two.ml | 29 +++++++++++++++++++++++++++++ plans/ocaml-on-sx.md | 10 ++++++++++ 3 files changed, 40 insertions(+) create mode 100644 lib/ocaml/baseline/stock_two.ml diff --git a/lib/ocaml/baseline/expected.json b/lib/ocaml/baseline/expected.json index c9a73bf7..36865605 100644 --- a/lib/ocaml/baseline/expected.json +++ b/lib/ocaml/baseline/expected.json @@ -166,6 +166,7 @@ "shuffle.ml": 55, "simpson_int.ml": 10000, "stable_unique.ml": 46, + "stock_two.ml": 6, "subseq_check.ml": 3, "tail_factorial.ml": 479001600, "tarjan_scc.ml": 4, diff --git a/lib/ocaml/baseline/stock_two.ml b/lib/ocaml/baseline/stock_two.ml new file mode 100644 index 00000000..063710fe --- /dev/null +++ b/lib/ocaml/baseline/stock_two.ml @@ -0,0 +1,29 @@ +let max_profit_two prices = + let n = Array.length prices in + if n < 2 then 0 + else begin + let left = Array.make n 0 in + let min_p = ref prices.(0) in + for i = 1 to n - 1 do + if prices.(i) < !min_p then min_p := prices.(i); + let p = prices.(i) - !min_p in + left.(i) <- if p > left.(i - 1) then p else left.(i - 1) + done; + let right = Array.make n 0 in + let max_p = ref prices.(n - 1) in + for i = n - 2 downto 0 do + if prices.(i) > !max_p then max_p := prices.(i); + let p = !max_p - prices.(i) in + right.(i) <- if p > right.(i + 1) then p else right.(i + 1) + done; + let best = ref 0 in + for i = 0 to n - 1 do + let total = left.(i) + right.(i) in + if total > !best then best := total + done; + !best + end + +;; + +max_profit_two [| 3; 3; 5; 0; 0; 3; 1; 4 |] diff --git a/plans/ocaml-on-sx.md b/plans/ocaml-on-sx.md index caf5e05f..8a8699e8 100644 --- a/plans/ocaml-on-sx.md +++ b/plans/ocaml-on-sx.md @@ -407,6 +407,16 @@ _Newest first._ binary search tree (`type 'a tree = Leaf | Node of 'a * 'a tree * 'a tree`) with insert + in-order traversal. Tests parametric ADT, recursive match, List.append, List.fold_left. +- 2026-05-11 Phase 5.1 — stock_two.ml baseline (max stock profit + with at most 2 transactions on [3;3;5;0;0;3;1;4] = 6). Two-pass + DP: left[i] = max single-transaction profit in prices[0..i] + (forward, tracking running min), right[i] = max single-transaction + profit in prices[i..n-1] (backward, tracking running max). Final + answer = max over i of left[i]+right[i], partitioning at the + best split. Optimal: buy@3, sell@5 (profit 2); buy@0, sell@4 + (profit 4); total = 6. Tests parallel forward + backward passes + on parallel DP arrays, mixed ref+array state, downto + ascending + scans on same data. 190 baseline programs total. - 2026-05-11 Phase 5.1 — house_robber.ml baseline (linear-DP max non-adjacent-sum on [2;7;9;3;1;5;8;6] = 22). dp[i] = max(dp[i-2]+houses[i], dp[i-1]). Optimal pick {7, 9, 5, 8} but