linny-r 1.9.0 → 1.9.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linny-r",
3
- "version": "1.9.0",
3
+ "version": "1.9.1",
4
4
  "description": "Executable graphical language with WYSIWYG editor for MILP models",
5
5
  "main": "server.js",
6
6
  "scripts": {
package/static/index.html CHANGED
@@ -750,6 +750,13 @@ NOTE: Unit symbols are case-sensitive, so BTU ≠ Btu">
750
750
  placeholder="1e-4" type="text" autocomplete="off">
751
751
  </td>
752
752
  </tr>
753
+ <tr title="When checked, small slack uses are reported in monitor">
754
+ <td style="padding: 0px; width: 20px">
755
+ <div id="solver-show-notices" class="box clear"></div>
756
+ </td>
757
+ <td style="padding-bottom:4px">Report small slack uses</td>
758
+ </td>
759
+ </tr>
753
760
  </table>
754
761
  </div>
755
762
  </div>
@@ -3689,6 +3689,7 @@ console.log('HERE name conflicts', name_conflicts, mapping);
3689
3689
  md.element('preference').innerHTML = html.join('');
3690
3690
  md.element('int-feasibility').value = MODEL.integer_tolerance;
3691
3691
  md.element('mip-gap').value = MODEL.MIP_gap;
3692
+ this.setBox('solver-show-notices', MODEL.show_notices);
3692
3693
  md.show();
3693
3694
  }
3694
3695
 
@@ -3717,6 +3718,7 @@ console.log('HERE name conflicts', name_conflicts, mapping);
3717
3718
  }
3718
3719
  MODEL.integer_tolerance = Math.max(1e-9, Math.min(0.1, itol));
3719
3720
  MODEL.MIP_gap = Math.max(0, Math.min(0.5, mgap));
3721
+ MODEL.show_notices = this.boxChecked('solver-show-notices');
3720
3722
  // Close the dialog.
3721
3723
  md.hide();
3722
3724
  }
@@ -66,6 +66,7 @@ Attributes, however, are case sensitive!">[Actor X|CF]</code> for cash flow.
66
66
  <code title="Relative time step (t &minus; t&#8320; + 1)">rt</code>,
67
67
  <code title="Number of current block">b</code>,
68
68
  <code title="Time step within current block">bt</code>,
69
+ <code title="Time step within current chunk">ct</code>,
69
70
  <code title="Duration of 1 time step (in hours)">dt</code>,
70
71
  <code title="Run length (# time steps)">N</code>,
71
72
  <code title="Block length (# time steps)">n</code>,
@@ -107,6 +107,7 @@ class LinnyRModel {
107
107
  this.integer_tolerance = 5e-7; // integer feasibility tolerance
108
108
  this.MIP_gap = 1e-4; // relative MIP gap
109
109
  this.always_diagnose = true;
110
+ this.show_notices = true;
110
111
 
111
112
  // Sensitivity-related properties
112
113
  this.base_case_selectors = '';
@@ -2670,6 +2671,7 @@ class LinnyRModel {
2670
2671
  this.report_results = nodeParameterValue(node, 'report-results') === '1';
2671
2672
  this.show_block_arrows = nodeParameterValue(node, 'block-arrows') === '1';
2672
2673
  this.always_diagnose = nodeParameterValue(node, 'diagnose') === '1';
2674
+ this.show_notices = nodeParameterValue(node, 'show-notices') === '1';
2673
2675
  this.name = xmlDecoded(nodeContentByTag(node, 'name'));
2674
2676
  this.author = xmlDecoded(nodeContentByTag(node, 'author'));
2675
2677
  this.comments = xmlDecoded(nodeContentByTag(node, 'notes'));
@@ -3023,6 +3025,7 @@ class LinnyRModel {
3023
3025
  if(this.report_results) p += ' report-results="1"';
3024
3026
  if(this.show_block_arrows) p += ' block-arrows="1"';
3025
3027
  if(this.always_diagnose) p += ' diagnose="1"';
3028
+ if(this.show_notices) p += ' show-notices="1"';
3026
3029
  let xml = this.xml_header + ['<model', p, '><name>', xmlEncoded(this.name),
3027
3030
  '</name><author>', xmlEncoded(this.author),
3028
3031
  '</author><notes>', xmlEncoded(this.comments),
@@ -430,20 +430,25 @@ class Expression {
430
430
  }
431
431
 
432
432
  result(t, number=false) {
433
- // Computes (only if needed) and then returns result for time step t
433
+ // Compute (only if needed) and then returns result for time step t.
434
434
  // The `number` is passed only by the VMI_push_dataset_modifier
435
- // instruction so as to force recomputation of the expression
436
- // NOTE: for t < 1 return the value for t = 1, since expressions have no
437
- // "initial value" (these follow from the variables used in the expression)
438
- // Select the vector to use
435
+ // instruction so as to force recomputation of the expression.
436
+ // Select the vector to use.
439
437
  const v = this.chooseVector(number);
440
438
  if(!Array.isArray(v)) {
441
439
  console.log('ANOMALY: No vector for result(t)');
442
440
  return VM.UNDEFINED;
443
441
  }
442
+ // NOTE: For t < 1 return the value for t = 1, since expressions have
443
+ // no "initial value" (these follow from the variables used in the
444
+ // expression).
444
445
  if(t < 0 || this.isStatic) t = 0;
445
446
  if(t >= v.length) return VM.UNDEFINED;
446
- if(v[t] === VM.NOT_COMPUTED || v[t] === VM.COMPUTING) {
447
+ // NOTE: When VM is setting up a tableau, values computed for the
448
+ // look-ahead period must be recomputed.
449
+ if(v[t] === VM.NOT_COMPUTED || v[t] === VM.COMPUTING ||
450
+ (!this.isStatic && VM.inLookAhead(t))) {
451
+ v[t] = VM.NOT_COMPUTED;
447
452
  this.compute(t, number);
448
453
  }
449
454
  // NOTE: when this expression is the "active" parameter for sensitivity
@@ -2477,8 +2482,19 @@ class VirtualMachine {
2477
2482
  this.t = 0;
2478
2483
  // Prepare for halt.
2479
2484
  this.halted = false;
2485
+ // Flag to indicate that VM is executing its tableau construction code.
2486
+ // This affects how chunk time (ct) is computed, and whether expression
2487
+ // results must be recomputed (see inLookAhead below).
2488
+ this.executing_tableau_code = false;
2480
2489
  UI.readyToSolve();
2481
2490
  }
2491
+
2492
+ inLookAhead(t) {
2493
+ // Return TRUE if VM is executing its tableau construction code AND
2494
+ // time step `t` falls in the look-ahead period of the previous block.
2495
+ return this.executing_tableau_code &&
2496
+ t - (this.block_count - 1) * MODEL.block_length <= MODEL.look_ahead;
2497
+ }
2482
2498
 
2483
2499
  errorMessage(n) {
2484
2500
  // VM errors are very big NEGATIVE numbers, so start comparing `n`
@@ -2871,7 +2887,7 @@ class VirtualMachine {
2871
2887
  const
2872
2888
  bm = r.block_messages[i],
2873
2889
  err = (bm.messages.indexOf('Solver status = 0') < 0 ||
2874
- bm.messages.indexOf('Warning') >= 0);
2890
+ bm.messages.indexOf(this.WARNING) >= 0);
2875
2891
  this.solver_times.push(bm.solver_time);
2876
2892
  this.messages.push(bm.messages);
2877
2893
  this.variables.push(this.no_variables);
@@ -4657,7 +4673,7 @@ class VirtualMachine {
4657
4673
  ppc[ci].usesSlack(b, v[1], v[0]);
4658
4674
  }
4659
4675
  }
4660
- } else if(CONFIGURATION.slight_slack_notices) {
4676
+ } else if(MODEL.show_notices) {
4661
4677
  this.logMessage(block, '---- Notice: (t=' + b + round + ') ' +
4662
4678
  v[1].displayName + ' ' + v[0] + ' slack = ' +
4663
4679
  slack.toPrecision(1));
@@ -5223,7 +5239,7 @@ class VirtualMachine {
5223
5239
  }
5224
5240
 
5225
5241
  addTableauSegment(start, abl) {
5226
- if(VM.halted) {
5242
+ if(this.halted) {
5227
5243
  this.hideSetUpOrWriteProgress();
5228
5244
  this.stopSolving();
5229
5245
  return;
@@ -5233,6 +5249,7 @@ class VirtualMachine {
5233
5249
  var l;
5234
5250
  const next_start = (start + this.tsl * 1.2 < abl ? start + this.tsl : abl);
5235
5251
  for(let i = start; i < next_start; i++) {
5252
+ this.executing_tableau_code = true;
5236
5253
  this.logTrace('EXECUTE for t=' + this.t);
5237
5254
  l = this.code.length;
5238
5255
  for(let j = 0; j < l; j++) {
@@ -5244,6 +5261,7 @@ class VirtualMachine {
5244
5261
  this.logTrace([(' ' + j).slice(-5), ': coeff = ',
5245
5262
  JSON.stringify(this.coefficients), '; rhs = ', this.rhs].join(''));
5246
5263
  }
5264
+ this.executing_tableau_code = false;
5247
5265
  this.logTrace('STOP executing block code');
5248
5266
  // Add constraints for paced process variables.
5249
5267
  // NOTE: This is effectuated by *executing* VM instructions.
@@ -6268,11 +6286,26 @@ function VMI_push_block_time(x) {
6268
6286
  const
6269
6287
  lt = x.step[x.step.length - 1] - 1,
6270
6288
  bnr = Math.floor(lt / MODEL.block_length),
6271
- t = lt - bnr * MODEL.block_length + 1;
6289
+ t = lt - bnr * MODEL.block_length + 1;
6272
6290
  if(DEBUGGING) console.log('push block time bt = ' + t);
6273
6291
  x.push(t);
6274
6292
  }
6275
6293
 
6294
+ function VMI_push_chunk_time(x) {
6295
+ // Push the time step for which the VM is preparing the tableau.
6296
+ // NOTE: Chunk time is meaningful only while the VM is solving a block.
6297
+ // If not, the block time is pushed.
6298
+ if(VM.executing_tableau_code) {
6299
+ const
6300
+ ct = VM.t - (VM.block_count - 1) * MODEL.block_length;
6301
+ if(DEBUGGING) console.log('push chunk time ct = ' + ct);
6302
+ x.push(ct);
6303
+ } else {
6304
+ if(DEBUGGING) console.log('push chunk time: NOT constructing tableau');
6305
+ VMI_push_block_time(x);
6306
+ }
6307
+ }
6308
+
6276
6309
  function VMI_push_block_number(x) {
6277
6310
  // Push the number of the block currently being optimized.
6278
6311
  // NOTE: Block numbering starts at 1.
@@ -8683,11 +8716,12 @@ const
8683
8716
  SEPARATOR_CHARS = PARENTHESES + OPERATOR_CHARS + "[ '",
8684
8717
  COMPOUND_OPERATORS = ['!=', '<>', '>=', '<='],
8685
8718
  CONSTANT_SYMBOLS = [
8686
- 't', 'rt', 'bt', 'b', 'N', 'n', 'l', 'r', 'lr', 'nr', 'x', 'nx',
8719
+ 't', 'rt', 'bt', 'ct', 'b', 'N', 'n', 'l', 'r', 'lr', 'nr', 'x', 'nx',
8687
8720
  'random', 'dt', 'true', 'false', 'pi', 'infinity', '#',
8688
8721
  'i', 'j', 'k', 'yr', 'wk', 'd', 'h', 'm', 's'],
8689
8722
  CONSTANT_CODES = [
8690
8723
  VMI_push_time_step, VMI_push_relative_time, VMI_push_block_time,
8724
+ VMI_push_chunk_time,
8691
8725
  VMI_push_block_number, VMI_push_run_length, VMI_push_block_length,
8692
8726
  VMI_push_look_ahead, VMI_push_round, VMI_push_last_round,
8693
8727
  VMI_push_number_of_rounds, VMI_push_run_number, VMI_push_number_of_runs,
@@ -8696,7 +8730,7 @@ const
8696
8730
  VMI_push_i, VMI_push_j, VMI_push_k,
8697
8731
  VMI_push_year, VMI_push_week, VMI_push_day, VMI_push_hour,
8698
8732
  VMI_push_minute, VMI_push_second],
8699
- DYNAMIC_SYMBOLS = ['t', 'rt', 'bt', 'b', 'r', 'random', 'i', 'j', 'k'],
8733
+ DYNAMIC_SYMBOLS = ['t', 'rt', 'bt', 'ct', 'b', 'r', 'random', 'i', 'j', 'k'],
8700
8734
  MONADIC_OPERATORS = [
8701
8735
  '~', 'not', 'abs', 'sin', 'cos', 'atan', 'ln',
8702
8736
  'exp', 'sqrt', 'round', 'int', 'fract', 'min', 'max',