You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
4.2 KiB
157 lines
4.2 KiB
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:ml_algo/ml_algo.dart';
|
|
import 'package:ml_dataframe/ml_dataframe.dart';
|
|
|
|
void main() {
|
|
test('LinearRegressor basic sanity check', () {
|
|
// Simple: y = 2x + 100
|
|
final data = DataFrame(
|
|
[
|
|
[1.0, 102.0],
|
|
[2.0, 104.0],
|
|
[3.0, 106.0],
|
|
[4.0, 108.0],
|
|
[5.0, 110.0],
|
|
[10.0, 120.0],
|
|
[20.0, 140.0],
|
|
[50.0, 200.0],
|
|
[0.0, 100.0],
|
|
[100.0, 300.0],
|
|
],
|
|
headerExists: false,
|
|
header: ['x', 'y'],
|
|
);
|
|
|
|
debugPrint('Training data columns: ${data.header}');
|
|
debugPrint('Training data rows: ${data.rows.length}');
|
|
|
|
final model = LinearRegressor(data, 'y');
|
|
|
|
final testDf = DataFrame(
|
|
[
|
|
[25.0],
|
|
],
|
|
headerExists: false,
|
|
header: ['x'],
|
|
);
|
|
|
|
final prediction = model.predict(testDf);
|
|
final value = prediction.rows.first.first;
|
|
debugPrint('Predict x=25 → y=$value (expected ~150)');
|
|
expect((value as num).toDouble(), closeTo(150, 5));
|
|
});
|
|
|
|
test('LinearRegressor multi-feature with constant column produces zeros', () {
|
|
// isFlood=0 for all rows → zero-variance column → singular matrix
|
|
final data = DataFrame(
|
|
[
|
|
[0.0, 50.0, 14.0, 0.0, 1900.0],
|
|
[0.0, 80.0, 14.0, 0.0, 2200.0],
|
|
[2.0, 50.0, 14.0, 0.0, 5000.0],
|
|
[4.0, 50.0, 14.0, 0.0, 9500.0],
|
|
],
|
|
headerExists: false,
|
|
header: [
|
|
'pathLength',
|
|
'messageBytes',
|
|
'hourOfDay',
|
|
'isFlood',
|
|
'deliveryMs',
|
|
],
|
|
);
|
|
|
|
final model = LinearRegressor(data, 'deliveryMs');
|
|
final testDf = DataFrame(
|
|
[
|
|
[2.0, 50.0, 14.0, 0.0],
|
|
],
|
|
headerExists: false,
|
|
header: ['pathLength', 'messageBytes', 'hourOfDay', 'isFlood'],
|
|
);
|
|
final pred = model.predict(testDf).rows.first.first;
|
|
debugPrint(
|
|
'With constant isFlood column: hops=2 → ${(pred as num).round()}ms (likely 0)',
|
|
);
|
|
});
|
|
|
|
test('LinearRegressor 2-feature works correctly', () {
|
|
// Just pathLength + messageBytes → deliveryMs
|
|
final data = DataFrame(
|
|
[
|
|
[0.0, 50.0, 1900.0],
|
|
[0.0, 80.0, 2200.0],
|
|
[2.0, 50.0, 5000.0],
|
|
[2.0, 80.0, 5500.0],
|
|
[4.0, 50.0, 9500.0],
|
|
[4.0, 80.0, 10000.0],
|
|
[0.0, 30.0, 1800.0],
|
|
[2.0, 30.0, 4800.0],
|
|
[4.0, 30.0, 9000.0],
|
|
[0.0, 60.0, 2000.0],
|
|
],
|
|
headerExists: false,
|
|
header: ['pathLength', 'messageBytes', 'deliveryMs'],
|
|
);
|
|
|
|
final model = LinearRegressor(data, 'deliveryMs');
|
|
|
|
for (final hops in [0.0, 2.0, 4.0]) {
|
|
final testDf = DataFrame(
|
|
[
|
|
[hops, 50.0],
|
|
],
|
|
headerExists: false,
|
|
header: ['pathLength', 'messageBytes'],
|
|
);
|
|
final pred = model.predict(testDf).rows.first.first;
|
|
debugPrint('2-feature: hops=$hops → ${(pred as num).round()}ms');
|
|
}
|
|
});
|
|
|
|
test('LinearRegressor multi-feature with variance in all columns', () {
|
|
// Mix flood and direct so isFlood has variance
|
|
final data = DataFrame(
|
|
[
|
|
[0.0, 50.0, 14.0, 0.0, 1900.0],
|
|
[0.0, 80.0, 10.0, 0.0, 2200.0],
|
|
[2.0, 50.0, 16.0, 0.0, 5000.0],
|
|
[2.0, 80.0, 20.0, 0.0, 5500.0],
|
|
[4.0, 50.0, 8.0, 0.0, 9500.0],
|
|
[4.0, 80.0, 12.0, 0.0, 10000.0],
|
|
[-1.0, 40.0, 14.0, 1.0, 5000.0],
|
|
[-1.0, 60.0, 18.0, 1.0, 6500.0],
|
|
[-1.0, 30.0, 10.0, 1.0, 4000.0],
|
|
[-1.0, 80.0, 22.0, 1.0, 7000.0],
|
|
],
|
|
headerExists: false,
|
|
header: [
|
|
'pathLength',
|
|
'messageBytes',
|
|
'hourOfDay',
|
|
'isFlood',
|
|
'deliveryMs',
|
|
],
|
|
);
|
|
|
|
final model = LinearRegressor(data, 'deliveryMs');
|
|
|
|
for (final tc in [
|
|
[0.0, 50.0, 14.0, 0.0],
|
|
[2.0, 50.0, 14.0, 0.0],
|
|
[4.0, 50.0, 14.0, 0.0],
|
|
[-1.0, 50.0, 14.0, 1.0],
|
|
]) {
|
|
final testDf = DataFrame(
|
|
[tc],
|
|
headerExists: false,
|
|
header: ['pathLength', 'messageBytes', 'hourOfDay', 'isFlood'],
|
|
);
|
|
final pred = model.predict(testDf).rows.first.first;
|
|
debugPrint(
|
|
'4-feature: hops=${tc[0]} flood=${tc[3]} → ${(pred as num).round()}ms',
|
|
);
|
|
}
|
|
});
|
|
}
|