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.
Files changed (36) hide show
  1. package/README.md +3 -40
  2. package/package.json +6 -2
  3. package/server.js +19 -157
  4. package/static/images/solve-not-same-changed.png +0 -0
  5. package/static/images/solve-not-same-not-changed.png +0 -0
  6. package/static/images/solve-same-changed.png +0 -0
  7. package/static/images/solve-same-not-changed.png +0 -0
  8. package/static/index.html +137 -20
  9. package/static/linny-r.css +260 -23
  10. package/static/scripts/iro.min.js +7 -7
  11. package/static/scripts/linny-r-ctrl.js +126 -85
  12. package/static/scripts/linny-r-gui-actor-manager.js +23 -33
  13. package/static/scripts/linny-r-gui-chart-manager.js +56 -53
  14. package/static/scripts/linny-r-gui-constraint-editor.js +10 -14
  15. package/static/scripts/linny-r-gui-controller.js +644 -260
  16. package/static/scripts/linny-r-gui-dataset-manager.js +64 -66
  17. package/static/scripts/linny-r-gui-documentation-manager.js +11 -17
  18. package/static/scripts/linny-r-gui-equation-manager.js +22 -22
  19. package/static/scripts/linny-r-gui-experiment-manager.js +124 -141
  20. package/static/scripts/linny-r-gui-expression-editor.js +26 -12
  21. package/static/scripts/linny-r-gui-file-manager.js +42 -48
  22. package/static/scripts/linny-r-gui-finder.js +294 -55
  23. package/static/scripts/linny-r-gui-model-autosaver.js +2 -4
  24. package/static/scripts/linny-r-gui-monitor.js +35 -41
  25. package/static/scripts/linny-r-gui-paper.js +42 -70
  26. package/static/scripts/linny-r-gui-power-grid-manager.js +31 -34
  27. package/static/scripts/linny-r-gui-receiver.js +1 -2
  28. package/static/scripts/linny-r-gui-repository-browser.js +44 -46
  29. package/static/scripts/linny-r-gui-scale-unit-manager.js +32 -32
  30. package/static/scripts/linny-r-gui-sensitivity-analysis.js +61 -67
  31. package/static/scripts/linny-r-gui-undo-redo.js +94 -95
  32. package/static/scripts/linny-r-milp.js +20 -24
  33. package/static/scripts/linny-r-model.js +1932 -2274
  34. package/static/scripts/linny-r-utils.js +27 -27
  35. package/static/scripts/linny-r-vm.js +900 -998
  36. 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
- // Adds one option to the selector for each chart defined for the model.
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
- // Refreshes all dialog fields to display actual MODEL chart properties
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(let i = 0; i < this.legend_options.length; i++) {
374
- const opt = this.legend_options[i], val = opt.toLowerCase();
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(let i = 0; i < c.variables.length; i++) {
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
- // Sets the selected chart to be the "active" chart
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
- // Prompts modeler for a new title for the current chart
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
- // Renames the current chart
567
+ // Rename the current chart.
570
568
  if(this.chart_index >= 0) {
571
- const t = document.getElementById('new-chart-title').value.trim();
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 experiment viewer in case its current experiment uses this chart
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(let i = 0; i < c.variables.length; i++) {
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) chart.addWildcardVariables(dsm, indices);
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(let i = 0; i < indices.length; i++) {
755
- tr.push('<tr><td class="v-box"><div id="wcv-box-', indices[i],
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('??', indices[i]),
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 && il) {
775
- for(let i = 0; i < il.length; i++) {
776
- if(UI.boxChecked('wcv-box-'+ il[i])) indices.push(il[i]);
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
- // Displays the SVG image for chart `c` (computed by this Chart object)
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
- // Shows the statistics on the chart variables.
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(let i = 0; i < vbl.length; i++) {
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>&mu;</th><th>&sigma;</th><th>&Sigma;</th>',
999
1003
  '<th>&ne;0</th><th>&#x26A0;</th></tr>');
1000
1004
  nr = 0;
1001
- for(let i = 0; i < vbl.length; i++) {
1002
- const v = vbl[i];
1005
+ for(const v of vbl) {
1003
1006
  if(v.visible) {
1004
- // NOTE: while still solving, display t-1 as N
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
- FILE_MANAGER.pushOutSVG(MODEL.charts[this.chart_index].svg);
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(let i = 0; i < c.bound_lines.length; i++) {
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(let i = 0; i < l.points.length; i++) {
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(let i = 0; i < l.points.length; i++) {
1088
+ for(const p of l.points) {
1093
1089
  const
1094
- px = l.points[i][0],
1095
- py = l.points[i][1];
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.innerHTML);
1122
- this.to_node = MODEL.objectByName(this.to_name.innerHTML);
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