linny-r 2.0.8 → 2.0.10
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/README.md +3 -40
- package/package.json +6 -2
- package/server.js +19 -157
- package/static/images/solve-not-same-changed.png +0 -0
- package/static/images/solve-not-same-not-changed.png +0 -0
- package/static/images/solve-same-changed.png +0 -0
- package/static/images/solve-same-not-changed.png +0 -0
- package/static/index.html +137 -20
- package/static/linny-r.css +260 -23
- package/static/scripts/iro.min.js +7 -7
- package/static/scripts/linny-r-ctrl.js +126 -85
- package/static/scripts/linny-r-gui-actor-manager.js +23 -33
- package/static/scripts/linny-r-gui-chart-manager.js +56 -53
- package/static/scripts/linny-r-gui-constraint-editor.js +10 -14
- package/static/scripts/linny-r-gui-controller.js +644 -260
- package/static/scripts/linny-r-gui-dataset-manager.js +64 -66
- package/static/scripts/linny-r-gui-documentation-manager.js +11 -17
- package/static/scripts/linny-r-gui-equation-manager.js +22 -22
- package/static/scripts/linny-r-gui-experiment-manager.js +124 -141
- package/static/scripts/linny-r-gui-expression-editor.js +26 -12
- package/static/scripts/linny-r-gui-file-manager.js +42 -48
- package/static/scripts/linny-r-gui-finder.js +294 -55
- package/static/scripts/linny-r-gui-model-autosaver.js +2 -4
- package/static/scripts/linny-r-gui-monitor.js +35 -41
- package/static/scripts/linny-r-gui-paper.js +42 -70
- package/static/scripts/linny-r-gui-power-grid-manager.js +31 -34
- package/static/scripts/linny-r-gui-receiver.js +1 -2
- package/static/scripts/linny-r-gui-repository-browser.js +44 -46
- package/static/scripts/linny-r-gui-scale-unit-manager.js +32 -32
- package/static/scripts/linny-r-gui-sensitivity-analysis.js +61 -67
- package/static/scripts/linny-r-gui-undo-redo.js +94 -95
- package/static/scripts/linny-r-milp.js +20 -24
- package/static/scripts/linny-r-model.js +1932 -2274
- package/static/scripts/linny-r-utils.js +27 -27
- package/static/scripts/linny-r-vm.js +900 -998
- package/static/show-png.html +0 -113
@@ -123,9 +123,7 @@ class GUIChartManager extends ChartManager {
|
|
123
123
|
document.getElementById('chart-copy-table-btn').addEventListener(
|
124
124
|
'click', () => CHART_MANAGER.copyTable());
|
125
125
|
document.getElementById('chart-save-btn').addEventListener(
|
126
|
-
'click', () => CHART_MANAGER.downloadChart());
|
127
|
-
document.getElementById('chart-render-btn').addEventListener(
|
128
|
-
'click', () => CHART_MANAGER.renderChartAsPNG());
|
126
|
+
'click', () => CHART_MANAGER.downloadChart(event.shiftKey));
|
129
127
|
document.getElementById('chart-widen-btn').addEventListener(
|
130
128
|
'click', () => CHART_MANAGER.stretchChart(1));
|
131
129
|
document.getElementById('chart-narrow-btn').addEventListener(
|
@@ -333,7 +331,7 @@ class GUIChartManager extends ChartManager {
|
|
333
331
|
}
|
334
332
|
|
335
333
|
updateSelector() {
|
336
|
-
//
|
334
|
+
// Add one option to the selector for each chart defined for the model.
|
337
335
|
// NOTE: Add the "new chart" option if it is not in the list.
|
338
336
|
MODEL.addChart(this.new_chart_title);
|
339
337
|
if(this.chart_index < 0) this.chart_index = 0;
|
@@ -356,7 +354,7 @@ class GUIChartManager extends ChartManager {
|
|
356
354
|
}
|
357
355
|
|
358
356
|
updateDialog() {
|
359
|
-
//
|
357
|
+
// Refreshe all dialog fields to display actual MODEL chart properties.
|
360
358
|
this.updateSelector();
|
361
359
|
let c = null;
|
362
360
|
if(this.chart_index >= 0) {
|
@@ -370,8 +368,8 @@ class GUIChartManager extends ChartManager {
|
|
370
368
|
}
|
371
369
|
UI.setBox('chart-title', c.show_title);
|
372
370
|
const ol = [];
|
373
|
-
for(
|
374
|
-
const
|
371
|
+
for(const opt of this.legend_options) {
|
372
|
+
const val = opt.toLowerCase();
|
375
373
|
ol.push(['<option value="', val,
|
376
374
|
(c.legend_position === val ? '" selected="selected' : ''),
|
377
375
|
'">', opt, '</option>'].join(''));
|
@@ -427,14 +425,16 @@ class GUIChartManager extends ChartManager {
|
|
427
425
|
} else {
|
428
426
|
UI.disableButtons(d_btn);
|
429
427
|
}
|
430
|
-
// If the Edit variable dialog is showing, update its header
|
428
|
+
// If the Edit variable dialog is showing, update its header.
|
431
429
|
if(this.variable_index >= 0 && !UI.hidden('variable-dlg')) {
|
432
430
|
document.getElementById('variable-dlg-name').innerHTML =
|
433
431
|
c.variables[this.variable_index].displayName;
|
434
432
|
}
|
435
433
|
}
|
434
|
+
// Finder dialog may need to update its "add variables to chart" button
|
435
|
+
if(FINDER.visible) FINDER.updateDialog();
|
436
436
|
this.add_variable_modal.element('obj').value = 0;
|
437
|
-
// Update variable dropdown list of the "add variable" modal
|
437
|
+
// Update variable dropdown list of the "add variable" modal.
|
438
438
|
X_EDIT.updateVariableBar('add-');
|
439
439
|
this.stretchChart(0);
|
440
440
|
}
|
@@ -507,9 +507,7 @@ class GUIChartManager extends ChartManager {
|
|
507
507
|
let n = '';
|
508
508
|
if(c.histogram) {
|
509
509
|
let vv = [];
|
510
|
-
for(
|
511
|
-
if(c.variables[i].visible) vv.push(c.variables[i]);
|
512
|
-
}
|
510
|
+
for(const v of c.variables) if(v.visible) vv.push(v);
|
513
511
|
const
|
514
512
|
l = vv.length,
|
515
513
|
bars = c.bins * l,
|
@@ -547,16 +545,16 @@ class GUIChartManager extends ChartManager {
|
|
547
545
|
}
|
548
546
|
|
549
547
|
selectChart() {
|
550
|
-
//
|
548
|
+
// Set the selected chart to be the "active" chart.
|
551
549
|
const ci = parseInt(this.chart_selector.value);
|
552
|
-
// Deselect variable only if different chart is selected
|
550
|
+
// Deselect variable only if different chart is selected.
|
553
551
|
if(ci !== this.chart_index) this.variable_index = -1;
|
554
552
|
this.chart_index = ci;
|
555
553
|
this.updateDialog();
|
556
554
|
}
|
557
555
|
|
558
556
|
promptForTitle() {
|
559
|
-
//
|
557
|
+
// Prompt modeler for a new title for the current chart.
|
560
558
|
if(this.chart_index >= 0) {
|
561
559
|
this.rename_chart_modal.show();
|
562
560
|
const nct = document.getElementById('new-chart-title');
|
@@ -566,29 +564,29 @@ class GUIChartManager extends ChartManager {
|
|
566
564
|
}
|
567
565
|
|
568
566
|
renameChart() {
|
569
|
-
//
|
567
|
+
// Rename the current chart.
|
570
568
|
if(this.chart_index >= 0) {
|
571
|
-
const t = document.getElementById('new-chart-title').value
|
572
|
-
// Check if a chart with this title already exists
|
569
|
+
const t = UI.cleanName(document.getElementById('new-chart-title').value);
|
570
|
+
// Check if a chart with this title already exists.
|
573
571
|
const ci = MODEL.indexOfChart(t);
|
574
572
|
if(ci >= 0 && ci != this.chart_index) {
|
575
573
|
UI.warn(`A chart with title "${t}" already exists`);
|
576
574
|
} else {
|
577
575
|
const c = MODEL.charts[this.chart_index];
|
578
|
-
// Remember the old title of the chart-to-be-renamed
|
576
|
+
// Remember the old title of the chart-to-be-renamed.
|
579
577
|
const ot = c.title;
|
580
578
|
c.title = t;
|
581
|
-
// If the default '(new chart)' has been renamed, create a new one
|
579
|
+
// If the default '(new chart)' has been renamed, create a new one.
|
582
580
|
if(ot === this.new_chart_title) {
|
583
581
|
MODEL.addChart(ot);
|
584
582
|
}
|
585
|
-
// Update the chart index so that it points to the renamed chart
|
583
|
+
// Update the chart index so that it points to the renamed chart.
|
586
584
|
this.chart_index = MODEL.indexOfChart(t);
|
587
585
|
this.updateSelector();
|
588
|
-
// Redraw the chart if title is shown
|
586
|
+
// Redraw the chart if title is shown.
|
589
587
|
if(c.show_title) this.drawChart();
|
590
588
|
}
|
591
|
-
// Update
|
589
|
+
// Update dialogs that may refer to this chart.
|
592
590
|
UI.updateControllerDialogs('CFX');
|
593
591
|
}
|
594
592
|
this.rename_chart_modal.hide();
|
@@ -608,10 +606,8 @@ class GUIChartManager extends ChartManager {
|
|
608
606
|
nc.bins = c.bins;
|
609
607
|
nc.show_title = c.show_title;
|
610
608
|
nc.legend_position = c.legend_position;
|
611
|
-
for(
|
612
|
-
const
|
613
|
-
cv = c.variables[i],
|
614
|
-
nv = new ChartVariable(nc);
|
609
|
+
for(const cv of c.variables) {
|
610
|
+
const nv = new ChartVariable(nc);
|
615
611
|
nv.setProperties(cv.object, cv.attribute, cv.stacked,
|
616
612
|
cv.color, cv.scale_factor, cv.line_width, cv.sorted);
|
617
613
|
nc.variables.push(nv);
|
@@ -743,7 +739,17 @@ class GUIChartManager extends ChartManager {
|
|
743
739
|
// First hide the "Add variable" modal.
|
744
740
|
this.add_variable_modal.hide();
|
745
741
|
// Do not prompt for selection if there is only 1 match.
|
746
|
-
if(indices.length < 2)
|
742
|
+
if(indices.length < 2) {
|
743
|
+
if(indices.length) {
|
744
|
+
chart.addWildcardVariables(dsm, indices);
|
745
|
+
} else if(dsm.selector.startsWith(':')) {
|
746
|
+
UI.notify('Plotting methods is work-in-progress!');
|
747
|
+
console.log('HERE dsm', dsm, 'expr', dsm.expression.text, 'indices', indices);
|
748
|
+
} else {
|
749
|
+
UI.notify(`Variable "${dsm.displayName}" cannot be plotted`);
|
750
|
+
}
|
751
|
+
return;
|
752
|
+
}
|
747
753
|
md.chart = chart;
|
748
754
|
md.modifier = dsm;
|
749
755
|
md.indices = indices;
|
@@ -751,10 +757,10 @@ class GUIChartManager extends ChartManager {
|
|
751
757
|
tr = [],
|
752
758
|
dn = dsm.displayName,
|
753
759
|
tbl = md.element('table');
|
754
|
-
for(
|
755
|
-
tr.push('<tr><td class="v-box"><div id="wcv-box-',
|
760
|
+
for(const index of indices) {
|
761
|
+
tr.push('<tr><td class="v-box"><div id="wcv-box-', index,
|
756
762
|
'" class="box clear" onclick="UI.toggleBox(event);"></td>',
|
757
|
-
'<td class="vname">', dn.replace('??',
|
763
|
+
'<td class="vname">', dn.replace('??', index),
|
758
764
|
'</td></tr>');
|
759
765
|
tbl.innerHTML = tr.join('');
|
760
766
|
}
|
@@ -769,11 +775,10 @@ class GUIChartManager extends ChartManager {
|
|
769
775
|
md = this.add_wildcard_modal,
|
770
776
|
c = md.chart,
|
771
777
|
dsm = md.modifier,
|
772
|
-
il = md.indices,
|
773
778
|
indices = [];
|
774
|
-
if(c && dsm
|
775
|
-
for(
|
776
|
-
if(UI.boxChecked('wcv-box-'+
|
779
|
+
if(c && dsm) {
|
780
|
+
for(const index of md.indices) {
|
781
|
+
if(UI.boxChecked('wcv-box-'+ index)) indices.push(index);
|
777
782
|
}
|
778
783
|
}
|
779
784
|
if(indices.length) c.addWildcardVariables(dsm, indices);
|
@@ -947,28 +952,27 @@ class GUIChartManager extends ChartManager {
|
|
947
952
|
this.variable_index = -1;
|
948
953
|
this.updateDialog();
|
949
954
|
// Also update the experiment viewer (charts define the output variables)
|
950
|
-
// and finder dialog
|
955
|
+
// and finder dialog.
|
951
956
|
if(EXPERIMENT_MANAGER.selected_experiment) UI.updateControllerDialogs('FX');
|
952
957
|
}
|
953
958
|
this.variable_modal.hide();
|
954
959
|
}
|
955
960
|
|
956
961
|
showChartImage(c) {
|
957
|
-
//
|
962
|
+
// Display the SVG image for chart `c` (computed by this Chart object).
|
958
963
|
if(c) document.getElementById('chart-svg').innerHTML = c.svg;
|
959
964
|
}
|
960
965
|
|
961
966
|
drawTable() {
|
962
|
-
//
|
967
|
+
// Show the statistics on the chart variables.
|
963
968
|
const html = [];
|
964
969
|
let vbl = [];
|
965
970
|
if(this.chart_index >= 0) vbl = MODEL.charts[this.chart_index].variables;
|
966
971
|
// First get the (potentially floating point) numbers so that their format
|
967
|
-
// can be made uniform per column
|
972
|
+
// can be made uniform per column.
|
968
973
|
const data = [];
|
969
974
|
let nr = 0;
|
970
|
-
for(
|
971
|
-
const v = vbl[i];
|
975
|
+
for(const v of vbl) {
|
972
976
|
if(v.visible) {
|
973
977
|
data.push([VM.sig4Dig(v.minimum), VM.sig4Dig(v.maximum),
|
974
978
|
VM.sig4Dig(v.mean), VM.sig4Dig(Math.sqrt(v.variance)),
|
@@ -980,7 +984,7 @@ class GUIChartManager extends ChartManager {
|
|
980
984
|
this.table_panel.innerHTML = '<div id="no-chart-data">No data</div>';
|
981
985
|
return;
|
982
986
|
}
|
983
|
-
// Process each of 5 columns separately
|
987
|
+
// Process each of 5 columns separately.
|
984
988
|
for(let c = 0; c < 5; c++) {
|
985
989
|
const col = [];
|
986
990
|
for(let r = 0; r < data.length; r++) {
|
@@ -998,10 +1002,9 @@ class GUIChartManager extends ChartManager {
|
|
998
1002
|
'<th>μ</th><th>σ</th><th>Σ</th>',
|
999
1003
|
'<th>≠0</th><th>⚠</th></tr>');
|
1000
1004
|
nr = 0;
|
1001
|
-
for(
|
1002
|
-
const v = vbl[i];
|
1005
|
+
for(const v of vbl) {
|
1003
1006
|
if(v.visible) {
|
1004
|
-
// NOTE:
|
1007
|
+
// NOTE: While still solving, display t-1 as N.
|
1005
1008
|
const n = Math.max(0, v.N);
|
1006
1009
|
html.push('<tr><td class="v-name">', v.displayName, '</td><td>', n,
|
1007
1010
|
'</td><td title="', v.minimum.toPrecision(8), '">', data[nr][0],
|
@@ -1086,17 +1089,17 @@ class GUIChartManager extends ChartManager {
|
|
1086
1089
|
}
|
1087
1090
|
}
|
1088
1091
|
|
1089
|
-
downloadChart() {
|
1090
|
-
// Pushes the SVG of the selected chart as file to the browser
|
1092
|
+
downloadChart(shift) {
|
1093
|
+
// Pushes the SVG of the selected chart as file to the browser.
|
1091
1094
|
if(this.chart_index >= 0) {
|
1092
|
-
|
1095
|
+
const svg = MODEL.charts[this.chart_index].svg;
|
1096
|
+
if(shift) {
|
1097
|
+
FILE_MANAGER.pushOutSVG(svg);
|
1098
|
+
} else {
|
1099
|
+
FILE_MANAGER.pushOutPNG(svg);
|
1100
|
+
}
|
1093
1101
|
}
|
1094
1102
|
}
|
1095
|
-
|
1096
|
-
renderChartAsPNG() {
|
1097
|
-
window.localStorage.removeItem('png-url');
|
1098
|
-
FILE_MANAGER.renderSVGAsPNG(MODEL.charts[this.chart_index].svg);
|
1099
|
-
}
|
1100
1103
|
|
1101
1104
|
drawChart() {
|
1102
1105
|
// Displays the selected chart unless an experiment is running, or
|
@@ -984,11 +984,10 @@ class ConstraintEditor {
|
|
984
984
|
'</defs>'].join('');
|
985
985
|
// Draw the grid
|
986
986
|
this.drawGrid();
|
987
|
-
// Use c as shorthand for this.constraint
|
987
|
+
// Use `c` as shorthand for this.constraint.
|
988
988
|
const c = this.constraint;
|
989
989
|
// Add the SVG for lower and upper bounds
|
990
|
-
for(
|
991
|
-
const bl = c.bound_lines[i];
|
990
|
+
for(const bl of c.bound_lines) {
|
992
991
|
this.drawContour(bl);
|
993
992
|
this.drawLine(bl);
|
994
993
|
}
|
@@ -1057,10 +1056,7 @@ class ConstraintEditor {
|
|
1057
1056
|
} else {
|
1058
1057
|
const base_y = (l.type === VM.GE ? 0 : 100);
|
1059
1058
|
cp = 'M' + this.point(0, base_y);
|
1060
|
-
for(
|
1061
|
-
const p = l.points[i];
|
1062
|
-
cp += `L${this.point(p[0], p[1])}`;
|
1063
|
-
}
|
1059
|
+
for(const p of l.points) cp += `L${this.point(p[0], p[1])}`;
|
1064
1060
|
cp += 'L' + this.point(100, base_y) + 'z';
|
1065
1061
|
// Save the contour for rapid display of thumbnails.
|
1066
1062
|
l.contour_path = cp;
|
@@ -1089,10 +1085,10 @@ class ConstraintEditor {
|
|
1089
1085
|
const
|
1090
1086
|
cfs = `fill="${color}" stroke="${color}" stroke-width="${width}"`,
|
1091
1087
|
icfs = 'fill="white" stroke="white" stroke-width="1"';
|
1092
|
-
for(
|
1088
|
+
for(const p of l.points) {
|
1093
1089
|
const
|
1094
|
-
px =
|
1095
|
-
py =
|
1090
|
+
px = p[0],
|
1091
|
+
py = p[1];
|
1096
1092
|
pp.push(this.point(px, py));
|
1097
1093
|
dots += `<circle ${this.circleCenter(px, py)} r="3" ${cfs}></circle>`;
|
1098
1094
|
// Draw "custom points" with a white inner circle.
|
@@ -1118,13 +1114,13 @@ class ConstraintEditor {
|
|
1118
1114
|
}
|
1119
1115
|
|
1120
1116
|
showDialog(group=[]) {
|
1121
|
-
this.from_node = MODEL.objectByName(this.from_name.
|
1122
|
-
this.to_node = MODEL.objectByName(this.to_name.
|
1123
|
-
// Double-check that these nodes exist
|
1117
|
+
this.from_node = MODEL.objectByName(this.from_name.innerText);
|
1118
|
+
this.to_node = MODEL.objectByName(this.to_name.innerText);
|
1119
|
+
// Double-check that these nodes exist.
|
1124
1120
|
if(!(this.from_node && this.to_node)) {
|
1125
1121
|
throw 'ERROR: Unknown constraint node(s)';
|
1126
1122
|
}
|
1127
|
-
// See if existing constraint is edited
|
1123
|
+
// See if existing constraint is edited.
|
1128
1124
|
this.edited_constraint = this.from_node.doesConstrain(this.to_node);
|
1129
1125
|
if(this.edited_constraint) {
|
1130
1126
|
// Make a working copy, as the constraint must be changed only when
|