fable 3.1.35 → 3.1.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fable.js +39 -21
- package/dist/fable.js.map +1 -1
- package/dist/fable.min.js +1 -1
- package/dist/fable.min.js.map +1 -1
- package/package.json +1 -1
- package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-ExpressionTokenizer-DirectiveMutation.js +67 -12
- package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-FunctionMap.json +4 -0
- package/source/services/Fable-Service-ExpressionParser.js +84 -16
- package/source/services/Fable-Service-Math.js +26 -5
- package/test/ExpressionParser_tests.js +331 -1
- package/test/Math_test.js +20 -12
|
@@ -461,6 +461,68 @@ suite
|
|
|
461
461
|
Expect(parseFloat(tmpResult)).to.be.at.most(13.78);
|
|
462
462
|
|
|
463
463
|
|
|
464
|
+
return fDone();
|
|
465
|
+
}
|
|
466
|
+
);
|
|
467
|
+
test
|
|
468
|
+
(
|
|
469
|
+
'Test map operation',
|
|
470
|
+
(fDone) =>
|
|
471
|
+
{
|
|
472
|
+
let testFable = new libFable();
|
|
473
|
+
let _Parser = testFable.instantiateServiceProviderIfNotExists('ExpressionParser');
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
let tmpManifest = testFable.newManyfest();
|
|
477
|
+
let tmpDataSourceObject = {};
|
|
478
|
+
tmpDataSourceObject.CitiesData = require('./data/Cities.json');
|
|
479
|
+
/* Records look like:
|
|
480
|
+
[
|
|
481
|
+
{
|
|
482
|
+
"city": "New York",
|
|
483
|
+
"growth_from_2000_to_2013": "4.8%",
|
|
484
|
+
"latitude": 40.7127837,
|
|
485
|
+
"longitude": -74.0059413,
|
|
486
|
+
"population": "8405837",
|
|
487
|
+
"rank": "1",
|
|
488
|
+
"state": "New York"
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
"city": "Los Angeles",
|
|
492
|
+
"growth_from_2000_to_2013": "4.8%",
|
|
493
|
+
"latitude": 34.0522342,
|
|
494
|
+
"longitude": -118.2436849,
|
|
495
|
+
"population": "3884307",
|
|
496
|
+
"rank": "2",
|
|
497
|
+
"state": "California"
|
|
498
|
+
},
|
|
499
|
+
*/
|
|
500
|
+
|
|
501
|
+
tmpDataSourceObject.MapTest = {};
|
|
502
|
+
tmpDataSourceObject.MapTest.Values = [ 1, 2, 3, 4, 5 ];
|
|
503
|
+
|
|
504
|
+
let tmpDataDestinationObject = {};
|
|
505
|
+
let tmpParserResultsObject = {};
|
|
506
|
+
|
|
507
|
+
let tmpResult = _Parser.solve('SimpleMapResult = MAP VAR x FROM MapTest.Values : x + 100', tmpDataSourceObject, tmpParserResultsObject, tmpManifest, tmpDataDestinationObject);
|
|
508
|
+
|
|
509
|
+
// Should expect 101 -> 105
|
|
510
|
+
Expect(tmpDataDestinationObject.SimpleMapResult.length).to.equal(5);
|
|
511
|
+
Expect(tmpDataDestinationObject.SimpleMapResult[0]).to.equal("101");
|
|
512
|
+
Expect(tmpDataDestinationObject.SimpleMapResult[1]).to.equal("102");
|
|
513
|
+
Expect(tmpDataDestinationObject.SimpleMapResult[2]).to.equal("103");
|
|
514
|
+
Expect(tmpDataDestinationObject.SimpleMapResult[3]).to.equal("104");
|
|
515
|
+
Expect(tmpDataDestinationObject.SimpleMapResult[4]).to.equal("105");
|
|
516
|
+
|
|
517
|
+
let tmpComplexMapResult = _Parser.solve('ComplexMapResult = MAP VAR cityRecord FROM CitiesData VAR x FROM MapTest.Values : cityRecord.population + (x * 1000000000000000)', tmpDataSourceObject, tmpParserResultsObject, tmpManifest, tmpDataDestinationObject);
|
|
518
|
+
|
|
519
|
+
Expect(tmpDataDestinationObject.ComplexMapResult.length).to.equal(1000);
|
|
520
|
+
Expect(tmpDataDestinationObject.ComplexMapResult[0]).to.equal("1000000008405837");
|
|
521
|
+
Expect(tmpDataDestinationObject.ComplexMapResult[4]).to.equal("5000000001553165");
|
|
522
|
+
// We ran out of values 1-5 so now it's just population
|
|
523
|
+
Expect(tmpDataDestinationObject.ComplexMapResult[10]).to.equal("885400");
|
|
524
|
+
Expect(tmpDataDestinationObject.ComplexMapResult[400]).to.equal("81050");
|
|
525
|
+
|
|
464
526
|
return fDone();
|
|
465
527
|
}
|
|
466
528
|
);
|
|
@@ -519,8 +581,8 @@ suite
|
|
|
519
581
|
{
|
|
520
582
|
let testFable = new libFable();
|
|
521
583
|
let _Parser = testFable.instantiateServiceProviderIfNotExists('ExpressionParser');
|
|
522
|
-
|
|
523
584
|
let tmpManifest = testFable.newManyfest();
|
|
585
|
+
|
|
524
586
|
let tmpDataSourceObject = {};
|
|
525
587
|
let tmpDataDestinationObject = {};
|
|
526
588
|
let tmpParserResultsObject = {};
|
|
@@ -532,6 +594,46 @@ suite
|
|
|
532
594
|
Expect(tmpResult).to.exist;
|
|
533
595
|
Expect(tmpResult.Samples.length).to.equal(1000);
|
|
534
596
|
|
|
597
|
+
// Rosenbrock function test (experimenting with non-deterministic test cases)
|
|
598
|
+
/* Interesting values:
|
|
599
|
+
|
|
600
|
+
| Purpose | (x) | (y) | (z) | Notes |
|
|
601
|
+
| ----------------------------------------- | ----------------- | ----------------- | ----------------- | ------------------------------------------------------------------------------- |
|
|
602
|
+
| **Exploration (broad view)** | ([-3, 3]) | ([-1, 5]) | ([-1, 5]) | Shows how the function grows large and steep outside the valley. |
|
|
603
|
+
| **Focused optimization testing** | ([0, 2]) | ([0, 2]) | ([0, 2]) | Focuses on region around the minimum — ideal for Monte Carlo convergence plots. |
|
|
604
|
+
| **High-resolution contour visualization** | ([-1.5, 1.5]) | ([0, 2]) | ([0, 2]) | Best for plotting slices and seeing the curvature of the valley. |
|
|
605
|
+
| **Stress testing** | ([-2.048, 2.048]) | ([-2.048, 2.048]) | ([-2.048, 2.048]) | Tests the function's behavior over a wider range, useful for robustness checks. |
|
|
606
|
+
*/
|
|
607
|
+
let tmpRosenbrockDataSourceObject = {};
|
|
608
|
+
let tmpRosenbrockDataDestinationObject = {};
|
|
609
|
+
let tmpRosenbrockParserResultsObject = {};
|
|
610
|
+
let tmpRosenbrockResult = _Parser.solve('RosenbrockResult = MONTECARLO SAMPLECOUNT 5000 VAR x PT x -3 PT x 3 VAR y PT y -1 PT y 5 VAR z PT z -1 PT z 5 : (1 - x)^2 + 100 * (y - x^2)^2 + (z - y)^2', tmpRosenbrockDataSourceObject, tmpRosenbrockParserResultsObject, tmpManifest, tmpRosenbrockDataDestinationObject);
|
|
611
|
+
|
|
612
|
+
Expect(tmpRosenbrockResult).to.exist;
|
|
613
|
+
Expect(tmpRosenbrockResult.Samples.length).to.equal(5000);
|
|
614
|
+
|
|
615
|
+
// Build a histogram of the results to see how many are near zero
|
|
616
|
+
let tmpHistogram = [];
|
|
617
|
+
for (let sampleIndex = 0; sampleIndex < tmpRosenbrockResult.Samples.length; sampleIndex++)
|
|
618
|
+
{
|
|
619
|
+
let tmpSample = tmpRosenbrockResult.Samples[sampleIndex];
|
|
620
|
+
let tmpValue = testFable.Math.roundPrecise(tmpSample, 0);
|
|
621
|
+
if (!tmpHistogram[tmpValue])
|
|
622
|
+
tmpHistogram[tmpValue] = 0;
|
|
623
|
+
tmpHistogram[tmpValue] = tmpHistogram[tmpValue] + 1;
|
|
624
|
+
// Log the output sample for visual inspection
|
|
625
|
+
testFable.log.info(`Rosenbrock Sample ${sampleIndex}: Value: ${tmpSample}, Rounded Value: ${tmpValue} --> Histogram Count: ${tmpHistogram[tmpValue]}`);
|
|
626
|
+
}
|
|
627
|
+
// Output the histogram for visual inspection
|
|
628
|
+
//testFable.ExpressionParser.Messaging.logMessage("Rosenbrock Histogram:");
|
|
629
|
+
let tmpHistogramKeys = Object.keys(tmpHistogram);
|
|
630
|
+
tmpHistogramKeys.sort((a, b) => parseFloat(a) - parseFloat(b));
|
|
631
|
+
for (let i = 0; i < tmpHistogramKeys.length; i++)
|
|
632
|
+
{
|
|
633
|
+
let key = tmpHistogramKeys[i];
|
|
634
|
+
testFable.log.info(`Value: ${key}, Count: ${tmpHistogram[key]}`);
|
|
635
|
+
}
|
|
636
|
+
|
|
535
637
|
return fDone();
|
|
536
638
|
}
|
|
537
639
|
);
|
|
@@ -797,6 +899,234 @@ suite
|
|
|
797
899
|
testFable.log.info('Series From Coefficients Result:', testFable.AppData.SeriesFromCoefficients);
|
|
798
900
|
_Parser.solve('IntegratedSeries = SUM(FLATTEN(AppData.SeriesFromCoefficients))', testFable, testFable.AppData, false, testFable.AppData);
|
|
799
901
|
testFable.log.info('Integrated Series Result:', testFable.AppData.IntegratedSeries);
|
|
902
|
+
|
|
903
|
+
const tmpRawData =
|
|
904
|
+
{
|
|
905
|
+
"StandardSelector": "English",
|
|
906
|
+
"MaxDryDensityTable": [
|
|
907
|
+
{
|
|
908
|
+
"MaxDryDensityTable": {
|
|
909
|
+
"f": "4.19",
|
|
910
|
+
"g": "125.7",
|
|
911
|
+
"j": "0.19",
|
|
912
|
+
"l": "109.1",
|
|
913
|
+
"NTest": "",
|
|
914
|
+
"a": "",
|
|
915
|
+
"b": "",
|
|
916
|
+
"d": "13.51",
|
|
917
|
+
"e": "9.32",
|
|
918
|
+
"h": "1.44",
|
|
919
|
+
"i": "1.25",
|
|
920
|
+
"k": "15.2"
|
|
921
|
+
},
|
|
922
|
+
"MaxDryDensityTablec": "10.00"
|
|
923
|
+
},
|
|
924
|
+
{
|
|
925
|
+
"MaxDryDensityTable": {
|
|
926
|
+
"f": "4.01",
|
|
927
|
+
"g": "120.3",
|
|
928
|
+
"j": "0.16",
|
|
929
|
+
"l": "106.5",
|
|
930
|
+
"NTest": "",
|
|
931
|
+
"a": "",
|
|
932
|
+
"b": "",
|
|
933
|
+
"d": "13.34",
|
|
934
|
+
"e": "9.33",
|
|
935
|
+
"h": "1.39",
|
|
936
|
+
"i": "1.23",
|
|
937
|
+
"k": "13"
|
|
938
|
+
},
|
|
939
|
+
"MaxDryDensityTablec": "11.00"
|
|
940
|
+
},
|
|
941
|
+
{
|
|
942
|
+
"MaxDryDensityTable": {
|
|
943
|
+
"f": "4.19",
|
|
944
|
+
"g": "125.7",
|
|
945
|
+
"j": "0.22",
|
|
946
|
+
"l": "106",
|
|
947
|
+
"NTest": "",
|
|
948
|
+
"a": "",
|
|
949
|
+
"b": "",
|
|
950
|
+
"d": "13.51",
|
|
951
|
+
"e": "9.32",
|
|
952
|
+
"h": "1.40",
|
|
953
|
+
"i": "1.18",
|
|
954
|
+
"k": "18.6"
|
|
955
|
+
},
|
|
956
|
+
"MaxDryDensityTablec": "12.00"
|
|
957
|
+
}
|
|
958
|
+
],
|
|
959
|
+
"NuclearTable": [
|
|
960
|
+
{
|
|
961
|
+
"NuclearTable": {},
|
|
962
|
+
"NDD": "0",
|
|
963
|
+
"ADD": "0",
|
|
964
|
+
"NuclearPercentPR": "0"
|
|
965
|
+
}
|
|
966
|
+
],
|
|
967
|
+
"Pulverization": [
|
|
968
|
+
{
|
|
969
|
+
"PTestNo": "1"
|
|
970
|
+
}
|
|
971
|
+
],
|
|
972
|
+
"FMC": [
|
|
973
|
+
{
|
|
974
|
+
"MassOfWater": "0"
|
|
975
|
+
}
|
|
976
|
+
],
|
|
977
|
+
"MetaTemplate": {},
|
|
978
|
+
"Header": {},
|
|
979
|
+
"SM": {
|
|
980
|
+
"SF": "0",
|
|
981
|
+
"SI": "0",
|
|
982
|
+
"SJ": "0"
|
|
983
|
+
},
|
|
984
|
+
"NM": {},
|
|
985
|
+
"Chart": {
|
|
986
|
+
"Slope": "1.18181818181818181818",
|
|
987
|
+
"Intercept": "91.136363636363636363664",
|
|
988
|
+
"MCZeroAtDD": "21.830887491264849755",
|
|
989
|
+
"ShiftToParallel": "3.230887491264849755",
|
|
990
|
+
"WetSideY2": "0.84615384615384615385",
|
|
991
|
+
"WetSideY1": "-36.84746008708272859272",
|
|
992
|
+
"DomainBegin": "13",
|
|
993
|
+
"DomainEnd": "18.6",
|
|
994
|
+
"WetSideY0": "-6240",
|
|
995
|
+
"OptimalMoistureContent": "16.27122843513086489567",
|
|
996
|
+
"DryCount": 16,
|
|
997
|
+
"WetCount": "16",
|
|
998
|
+
"TotalCount": "32",
|
|
999
|
+
"StartPlot": "12",
|
|
1000
|
+
"XValues": [
|
|
1001
|
+
"13.2",
|
|
1002
|
+
"13.4",
|
|
1003
|
+
"13.6",
|
|
1004
|
+
"13.8",
|
|
1005
|
+
"14",
|
|
1006
|
+
"14.2",
|
|
1007
|
+
"14.4",
|
|
1008
|
+
"14.6",
|
|
1009
|
+
"14.8",
|
|
1010
|
+
"15",
|
|
1011
|
+
"15.2",
|
|
1012
|
+
"15.4",
|
|
1013
|
+
"15.6",
|
|
1014
|
+
"15.8",
|
|
1015
|
+
"16",
|
|
1016
|
+
"16.2",
|
|
1017
|
+
"16.4",
|
|
1018
|
+
"16.6",
|
|
1019
|
+
"16.8",
|
|
1020
|
+
"17",
|
|
1021
|
+
"17.2",
|
|
1022
|
+
"17.4",
|
|
1023
|
+
"17.6",
|
|
1024
|
+
"17.8",
|
|
1025
|
+
"18",
|
|
1026
|
+
"18.2",
|
|
1027
|
+
"18.4",
|
|
1028
|
+
"18.6",
|
|
1029
|
+
"18.8",
|
|
1030
|
+
"19",
|
|
1031
|
+
"19.2",
|
|
1032
|
+
"19.4",
|
|
1033
|
+
],
|
|
1034
|
+
"PrimaryRoot": "110.3659972415182948767",
|
|
1035
|
+
"WetCountIntermediate": "43",
|
|
1036
|
+
"ValueLimit": "28"
|
|
1037
|
+
},
|
|
1038
|
+
"Result": "",
|
|
1039
|
+
"FamilyOfCurvesZone": "0.99",
|
|
1040
|
+
"MaxDryDensityEnglish": "0",
|
|
1041
|
+
"MaxDryDensityMetric": "0",
|
|
1042
|
+
"DryX": "15.2",
|
|
1043
|
+
"DryY": "109.1",
|
|
1044
|
+
"AsIsX": "13",
|
|
1045
|
+
"AsIsY": "106.5",
|
|
1046
|
+
"WetX": "18.6",
|
|
1047
|
+
"WetY": "106",
|
|
1048
|
+
"AverageMaxDryDensity": "11",
|
|
1049
|
+
"OptimumMoistureOfTotalMaterial": "0.1",
|
|
1050
|
+
"om": "0.0",
|
|
1051
|
+
"pr": "0.0"
|
|
1052
|
+
};
|
|
1053
|
+
|
|
1054
|
+
const tmpBaseMoistures = tmpRawData.Chart.XValues;
|
|
1055
|
+
//TODO: compute this form above; 3 stages; dry, wet, combined
|
|
1056
|
+
const tmpCombinedDensities = [ '106.7363636','106.9727273','107.2090909','107.4454545','107.6818182','107.9181818',
|
|
1057
|
+
'108.1545455','108.3909091','108.6272727','108.8636364','109.1','109.3363636','109.5727273','109.8090909','110.0454545',
|
|
1058
|
+
'110.2818182','110.1152028','109.7279363','109.3433842','108.9615182','108.5823101','108.2057322','107.8317574',
|
|
1059
|
+
'107.4603587','107.0915096','106.7251839','106.3613559','106','105.6410912','105.2846046','104.9305159','104.5788009'
|
|
1060
|
+
];
|
|
1061
|
+
const tmpMatrix = [];
|
|
1062
|
+
for (let i = 1; i <= 10; ++i)
|
|
1063
|
+
{
|
|
1064
|
+
const tmpPowArray = [];
|
|
1065
|
+
for (let j = 0; j < tmpBaseMoistures.length; ++j)
|
|
1066
|
+
{
|
|
1067
|
+
tmpPowArray.push(testFable.Math.powerPrecise(tmpBaseMoistures[j], i));
|
|
1068
|
+
}
|
|
1069
|
+
tmpMatrix.push(tmpPowArray);
|
|
1070
|
+
}
|
|
1071
|
+
testFable.AppData.FitToDensities = tmpCombinedDensities;
|
|
1072
|
+
testFable.AppData.MoistureMatrix = tmpMatrix;
|
|
1073
|
+
testFable.log.info('Fit To Densities:', testFable.AppData.FitToDensities);
|
|
1074
|
+
testFable.log.info('Moisture Matrix:', testFable.AppData.MoistureMatrix);
|
|
1075
|
+
_Parser.solve('LinearRegressionHand = LINEST(AppData.MoistureMatrix, AppData.FitToDensities)', testFable, testFable.AppData, false, testFable.AppData);
|
|
1076
|
+
testFable.log.info('Density Regression Coefficients:', testFable.AppData.LinearRegressionHand);
|
|
1077
|
+
|
|
1078
|
+
const tmpSolverInstructions =
|
|
1079
|
+
[
|
|
1080
|
+
'ChartDomainBegin = MaxDryDensityTable[0].MaxDryDensityTable.k - 2',
|
|
1081
|
+
'ChartDomainEnd = ChartDomainBegin + (Chart.TotalCount - 1) * 0.2',
|
|
1082
|
+
'XValues = SERIES FROM ChartDomainBegin TO ChartDomainEnd STEP 0.2 : n + 0',
|
|
1083
|
+
'DryCount = MATCH(Chart.OptimalMoistureContent, XValues)',
|
|
1084
|
+
'WetCountIntermediate = 60 - DryCount',
|
|
1085
|
+
'WetCount = IF(DryCount, "<=", 30, DryCount, WetCountIntermediate)',
|
|
1086
|
+
'TotalCount = DryCount + WetCount',
|
|
1087
|
+
'StartPlot = DryCount - 5',
|
|
1088
|
+
'ChartValueLimit = Chart.XValues.length - 1',
|
|
1089
|
+
'DryValues = MAP VAR x FROM Chart.XValues : x * Chart.Slope + Chart.Intercept',
|
|
1090
|
+
'WetValues = MAP VAR x FROM Chart.XValues : 6240 / (x + 100 / 2.7 + Chart.ShiftToParallel)',
|
|
1091
|
+
'CombinedValues = MAP VAR dry FROM DryValues VAR wet FROM WetValues VAR x from XValues : IF(x, "LTE", Chart.OptimalMoistureContent, dry, wet)',
|
|
1092
|
+
'FilteredXValues = MAP VAR x FROM XValues : IF(ABS(Chart.OptimalMoistureContent - x), "LT", 1, x, 0)',
|
|
1093
|
+
'XValueMatrix = createarrayfromabsolutevalues(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)', // Create Placeholders
|
|
1094
|
+
'XValueMatrix[0] = MAP VAR x FROM XValues : x + 0',
|
|
1095
|
+
'XValueMatrix[1] = MAP VAR x FROM XValues : x^2',
|
|
1096
|
+
'XValueMatrix[2] = MAP VAR x FROM XValues : x^3',
|
|
1097
|
+
'XValueMatrix[3] = MAP VAR x FROM XValues : x^4',
|
|
1098
|
+
'XValueMatrix[4] = MAP VAR x FROM XValues : x^5',
|
|
1099
|
+
'XValueMatrix[5] = MAP VAR x FROM XValues : x^6',
|
|
1100
|
+
'XValueMatrix[6] = MAP VAR x FROM XValues : x^7',
|
|
1101
|
+
'XValueMatrix[7] = MAP VAR x FROM XValues : x^8',
|
|
1102
|
+
'XValueMatrix[8] = MAP VAR x FROM XValues : x^9',
|
|
1103
|
+
'XValueMatrix[9] = MAP VAR x FROM XValues : x^10',
|
|
1104
|
+
'LinearRegression = LINEST(XValueMatrix, CombinedValues)',
|
|
1105
|
+
'FilteredXValueVectors = MatrixTranspose(XValueMatrix)',
|
|
1106
|
+
'FittedDensities = MAP VAR x FROM XValues VAR vector FROM FilteredXValueVectors : PREDICT(LinearRegression, vector)',
|
|
1107
|
+
'FilteredDensities = MAP VAR x FROM FilteredXValues VAR prediction FROM FittedDensities : IF(x, "==", 0, 0, prediction)',
|
|
1108
|
+
];
|
|
1109
|
+
const tmpResultsObject = {};
|
|
1110
|
+
for (const tmpInstruction of tmpSolverInstructions)
|
|
1111
|
+
{
|
|
1112
|
+
_Parser.solve(tmpInstruction, tmpRawData, tmpResultsObject, false, tmpRawData);
|
|
1113
|
+
testFable.log.info(`After instruction: ${tmpInstruction}`, tmpRawData[tmpInstruction.split('=')[0].trim()]);
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
Expect(tmpRawData.FilteredDensities[10]).to.equal('0');
|
|
1117
|
+
Expect(Number(tmpRawData.FilteredDensities[11])).to.be.closeTo(109.3, 0.1);
|
|
1118
|
+
Expect(Number(tmpRawData.FilteredDensities[20])).to.be.closeTo(108.6, 0.1);
|
|
1119
|
+
Expect(tmpRawData.FilteredDensities[21]).to.equal('0');
|
|
1120
|
+
|
|
1121
|
+
/*
|
|
1122
|
+
testFable.log.info('linest payload (hand):', { MoistureMatrix: testFable.AppData.MoistureMatrix, FitToDensities: testFable.AppData.FitToDensities });
|
|
1123
|
+
testFable.log.info('linest payload (solver):', { XValueMatrix: tmpRawData.XValueMatrix, CombinedValues: tmpRawData.CombinedValues });
|
|
1124
|
+
|
|
1125
|
+
testFable.log.info('coefficients (hand):', testFable.AppData.LinearRegressionHand);
|
|
1126
|
+
testFable.log.info('coefficients (solver):', tmpRawData.LinearRegression);
|
|
1127
|
+
|
|
1128
|
+
testFable.log.info('filtered densities (solver):', tmpRawData.FilteredDensities);
|
|
1129
|
+
*/
|
|
800
1130
|
}
|
|
801
1131
|
);
|
|
802
1132
|
}
|
package/test/Math_test.js
CHANGED
|
@@ -486,25 +486,33 @@ suite
|
|
|
486
486
|
testFable.log.info('Prediction for [2,1]:', predict(coeffs_1, [2.5]));
|
|
487
487
|
|
|
488
488
|
// Example: predict y from x1 and x2
|
|
489
|
+
/* Example from: https://mathforcollege.com/nm/mws/gen/06reg/mws_gen_reg_spe_multivariate.pdf
|
|
490
|
+
144 18 52
|
|
491
|
+
142 24 40
|
|
492
|
+
124 12 40
|
|
493
|
+
64 30 48
|
|
494
|
+
96 30 32
|
|
495
|
+
92 22 16
|
|
496
|
+
*/
|
|
489
497
|
const X = [
|
|
490
|
-
[
|
|
491
|
-
[
|
|
492
|
-
[3, 1],
|
|
493
|
-
[4, 3]
|
|
498
|
+
[ 18, 24, 12, 30, 30, 22 ],
|
|
499
|
+
[ 52, 40, 40, 48, 32, 16 ],
|
|
494
500
|
];
|
|
495
501
|
|
|
496
|
-
const y = [
|
|
502
|
+
const y = [ 144, 142, 124, 64, 96, 92 ];
|
|
497
503
|
|
|
498
504
|
const coeffs = testFable.Math.leastSquares(X, y);
|
|
499
505
|
testFable.log.info('Coefficients:', coeffs);
|
|
506
|
+
Expect(coeffs.length).to.equal(3); // intercept + 2 variables
|
|
507
|
+
Expect(Number(coeffs[0])).to.be.closeTo(150.166, 0.01);
|
|
508
|
+
Expect(Number(coeffs[1])).to.be.closeTo(-2.731, 0.01);
|
|
509
|
+
Expect(Number(coeffs[2])).to.be.closeTo(0.581, 0.01);
|
|
500
510
|
|
|
501
|
-
testFable.log.info('Prediction for [
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
Expect(Number(predict(coeffs, [4, 3]))).to.be.closeTo(5, 0.25);
|
|
507
|
-
testFable.log.info('Prediction for [2,1]:', predict(coeffs, [2, 1]));
|
|
511
|
+
testFable.log.info('Prediction for [18,52] (training value is 144):', predict(coeffs, [18, 52]));
|
|
512
|
+
Expect(Number(predict(coeffs, [18, 52]))).to.be.closeTo(144, 15);
|
|
513
|
+
|
|
514
|
+
testFable.log.info('Prediction for [22,16] (training value is 92):', predict(coeffs, [22, 16]));
|
|
515
|
+
Expect(Number(predict(coeffs, [22, 16]))).to.be.closeTo(92, 10);
|
|
508
516
|
}
|
|
509
517
|
);
|
|
510
518
|
|