@sdeverywhere/cli 0.7.41 → 0.7.42

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": "@sdeverywhere/cli",
3
- "version": "0.7.41",
3
+ "version": "0.7.42",
4
4
  "description": "Contains the `sde` command line interface for the SDEverywhere tool suite.",
5
5
  "type": "module",
6
6
  "files": [
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@sdeverywhere/build": "^0.3.12",
15
- "@sdeverywhere/compile": "^0.7.29",
15
+ "@sdeverywhere/compile": "^0.7.30",
16
16
  "byline": "^5.0.0",
17
17
  "ramda": "^0.27.0",
18
18
  "shelljs": "^0.10.0",
package/src/c/vensim.c CHANGED
@@ -503,6 +503,237 @@ double* _ALLOCATE_AVAILABLE(
503
503
  return allocations;
504
504
  }
505
505
 
506
+ //
507
+ // Helper methods for allocate by priority
508
+ //
509
+ double __sum(double* arr, size_t n) {
510
+ double total = 0.0;
511
+ for (size_t i = 0; i < n; i++) {
512
+ total += arr[i];
513
+ }
514
+ return total;
515
+ }
516
+
517
+ //
518
+ // ALLOCATE BY PRIORITY
519
+ //
520
+ #define ALLOCATE_BY_PRIORITY_BUFSIZE 60
521
+ #define PRINT_ALLOCATIONS_DEBUG_INFO
522
+
523
+ double* _ALLOCATE_BY_PRIORITY(
524
+ double* request_quantities, double* priority_values, double size, double width, double supply, size_t num_requesters) {
525
+
526
+ // request points to an array of length num_requesters.
527
+ // priority points to an array of length num_requesters.
528
+ // size is the number of elements across which allocation is being made.
529
+ // width specifies how big a gap in priority is required to have the allocation go first to
530
+ // higher priority with only leftovers going to lower priority.
531
+ // supply is the total supply available to fulfill all requests.
532
+
533
+ // Allocate by priority allocates supply to requesters based on order of priority. The way in
534
+ // which the rationing works is determined by the relative priorities and the width parameter.
535
+
536
+ static double allocations[ALLOCATE_BY_PRIORITY_BUFSIZE];
537
+ if (num_requesters > ALLOCATE_BY_PRIORITY_BUFSIZE) {
538
+ fprintf(stderr, "_ALLOCATE_BY_PRIORITY num_requesters exceeds internal maximum size of %d\n", ALLOCATE_BY_PRIORITY_BUFSIZE);
539
+ return NULL;
540
+ }
541
+
542
+ // Validate request values (must be non-negative)
543
+ for (size_t i = 0; i < num_requesters; i++) {
544
+ if (request_quantities[i] < -_epsilon) {
545
+ fprintf(stderr,
546
+ "_ALLOCATE_BY_PRIORITY encountered negative request value at index %zu: %f\n",
547
+ i, request_quantities[i]);
548
+ return NULL;
549
+ }
550
+ }
551
+
552
+ // Validate width (must not be negative)
553
+ if (width < -_epsilon) {
554
+ fprintf(stderr,
555
+ "_ALLOCATE_BY_PRIORITY encountered invalid width value: %f\n"
556
+ "Width must not be negative.\n",
557
+ width);
558
+ return NULL;
559
+ }
560
+
561
+ // Validate supply (must not be negative)
562
+ if (supply < -_epsilon) {
563
+ fprintf(stderr,
564
+ "_ALLOCATE_BY_PRIORITY encountered invalid supply value: %f\n"
565
+ "Supply must not be negative.\n",
566
+ supply);
567
+ return NULL;
568
+ }
569
+
570
+ // If supply > sum(request), return request
571
+ if (supply > __sum(request_quantities, num_requesters)) {
572
+ return request_quantities;
573
+ }
574
+
575
+ // If supply = 0, all targets get allocated 0
576
+ if(fabs(supply) < _epsilon) {
577
+ return allocations;
578
+ }
579
+
580
+ static double out_return[ALLOCATE_BY_PRIORITY_BUFSIZE];
581
+
582
+ // Remove request 0 targets and order by priority
583
+ bool is_0[ALLOCATE_BY_PRIORITY_BUFSIZE];
584
+ size_t idx[ALLOCATE_BY_PRIORITY_BUFSIZE];
585
+ size_t m = 0;
586
+
587
+ for (size_t i = 0; i < num_requesters; i++) {
588
+ is_0[i] = request_quantities[i] == 0.0;
589
+ if (!is_0[i]) {
590
+ idx[m++] = i;
591
+ }
592
+ }
593
+
594
+ // Sort indices in `idx` by descending `priority_values` (highest priority first)
595
+ for (size_t i = 0; i < m; i++) {
596
+ for (size_t j = i + 1; j < m; j++) {
597
+ if (priority_values[idx[j]] > priority_values[idx[i]]) {
598
+ size_t tmp = idx[i];
599
+ idx[i] = idx[j];
600
+ idx[j] = tmp;
601
+ }
602
+ }
603
+ }
604
+
605
+ // Populate local arrays with request and priority values reordered according to idx
606
+ double request[ALLOCATE_BY_PRIORITY_BUFSIZE];
607
+ double priority[ALLOCATE_BY_PRIORITY_BUFSIZE];
608
+
609
+ for (size_t i = 0; i < m; i++) {
610
+ request[i] = (double)request_quantities[idx[i]];
611
+ priority[i] = priority_values[idx[i]];
612
+ }
613
+
614
+ // Create the outputs array
615
+ for (size_t i = 0; i < num_requesters; i++) {
616
+ out_return[i] = 0.0;
617
+ }
618
+
619
+ double out[ALLOCATE_BY_PRIORITY_BUFSIZE] = {0.0};
620
+
621
+ // Compute the distances between target supply and next target start
622
+ double distances[ALLOCATE_BY_PRIORITY_BUFSIZE];
623
+
624
+ for (size_t i = 0; i < m; i++) {
625
+ distances[i] = NAN;
626
+ }
627
+
628
+ // Last target will have NaN as distances as there are no more targets after
629
+ for (size_t i = 0; i + 1 < m; i++) {
630
+ double d = -(priority[i + 1] - priority[i]) / width;
631
+ if (d > 1.0) d = 1.0;
632
+ distances[i] = d * request[i];
633
+ }
634
+
635
+ // Index of the current activated target
636
+ bool active[ALLOCATE_BY_PRIORITY_BUFSIZE] = {false};
637
+ active[0] = true;
638
+
639
+ // Index of the last activated target
640
+ size_t c_i = 0;
641
+
642
+ // Continue allocating until supply is exhausted
643
+ while (supply > _epsilon) {
644
+ // Check if there are any active targets left
645
+ bool any_active = false;
646
+ for (size_t i = 0; i < m; i++) {
647
+ if (active[i]) {
648
+ any_active = true;
649
+ break;
650
+ }
651
+ }
652
+ if (!any_active) {
653
+ break;
654
+ }
655
+
656
+ // Compute proportional allocation weights ("slopes") for active targets
657
+ double slopes[ALLOCATE_BY_PRIORITY_BUFSIZE];
658
+ double slope_sum = 0.0;
659
+
660
+ for (size_t i = 0; i < m; i++) {
661
+ if (active[i]) {
662
+ slopes[i] = request[i]; // weight based on requested amount
663
+ slope_sum += slopes[i];
664
+ } else {
665
+ slopes[i] = 0.0;
666
+ }
667
+ }
668
+
669
+ // Normalize slopes so total allocation proportion sums to 1
670
+ for (size_t i = 0; i < m; i++) {
671
+ slopes[i] /= slope_sum;
672
+ }
673
+
674
+ // Compute how much supply much be given to any target reach its request
675
+ double dx_next_top = NAN;
676
+
677
+ for (size_t i = 0; i < m; i++) {
678
+ if (active[i]) {
679
+ double val = (request[i] - out[i]) / slopes[i];
680
+ if (isnan(dx_next_top) || val < dx_next_top) {
681
+ dx_next_top = val;
682
+ }
683
+ }
684
+ }
685
+
686
+ // Compute how much supply is needed to activate the next target
687
+ // (last target will return nan)
688
+ double dx_next_start = (distances[c_i] - out[c_i]) / slopes[c_i];
689
+
690
+ // Determine next allocation step size:
691
+ // smallest of (next completion, next activation, remaining supply)
692
+ double dx = dx_next_top;
693
+
694
+ if (!isnan(dx_next_start) && dx_next_start < dx) {
695
+ dx = dx_next_start;
696
+ }
697
+ if (supply < dx) {
698
+ dx = supply;
699
+ }
700
+
701
+ // Distribute this increment of supply across active targets
702
+ for (size_t i = 0; i < m; i++) {
703
+ out[i] += slopes[i] * dx;
704
+ }
705
+
706
+ // If we reached the threshold to activate the next target
707
+ if (fabs(dx - dx_next_start) <= (1e-10 * fabs(dx_next_start) + 1e-16)) {
708
+ // A new target will start in the next loop
709
+ c_i++;
710
+
711
+ // Active the next targetif its request is different than 0
712
+ if (c_i < m) active[c_i] = true;
713
+ }
714
+
715
+ // If any targets have reached their requested amount, deactivate them
716
+ if (dx == dx_next_top) {
717
+ for (size_t i = 0; i < m; i++) {
718
+ if (fabs(out[i] - request[i]) <= 1e-12) {
719
+ active[i] = false;
720
+ }
721
+ }
722
+ }
723
+
724
+ // Reduce remaining supply
725
+ supply -= dx;
726
+ }
727
+
728
+ // Return the distributed supply in the original order
729
+ // adding to it again the request 0 if the where removed
730
+ for (size_t i = 0; i < m; i++) {
731
+ out_return[idx[i]] = out[i];
732
+ }
733
+
734
+ return out_return;
735
+ }
736
+
506
737
  //
507
738
  // DELAY FIXED
508
739
  //
package/src/c/vensim.h CHANGED
@@ -39,6 +39,7 @@ extern "C" {
39
39
 
40
40
 
41
41
  double* _ALLOCATE_AVAILABLE(double* requested_quantities, double* priority_profiles, double available_resource, size_t num_requesters);
42
+ double* _ALLOCATE_BY_PRIORITY(double* request, double* priority, double size, double width, double supply, size_t num_requesters);
42
43
  double _PULSE(double start, double width);
43
44
  double _PULSE_TRAIN(double start, double width, double interval, double end);
44
45
  double _RAMP(double slope, double start_time, double end_time);