vital_solver 0.11.3
vital_solver: ^0.11.3 copied to clipboard
Pure-Dart nutritional solver. Coordinate-descent optimizer with quality rules (V22b sweet-batch cascade, fruit/fat/carb bounds, whey rescue) and pre-solve report aggregation. No Firebase, no FlutterFl [...]
example/vital_solver_example.dart
// example/vital_solver_example.dart
//
// Minimal end-to-end demo of the public API. Run with:
//
// dart run example/vital_solver_example.dart
//
// The example builds a simple meal (chicken + rice + olive oil), runs the
// full pipeline (quality rules + optimizer + post-solve corrections), and
// then runs the pre-solve report builder so you can see both shapes.
// ignore_for_file: avoid_print
// `print` is conventional for example files. Production code uses logging.
import 'package:vital_solver/vital_solver.dart';
void main() {
// Each row is a legacy-shape `Map<String, dynamic>` matching what the
// FlutterFlow shim builds from Firestore documents. The package never
// touches Firestore — it just consumes maps.
final rows = <Map<String, dynamic>>[
_row(id: 'chicken', name: 'poulet', p: 23, c: 0, l: 3, role: 'protein_main'),
_row(
id: 'rice',
name: 'riz',
p: 7,
c: 28,
l: 0.5,
fiber: 0.4,
role: 'carb_main',
),
_row(
id: 'oil',
name: 'huile olive',
p: 0,
c: 0,
l: 100,
role: 'fat',
),
];
final targets = <String, dynamic>{
'P': 30.0,
'C': 40.0,
'L': 12.0,
'FiMin': 5.0,
};
final options = <String, dynamic>{};
// ────────────────────────────────────────────────────────────────────
// 1) Run the full solve pipeline.
// ────────────────────────────────────────────────────────────────────
final pipelineResult = solvePipeline(
rows: rows,
targets: targets,
options: options,
);
final solver = pipelineResult.solverOutput;
final ok = solver['constraintsOk'] == true;
final totals = solver['totals'] as Map;
final gramsById = solver['gramsById'] as Map;
print('--- Pipeline result ---');
print(' constraintsOk: $ok');
print(' totals: $totals');
print(' gramsById: $gramsById');
// ────────────────────────────────────────────────────────────────────
// 2) Build the pre-solve report (warnings / blocking / suggestions).
// ────────────────────────────────────────────────────────────────────
final report = buildPreSolveReport(
rows: rows,
targets: targets,
options: options,
);
print('\n--- Pre-solve report ---');
print(' okToCreate: ${report.okToCreate}');
print(' status: ${report.status}');
print(' title: ${report.title}');
print(' message: ${report.message}');
print(' blockingReasons: ${report.blockingReasons.length}');
print(' warnings: ${report.warnings.length}');
print(' suggestions: ${report.suggestions.length}');
}
Map<String, dynamic> _row({
required String id,
required String name,
required double p,
required double c,
required double l,
double fiber = 0.0,
double sugars = 0.0,
double grams = 100.0,
String? role,
}) {
return <String, dynamic>{
'id': id,
'rowId': id,
'name': name,
'proteinPer100g': p,
'carbsPer100g': c,
'totalCarbsPer100g': c,
'fatPer100g': l,
'fiberPer100g': fiber,
'sugarsPer100g': sugars,
'grams': grams,
'defaultG': grams,
'minG': 0.0,
'maxG': 500.0,
if (role != null) 'resolvedMealUiRole': role,
'role': 'variable',
};
}