@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 +2 -2
- package/src/c/vensim.c +231 -0
- package/src/c/vensim.h +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdeverywhere/cli",
|
|
3
|
-
"version": "0.7.
|
|
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.
|
|
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);
|