Skip to content

Commit bfa64e0

Browse files
committed
fix: attempt hungarian solver on dropped neural
1 parent 9416b9e commit bfa64e0

22 files changed

Lines changed: 1603 additions & 270 deletions

examples/advanced/DroppedNeuralNet/Data/_01_Raw/Catalog.Raw.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,16 @@ public partial class Catalog
3636

3737
/// <summary>
3838
/// Raw layer blobs loaded from the pieces directory.
39-
/// Produced by the load_pieces Python step; held in memory throughout the pipeline.
40-
/// The pieces directory path is passed as configuration — Flowthru is not responsible
41-
/// for managing the individual .pth files.
39+
/// Produced by the load_pieces Python step; persisted as JSON (base64-encoded Data field)
40+
/// so downstream flows (Exploration, Validation, Solver) can run independently without
41+
/// re-executing DataPrep from scratch.
4242
/// </summary>
4343
public IItem<IEnumerable<PieceBlob>> Pieces =>
44-
CreateItem(() => ItemFactory.Enumerable.Memory<PieceBlob>(label: "Pieces"));
44+
CreateItem(
45+
() =>
46+
ItemFactory.Enumerable.Json<PieceBlob>(
47+
label: "Pieces",
48+
filePath: $"{_basePath}/_01_Raw/Datasets/pieces.json"
49+
)
50+
);
4551
}

examples/advanced/DroppedNeuralNet/Data/_01_Raw/Datasets/pieces.json

Lines changed: 390 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using DroppedNeuralNet.Data._04_Analysis.Schemas;
2+
using Flowthru.Core.Data;
3+
4+
namespace DroppedNeuralNet.Data;
5+
6+
public partial class Catalog
7+
{
8+
/// <summary>
9+
/// Frobenius norms of the weight product ||out.W @ inp.W||_F for every legal (inp, out) pairing.
10+
/// Produced by the compute_pairing_scores Python step; persisted as JSON for inspection.
11+
/// </summary>
12+
public IItem<IEnumerable<PairingScore>> PairingScores =>
13+
CreateItem(
14+
() =>
15+
ItemFactory.Enumerable.Json<PairingScore>(
16+
label: "PairingScores",
17+
filePath: $"{_basePath}/_04_Analysis/Datasets/pairing_scores.json"
18+
)
19+
);
20+
21+
/// <summary>
22+
/// Optimal (inp, out) Block pairings selected by the Hungarian algorithm.
23+
/// Minimises total ProductNorm across all 48 Block assignments.
24+
/// Persisted as JSON; consumed by the rank_orderings step.
25+
/// </summary>
26+
public IItem<IEnumerable<BlockAssignment>> BlockAssignments =>
27+
CreateItem(
28+
() =>
29+
ItemFactory.Enumerable.Json<BlockAssignment>(
30+
label: "BlockAssignments",
31+
filePath: $"{_basePath}/_04_Analysis/Datasets/block_assignments.json"
32+
)
33+
);
34+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using Flowthru.Core.Abstractions;
2+
3+
namespace DroppedNeuralNet.Data._04_Analysis.Schemas;
4+
5+
/// <summary>
6+
/// A single Block pairing selected by the Hungarian algorithm: the globally optimal
7+
/// assignment of inp pieces to out pieces under the minimum total ProductNorm objective.
8+
/// </summary>
9+
[FlowthruSchema]
10+
public partial record BlockAssignment
11+
{
12+
/// <summary>Sequential Block position assigned by the Hungarian solver (0–47). Not the execution order.</summary>
13+
public int BlockIndex { get; init; }
14+
15+
public int InpPieceIndex { get; init; }
16+
public int OutPieceIndex { get; init; }
17+
18+
/// <summary>ProductNorm score for this pairing — the cost the solver minimized.</summary>
19+
public float AssignmentScore { get; init; }
20+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using Flowthru.Core.Abstractions;
2+
3+
namespace DroppedNeuralNet.Data._04_Analysis.Schemas;
4+
5+
/// <summary>
6+
/// The Frobenius norm of the product ||out.W @ inp.W||_F for a candidate Block pairing.
7+
/// Lower values indicate that the out layer is a better inverse of the inp layer,
8+
/// which is the structural signal left in the weights by the residual training objective.
9+
/// </summary>
10+
[FlowthruSchema]
11+
public partial record PairingScore
12+
{
13+
public int InpPieceIndex { get; init; }
14+
public int OutPieceIndex { get; init; }
15+
16+
/// <summary>||W_out @ W_inp||_F. Lower = stronger residual coupling between these two layers.</summary>
17+
public float ProductNorm { get; init; }
18+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using DroppedNeuralNet.Data._05_Candidates.Schemas;
2+
using Flowthru.Core.Data;
3+
4+
namespace DroppedNeuralNet.Data;
5+
6+
public partial class Catalog
7+
{
8+
/// <summary>
9+
/// Ranked candidate execution orderings produced by the rank_orderings step.
10+
/// Each row is a JSON-encoded int[97] permutation. Persisted as JSON so the
11+
/// Solver flow can be run independently after Exploration completes.
12+
/// </summary>
13+
public IItem<IEnumerable<CandidatePermutation>> CandidatePermutations =>
14+
CreateItem(
15+
() =>
16+
ItemFactory.Enumerable.Json<CandidatePermutation>(
17+
label: "CandidatePermutations",
18+
filePath: $"{_basePath}/_05_Candidates/Datasets/candidate_permutations.json"
19+
)
20+
);
21+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using Flowthru.Core.Abstractions;
2+
3+
namespace DroppedNeuralNet.Data._05_Candidates.Schemas;
4+
5+
/// <summary>
6+
/// A single candidate execution ordering for the 97 network pieces.
7+
/// The permutation is JSON-encoded so it can cross the Arrow boundary as a flat string
8+
/// and be decoded by Python steps without a nested-schema storage adapter.
9+
/// </summary>
10+
[FlowthruSchema]
11+
public partial record CandidatePermutation
12+
{
13+
public int CandidateIndex { get; init; }
14+
15+
/// <summary>
16+
/// JSON-encoded int array of length 97.
17+
/// Positions 2k and 2k+1 are the inp/out pieces for Block k (k = 0..47).
18+
/// Position 96 is the LastLayer piece index.
19+
/// Example: "[12, 45, 3, 67, ...]"
20+
/// </summary>
21+
public string Permutation { get; init; } = "[]";
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using DroppedNeuralNet.Data._08_Reporting.Schemas;
2+
using Flowthru.Core.Data;
3+
4+
namespace DroppedNeuralNet.Data;
5+
6+
public partial class Catalog
7+
{
8+
/// <summary>
9+
/// Diagnostic measurements from the Validation flow.
10+
/// Each row is a (Category, Metric, Value, Notes) tuple covering pairing signal
11+
/// quality, fixed-ordering baseline error, and per-candidate forward-pass errors.
12+
/// Persisted as JSON so reports survive process exit and can be inspected offline.
13+
/// </summary>
14+
public IItem<IEnumerable<DiagnosticEntry>> Diagnostics =>
15+
CreateItem(
16+
() =>
17+
ItemFactory.Enumerable.Json<DiagnosticEntry>(
18+
label: "Diagnostics",
19+
filePath: $"{_basePath}/_08_Reporting/Datasets/diagnostics.json"
20+
)
21+
);
22+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using Flowthru.Core.Abstractions;
2+
3+
namespace DroppedNeuralNet.Data._08_Reporting.Schemas;
4+
5+
/// <summary>
6+
/// A single diagnostic measurement emitted by the Validation flow.
7+
///
8+
/// Rows are grouped by <see cref="Category"/> (e.g. "FixedOrdering", "Candidate_3",
9+
/// "PairingSignal") and keyed by <see cref="Metric"/> within each group. This flat
10+
/// schema lets a single step emit heterogeneous signal types without requiring a
11+
/// separate schema per check.
12+
/// </summary>
13+
[FlowthruSchema]
14+
public partial record DiagnosticEntry
15+
{
16+
/// <summary>Logical grouping, e.g. "FixedOrdering", "Candidate_7", "PairingSignal".</summary>
17+
public string Category { get; init; } = "";
18+
19+
/// <summary>Name of the measured quantity, e.g. "MaxErr", "MeanErr", "ScoreStd".</summary>
20+
public string Metric { get; init; } = "";
21+
22+
/// <summary>Numeric value of the measurement.</summary>
23+
public float Value { get; init; }
24+
25+
/// <summary>Optional human-readable context emitted alongside the value.</summary>
26+
public string Notes { get; init; } = "";
27+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using DroppedNeuralNet.Data;
2+
using DroppedNeuralNet.Data._01_Raw.Schemas;
3+
using DroppedNeuralNet.Data._02_Intermediate.Schemas;
4+
using DroppedNeuralNet.Data._03_Primary.Schemas;
5+
using DroppedNeuralNet.Data._04_Analysis.Schemas;
6+
using DroppedNeuralNet.Data._05_Candidates.Schemas;
7+
using DroppedNeuralNet.Flows.Exploration.Steps;
8+
using Flowthru.Core.Flows;
9+
using Flowthru.Extensions.Python.Execution;
10+
using Flowthru.Extensions.Python.Steps;
11+
12+
namespace DroppedNeuralNet.Flows.Exploration;
13+
14+
/// <summary>
15+
/// Analytical pipeline that narrows the search space before the Solver validates permutations.
16+
///
17+
/// Step 1 (C#) — FindLegalPairings:
18+
/// Sieves PieceMetadata to enumerate every structurally valid (inp, out) Block candidate.
19+
/// Pure dimension arithmetic; no blobs.
20+
///
21+
/// Step 2 (Python) — compute_pairing_scores:
22+
/// For every legal (inp, out) candidate, computes ||W_out @ W_inp||_F.
23+
/// Lower scores indicate residual coupling — the signal left by training.
24+
///
25+
/// Step 3 (Python) — run_hungarian:
26+
/// Applies the Hungarian algorithm to the 48×48 score matrix.
27+
/// Produces the globally optimal assignment of inp ↔ out pieces in O(n³).
28+
///
29+
/// Step 4 (Python) — rank_orderings:
30+
/// Uses activation chaining on historical data to score Block execution orderings.
31+
/// Emits a small ranked set of candidate permutations for the Solver to validate.
32+
/// </summary>
33+
public static class ExplorationFlow
34+
{
35+
public static Flow Create(Catalog catalog, IPythonExecutor executor)
36+
{
37+
return FlowBuilder.CreateFlow(pipeline =>
38+
{
39+
pipeline.AddStep(
40+
label: "FindLegalPairings",
41+
description: "Sieve PieceMetadata to all dimension-valid (inp, out) Block candidates (C#).",
42+
transform: FindLegalPairingsStep.Create(),
43+
input: catalog.PieceMetadata,
44+
output: catalog.LegalPairings
45+
);
46+
47+
pipeline.AddPythonStep<
48+
IEnumerable<PieceMetadata>,
49+
IEnumerable<PieceBlob>,
50+
IEnumerable<BlockCandidate>,
51+
IEnumerable<PairingScore>
52+
>(
53+
label: "ComputePairingScores",
54+
description: "Compute ||W_out @ W_inp||_F for every legal pairing. Lower = stronger residual coupling (Python).",
55+
module: "Flows.Exploration.Steps.compute_pairing_scores",
56+
function: "compute_pairing_scores",
57+
input: (catalog.PieceMetadata, catalog.Pieces, catalog.LegalPairings),
58+
output: catalog.PairingScores,
59+
executor: executor
60+
);
61+
62+
pipeline.AddPythonStep<IEnumerable<PairingScore>, IEnumerable<BlockAssignment>>(
63+
label: "RunHungarian",
64+
description: "Globally optimal inp↔out assignment via Hungarian algorithm on the 48×48 score matrix (Python).",
65+
module: "Flows.Exploration.Steps.run_hungarian",
66+
function: "run_hungarian",
67+
input: catalog.PairingScores,
68+
output: catalog.BlockAssignments,
69+
executor: executor
70+
);
71+
72+
pipeline.AddPythonStep<
73+
IEnumerable<BlockAssignment>,
74+
IEnumerable<PieceBlob>,
75+
IEnumerable<MeasurementSchema>,
76+
IEnumerable<CandidatePermutation>
77+
>(
78+
label: "RankOrderings",
79+
description: "Score Block execution orderings via activation chaining; emit top-N candidate permutations (Python).",
80+
module: "Flows.Exploration.Steps.rank_orderings",
81+
function: "rank_orderings",
82+
input: (catalog.BlockAssignments, catalog.Pieces, catalog.HistoricalData),
83+
output: catalog.CandidatePermutations,
84+
executor: executor
85+
);
86+
});
87+
}
88+
}

0 commit comments

Comments
 (0)