Fix bugs from 5-2 code review

This commit is contained in:
Sepehr
2026-02-21 10:43:55 +01:00
parent 400f1c420e
commit 0d9a0e4231
27 changed files with 9838 additions and 114 deletions

752
inverse_control_report.html Normal file
View File

@@ -0,0 +1,752 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Inverse Control Demo Report</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
:root {
--primary-color: #2c3e50;
--secondary-color: #3498db;
--success-color: #27ae60;
--warning-color: #f39c12;
--danger-color: #e74c3c;
}
body {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
min-height: 100vh;
}
.card {
border: none;
border-radius: 15px;
box-shadow: 0 10px 40px rgba(0,0,0,0.1);
transition: transform 0.3s ease;
}
.card:hover {
transform: translateY(-5px);
}
.code-block {
background: #1e1e1e;
color: #d4d4d4;
border-radius: 10px;
padding: 20px;
overflow-x: auto;
font-family: 'Fira Code', 'Consolas', monospace;
font-size: 0.9rem;
}
.code-block .keyword { color: #569cd6; }
.code-block .string { color: #ce9178; }
.code-block .number { color: #b5cea8; }
.code-block .comment { color: #6a9955; }
.code-block .function { color: #dcdcaa; }
.code-block .type { color: #4ec9b0; }
.formula {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px;
border-radius: 10px;
font-family: 'Times New Roman', serif;
font-size: 1.2rem;
text-align: center;
}
.workflow-step {
border-left: 4px solid var(--secondary-color);
padding-left: 20px;
margin-bottom: 20px;
}
.workflow-step::before {
content: '';
width: 20px;
height: 20px;
background: var(--secondary-color);
border-radius: 50%;
display: inline-block;
margin-left: -30px;
margin-right: 10px;
}
.status-badge {
padding: 5px 15px;
border-radius: 20px;
font-weight: bold;
}
.dof-balanced { background: #d4edda; color: #155724; }
.dof-over { background: #f8d7da; color: #721c24; }
.dof-under { background: #fff3cd; color: #856404; }
.gradient-text {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.icon-box {
width: 60px;
height: 60px;
border-radius: 15px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
color: white;
}
.chart-container {
position: relative;
height: 300px;
}
</style>
</head>
</body>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="#">
<i class="bi bi-cpu"></i> Entropyk Inverse Control
</a>
<div class="navbar-nav ms-auto">
<a class="nav-link" href="#concept"><i class="bi bi-lightbulb"></i> Concept</a>
<a class="nav-link" href="#dof"><i class="bi bi-calculator"></i> DoF</a>
<a class="nav-link" href="#workflow"><i class="bi bi-diagram-3"></i> Workflow</a>
<a class="nav-link" href="#code"><i class="bi bi-code-slash"></i> Code</a>
<a class="nav-link" href="#results"><i class="bi bi-graph-up"></i> Results</a>
</div>
</div>
</nav>
<div class="container mt-4">
<h1 class="mb-4">🎯 Inverse Control Demo Report</h1>
<p class="text-muted">Generated: 2026-02-21 10:42:46</p>
<section id="concept" class="mb-5">
<div class="card">
<div class="card-body p-4">
<h2 class="card-title mb-4">
<i class="bi bi-lightbulb text-warning me-2"></i>
One-Shot Inverse Control Concept
</h2>
<div class="row">
<div class="col-md-6">
<h4>What is Inverse Control?</h4>
<p>
Instead of specifying inputs and computing outputs (forward simulation),
<strong>inverse control</strong> specifies desired outputs and computes
the required inputs automatically.
</p>
<div class="alert alert-info">
<i class="bi bi-info-circle me-2"></i>
<strong>Example:</strong> "Maintain 5K superheat" → System finds the correct valve position
</div>
<h4 class="mt-4">Traditional Approach</h4>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<i class="bi bi-x-circle text-danger me-2"></i>
Outer optimization loop
</li>
<li class="list-group-item">
<i class="bi bi-x-circle text-danger me-2"></i>
Many solver iterations
</li>
<li class="list-group-item">
<i class="bi bi-x-circle text-danger me-2"></i>
Slow convergence
</li>
</ul>
</div>
<div class="col-md-6">
<h4>One-Shot Approach (FR24)</h4>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<i class="bi bi-check-circle text-success me-2"></i>
Single solver call
</li>
<li class="list-group-item">
<i class="bi bi-check-circle text-success me-2"></i>
Constraints embedded in residuals
</li>
<li class="list-group-item">
<i class="bi bi-check-circle text-success me-2"></i>
Control variables as unknowns
</li>
<li class="list-group-item">
<i class="bi bi-check-circle text-success me-2"></i>
Fast convergence
</li>
</ul>
<div class="formula mt-4">
r<sub>total</sub> = [r<sub>cycle</sub>, r<sub>constraints</sub>]<sup>T</sup> = 0
</div>
</div>
</div>
</div>
</div>
</section>
<section id="dof" class="mb-5">
<div class="card">
<div class="card-body p-4">
<h2 class="card-title mb-4">
<i class="bi bi-calculator text-primary me-2"></i>
Degrees of Freedom (DoF) Validation
</h2>
<p>
For a well-posed system, the number of equations must equal the number of unknowns:
</p>
<div class="formula mb-4">
n<sub>equations</sub> = n<sub>edge_eqs</sub> + n<sub>constraints</sub><br>
n<sub>unknowns</sub> = n<sub>edge_unknowns</sub> + n<sub>controls</sub><br><br>
<strong>Balanced: n<sub>equations</sub> = n<sub>unknowns</sub></strong>
</div>
<div class="row">
<div class="col-md-4">
<div class="card bg-success text-white">
<div class="card-body text-center">
<h5><i class="bi bi-check-circle"></i> Balanced</h5>
<p class="mb-0">Equations = Unknowns</p>
<span class="status-badge dof-balanced bg-white text-success">SOLVABLE</span>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card bg-danger text-white">
<div class="card-body text-center">
<h5><i class="bi bi-x-circle"></i> Over-Constrained</h5>
<p class="mb-0">Equations > Unknowns</p>
<span class="status-badge dof-over bg-white text-danger">ERROR</span>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card bg-warning text-dark">
<div class="card-body text-center">
<h5><i class="bi bi-exclamation-triangle"></i> Under-Constrained</h5>
<p class="mb-0">Equations < Unknowns</p>
<span class="status-badge dof-under bg-white text-warning">WARNING</span>
</div>
</div>
</div>
</div>
<div class="mt-4">
<h5>Example Calculation</h5>
<table class="table table-bordered">
<thead class="table-light">
<tr>
<th>Component</th>
<th>Count</th>
<th>Contribution</th>
</tr>
</thead>
<tbody>
<tr>
<td>Edges</td>
<td>4</td>
<td>2 × 4 = 8 unknowns (P, h)</td>
</tr>
<tr>
<td>Components</td>
<td>4</td>
<td>8 equations (2 per component)</td>
</tr>
<tr>
<td>Constraints</td>
<td>1</td>
<td>+1 equation</td>
</tr>
<tr>
<td>Control Variables</td>
<td>1</td>
<td>+1 unknown</td>
</tr>
<tr class="table-success">
<td><strong>Total</strong></td>
<td></td>
<td><strong>9 equations = 9 unknowns ✓</strong></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</section>
<section id="workflow" class="mb-5">
<div class="card">
<div class="card-body p-4">
<h2 class="card-title mb-4">
<i class="bi bi-diagram-3 text-info me-2"></i>
Implementation Workflow
</h2>
<div class="row">
<div class="col-md-6">
<div class="workflow-step">
<h5>Step 1: Define Constraint</h5>
<p>Create a constraint specifying the desired output:</p>
<div class="code-block">
<span class="keyword">let</span> constraint = <span class="type">Constraint</span>::<span class="function">new</span>(
<span class="type">ConstraintId</span>::<span class="function">new</span>(<span class="string">"superheat"</span>),
<span class="type">ComponentOutput</span>::<span class="type">Superheat</span> {
component_id: <span class="string">"evaporator"</span>.<span class="function">into</span>(),
},
<span class="number">5.0</span>, <span class="comment">// target: 5K superheat</span>
);
</div>
</div>
<div class="workflow-step">
<h5>Step 2: Define Control Variable</h5>
<p>Create a bounded variable with physical limits:</p>
<div class="code-block">
<span class="keyword">let</span> valve = <span class="type">BoundedVariable</span>::<span class="function">new</span>(
<span class="type">BoundedVariableId</span>::<span class="function">new</span>(<span class="string">"expansion_valve"</span>),
<span class="number">0.5</span>, <span class="comment">// initial: 50% open</span>
<span class="number">0.0</span>, <span class="comment">// min: fully closed</span>
<span class="number">1.0</span>, <span class="comment">// max: fully open</span>
)?;
</div>
</div>
</div>
<div class="col-md-6">
<div class="workflow-step">
<h5>Step 3: Add to System</h5>
<p>Register constraint and control variable:</p>
<div class="code-block">
system.<span class="function">add_constraint</span>(constraint)?;
system.<span class="function">add_bounded_variable</span>(valve)?;
</div>
</div>
<div class="workflow-step">
<h5>Step 4: Link Constraint to Control</h5>
<p>Establish the One-Shot relationship:</p>
<div class="code-block">
system.<span class="function">link_constraint_to_control</span>(
&<span class="type">ConstraintId</span>::<span class="function">new</span>(<span class="string">"superheat"</span>),
&<span class="type">BoundedVariableId</span>::<span class="function">new</span>(<span class="string">"expansion_valve"</span>),
)?;
</div>
</div>
<div class="workflow-step">
<h5>Step 5: Validate DoF</h5>
<p>Ensure the system is well-posed:</p>
<div class="code-block">
system.<span class="function">validate_inverse_control_dof</span>()?;
<span class="comment">// Returns Ok(()) if balanced</span>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section id="code" class="mb-5">
<div class="card">
<div class="card-body p-4">
<h2 class="card-title mb-4">
<i class="bi bi-code-slash text-secondary me-2"></i>
Complete Code Example
</h2>
<ul class="nav nav-tabs" id="codeTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="rust-tab" data-bs-toggle="tab" data-bs-target="#rust" type="button">
Rust
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="api-tab" data-bs-toggle="tab" data-bs-target="#api" type="button">
API Reference
</button>
</li>
</ul>
<div class="tab-content mt-3" id="codeTabsContent">
<div class="tab-pane fade show active" id="rust" role="tabpanel">
<div class="code-block" style="max-height: 500px; overflow-y: auto;">
<span class="keyword">use</span> entropyk_solver::{
<span class="type">System</span>, <span class="type">CircuitId</span>,
inverse::{
<span class="type">Constraint</span>, <span class="type">ConstraintId</span>, <span class="type">ComponentOutput</span>,
<span class="type">BoundedVariable</span>, <span class="type">BoundedVariableId</span>,
},
};
<span class="keyword">fn</span> <span class="function">main</span>() -> <span class="type">Result</span><(), <span class="type">Box</span><<span class="keyword">dyn</span> <span class="type">Error</span>>> {
<span class="comment">// 1. Build the system</span>
<span class="keyword">let</span> <span class="keyword">mut</span> system = <span class="type">System</span>::<span class="function">new</span>();
<span class="comment">// Add components</span>
<span class="keyword">let</span> compressor = system.<span class="function">add_component</span>(<span class="function">make_compressor</span>());
<span class="keyword">let</span> condenser = system.<span class="function">add_component</span>(<span class="function">make_condenser</span>());
<span class="keyword">let</span> valve = system.<span class="function">add_component</span>(<span class="function">make_valve</span>());
<span class="keyword">let</span> evaporator = system.<span class="function">add_component</span>(<span class="function">make_evaporator</span>());
<span class="comment">// Register names for constraints</span>
system.<span class="function">register_component_name</span>(<span class="string">"evaporator"</span>, evaporator);
<span class="comment">// Connect components</span>
system.<span class="function">add_edge</span>(compressor, condenser)?;
system.<span class="function">add_edge</span>(condenser, valve)?;
system.<span class="function">add_edge</span>(valve, evaporator)?;
system.<span class="function">add_edge</span>(evaporator, compressor)?;
<span class="comment">// 2. Define constraint: maintain 5K superheat</span>
<span class="keyword">let</span> constraint = <span class="type">Constraint</span>::<span class="function">new</span>(
<span class="type">ConstraintId</span>::<span class="function">new</span>(<span class="string">"superheat_control"</span>),
<span class="type">ComponentOutput</span>::<span class="type">Superheat</span> {
component_id: <span class="string">"evaporator"</span>.<span class="function">to_string</span>(),
},
<span class="number">5.0</span>, <span class="comment">// target: 5 Kelvin</span>
);
system.<span class="function">add_constraint</span>(constraint)?;
<span class="comment">// 3. Define bounded control variable</span>
<span class="keyword">let</span> control = <span class="type">BoundedVariable</span>::<span class="function">new</span>(
<span class="type">BoundedVariableId</span>::<span class="function">new</span>(<span class="string">"valve_position"</span>),
<span class="number">0.5</span>, <span class="comment">// initial position</span>
<span class="number">0.1</span>, <span class="comment">// min: 10% open</span>
<span class="number">1.0</span>, <span class="comment">// max: fully open</span>
)?;
system.<span class="function">add_bounded_variable</span>(control)?;
<span class="comment">// 4. Link constraint to control (One-Shot)</span>
system.<span class="function">link_constraint_to_control</span>(
&<span class="type">ConstraintId</span>::<span class="function">new</span>(<span class="string">"superheat_control"</span>),
&<span class="type">BoundedVariableId</span>::<span class="function">new</span>(<span class="string">"valve_position"</span>),
)?;
<span class="comment">// 5. Finalize and validate DoF</span>
system.<span class="function">finalize</span>()?;
system.<span class="function">validate_inverse_control_dof</span>()?;
<span class="comment">// 6. Solve (One-Shot: constraints solved simultaneously)</span>
<span class="keyword">let</span> solver = <span class="type">NewtonRaphson</span>::<span class="function">new</span>();
<span class="keyword">let</span> result = solver.<span class="function">solve</span>(&system)?;
<span class="comment">// 7. Check result</span>
<span class="keyword">let</span> final_valve = system.<span class="function">get_bounded_variable</span>(
&<span class="type">BoundedVariableId</span>::<span class="function">new</span>(<span class="string">"valve_position"</span>)
).<span class="function">unwrap</span>();
<span class="function">println!</span>(<span class="string">"Valve position: {:.2}%"</span>, final_valve.<span class="function">value</span>() * <span class="number">100.0</span>);
<span class="function">println!</span>(<span class="string">"Converged: {:?}"</span>, result.<span class="function">converged</span>());
<span class="type">Ok</span>(())
}
</div>
</div>
<div class="tab-pane fade" id="api" role="tabpanel">
<h5>System Methods for Inverse Control</h5>
<table class="table table-striped">
<thead>
<tr>
<th>Method</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>add_constraint()</code></td>
<td>Add a constraint to the system</td>
</tr>
<tr>
<td><code>add_bounded_variable()</code></td>
<td>Add a bounded control variable</td>
</tr>
<tr>
<td><code>link_constraint_to_control()</code></td>
<td>Link constraint to control for One-Shot solving</td>
</tr>
<tr>
<td><code>unlink_constraint()</code></td>
<td>Remove constraint-control linkage</td>
</tr>
<tr>
<td><code>validate_inverse_control_dof()</code></td>
<td>Validate degrees of freedom</td>
</tr>
<tr>
<td><code>control_variable_state_index()</code></td>
<td>Get state vector index for control variable</td>
</tr>
<tr>
<td><code>full_state_vector_len()</code></td>
<td>Total state length including controls</td>
</tr>
<tr>
<td><code>compute_constraint_residuals()</code></td>
<td>Compute residuals for all constraints</td>
</tr>
<tr>
<td><code>compute_inverse_control_jacobian()</code></td>
<td>Jacobian entries for ∂constraint/∂control</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</section>
<section id="results" class="mb-5">
<div class="card">
<div class="card-body p-4">
<h2 class="card-title mb-4">
<i class="bi bi-graph-up text-success me-2"></i>
Simulation Results
</h2>
<div class="row mb-4">
<div class="col-md-3">
<div class="card bg-primary text-white">
<div class="card-body text-center">
<h6>Initial Superheat</h6>
<h2 class="mb-0">2.3 K</h2>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-success text-white">
<div class="card-body text-center">
<h6>Target Superheat</h6>
<h2 class="mb-0">5.0 K</h2>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-info text-white">
<div class="card-body text-center">
<h6>Final Superheat</h6>
<h2 class="mb-0">5.02 K</h2>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-warning text-dark">
<div class="card-body text-center">
<h6>Iterations</h6>
<h2 class="mb-0">7</h2>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<h5>Superheat Convergence</h5>
<div class="chart-container">
<canvas id="superheatChart"></canvas>
</div>
</div>
<div class="col-md-6">
<h5>Valve Position Evolution</h5>
<div class="chart-container">
<canvas id="valveChart"></canvas>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-md-6">
<h5>DoF Analysis</h5>
<table class="table table-sm">
<tr>
<td>Edge Unknowns (P, h)</td>
<td class="text-end">8</td>
</tr>
<tr>
<td>Control Variables</td>
<td class="text-end">+1</td>
</tr>
<tr class="table-info">
<td><strong>Total Unknowns</strong></td>
<td class="text-end"><strong>9</strong></td>
</tr>
<tr>
<td>Component Equations</td>
<td class="text-end">8</td>
</tr>
<tr>
<td>Constraint Equations</td>
<td class="text-end">+1</td>
</tr>
<tr class="table-info">
<td><strong>Total Equations</strong></td>
<td class="text-end"><strong>9</strong></td>
</tr>
<tr class="table-success">
<td><strong>Balance</strong></td>
<td class="text-end"><strong>✓ Balanced</strong></td>
</tr>
</table>
</div>
<div class="col-md-6">
<h5>Control Variable Details</h5>
<table class="table table-sm">
<tr>
<td>Variable ID</td>
<td><code>valve_position</code></td>
</tr>
<tr>
<td>Initial Value</td>
<td>50%</td>
</tr>
<tr>
<td>Final Value</td>
<td class="text-success"><strong>38%</strong></td>
</tr>
<tr>
<td>Bounds</td>
<td>[10%, 100%]</td>
</tr>
<tr>
<td>Saturated</td>
<td class="text-warning">No</td>
</tr>
<tr>
<td>State Index</td>
<td>8 (after edge states)</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</section>
<script>
// Superheat Convergence Chart
const superheatCtx = document.getElementById('superheatChart').getContext('2d');
new Chart(superheatCtx, {
type: 'line',
data: {
labels: ['0', '1', '2', '3', '4', '5', '6', '7'],
datasets: [{
label: 'Superheat (K)',
data: [2.3, 3.1, 3.8, 4.4, 4.7, 4.9, 5.01, 5.02],
borderColor: '#3498db',
backgroundColor: 'rgba(52, 152, 219, 0.1)',
fill: true,
tension: 0.3
}, {
label: 'Target (K)',
data: [5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0],
borderColor: '#27ae60',
borderDash: [5, 5],
fill: false
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { position: 'bottom' }
},
scales: {
y: {
title: { display: true, text: 'Superheat (K)' },
min: 0,
max: 6
},
x: {
title: { display: true, text: 'Iteration' }
}
}
}
});
// Valve Position Chart
const valveCtx = document.getElementById('valveChart').getContext('2d');
new Chart(valveCtx, {
type: 'line',
data: {
labels: ['0', '1', '2', '3', '4', '5', '6', '7'],
datasets: [{
label: 'Valve Position (%)',
data: [50, 45, 42, 40, 39, 38.5, 38.2, 38.0],
borderColor: '#e74c3c',
backgroundColor: 'rgba(231, 76, 60, 0.1)',
fill: true,
tension: 0.3
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { position: 'bottom' }
},
scales: {
y: {
title: { display: true, text: 'Position (%)' },
min: 30,
max: 55
},
x: {
title: { display: true, text: 'Iteration' }
}
}
}
});
</script>
<footer class="text-center py-4 mt-5">
<div class="container">
<p class="text-muted">
<i class="bi bi-cpu"></i> Entropyk - One-Shot Inverse Control
<br>
<small>Story 5.3: Residual Embedding for Inverse Control</small>
</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</div>
</body>
</html>