Skip to content

Commit

Permalink
feat: add support for GAME function and for providing gaming inputs a…
Browse files Browse the repository at this point in the history
…t runtime (#505)

Fixes #483
  • Loading branch information
chrispcampbell authored Aug 16, 2024
1 parent fcea642 commit 338e91e
Show file tree
Hide file tree
Showing 25 changed files with 658 additions and 68 deletions.
2 changes: 0 additions & 2 deletions examples/house-game/model/houses.dat

This file was deleted.

7 changes: 4 additions & 3 deletions examples/house-game/model/houses.mdl
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ replacement houses = demolishing
~ house/Month
~ |

planning data ~~|
initial planning = INITIAL ( MAX( 0, replacement houses + (gap in houses / time to respond to gap) ) )
~ house/Month
~ |

planning = GET DATA BETWEEN TIMES(planning data, Time, -1)
planning = GAME(initial planning)
~ house/Month
~ Originally: GAME( MAX( 0, replacement houses + (gap in houses / time to respond to gap)) )
~ |

average house life = 600
Expand Down
2 changes: 1 addition & 1 deletion examples/house-game/packages/app/src/model/app-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export class AppModel {
}
]
}
const gameLookup = createLookupDef({ varName: 'planning data' }, this.gameLookupPoints)
const gameLookup = createLookupDef({ varName: 'planning game inputs' }, this.gameLookupPoints)
const lookups = [gameLookup]

// Set the "busy" flag (to put the UI into a non-editable state)
Expand Down
3 changes: 2 additions & 1 deletion examples/house-game/sde.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export async function config() {
'time to respond to gap'
],
outputs: ['number of houses required', 'houses completed'],
datFiles: ['../model/houses.dat']
bundleListing: true,
customLookups: ['planning game inputs']
}
},

Expand Down
17 changes: 17 additions & 0 deletions packages/cli/src/c/vensim.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,23 @@ double _LOOKUP_INVERT(Lookup* lookup, double y) {
return __lookup(lookup, y, true, Interpolate);
}

double _GAME(Lookup* lookup, double default_value) {
if (lookup == NULL || lookup->n <= 0) {
// The lookup is NULL or empty, so return the default value
return default_value;
}

double x0 = lookup->data[0];
if (_time < x0) {
// The current time is earlier than the first data point, so return the
// default value
return default_value;
}

// For all other cases, we can use `__lookup` with `Backward` mode
return __lookup(lookup, _time, false, Backward);
}

typedef struct {
double x;
int ind;
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/c/vensim.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ extern "C" {
#define _ARCTAN(x) atan(x)
#define _COS(x) cos(x)
#define _EXP(x) exp(x)
#define _GAME(x) (x)
#define _GAMMA_LN(x) lgamma(x)
#define _IF_THEN_ELSE(c, t, f) (bool_cond(c) ? (t) : (f))
#define _INTEG(value, rate) ((value) + (rate) * _time_step)
Expand Down Expand Up @@ -78,6 +77,8 @@ double __get_data_between_times(Lookup* lookup, double input, LookupMode mode);
#define _GET_DATA_MODE_TO_LOOKUP_MODE(mode) ((mode) >= 1) ? Forward : (((mode) <= -1) ? Backward : Interpolate)
#define _GET_DATA_BETWEEN_TIMES(lookup, x, mode) __get_data_between_times(lookup, x, _GET_DATA_MODE_TO_LOOKUP_MODE(mode))

double _GAME(Lookup* lookup, double default_value);

//
// DELAY FIXED
//
Expand Down
3 changes: 2 additions & 1 deletion packages/compile/src/_tests/test-support.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export interface Variable {
refId: string
varType: VariableType
// TODO: Remove empty string variant
varSubtype: '' | 'fixedDelay' | 'depreciation'
varSubtype: '' | 'fixedDelay' | 'depreciation' | 'gameInputs'
referencedFunctionNames?: string[]
referencedLookupVarNames?: string[]
references: string[]
Expand All @@ -83,6 +83,7 @@ export interface Variable {
delayTimeVarName: string
fixedDelayVarName: string
depreciationVarName: string
gameLookupVarName: string
includeInOutput: boolean
}

Expand Down
38 changes: 26 additions & 12 deletions packages/compile/src/generate/gen-code-c.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ describe('generateC (Vensim -> C)', () => {
b[DimA, DimB] = b data[DimA, DimB] ~~|
c data ~~|
c = c data ~~|
d[DimA] = GAME(x) ~~|
w = WITH LOOKUP(x, ( [(0,0)-(2,2)], (0,0),(0.1,0.01),(0.5,0.7),(1,1),(1.5,1.2),(2,1.3) )) ~~|
INITIAL TIME = 0 ~~|
FINAL TIME = 2 ~~|
Expand All @@ -97,7 +98,7 @@ describe('generateC (Vensim -> C)', () => {
const code = readInlineModelAndGenerateC(mdl, {
extData,
inputVarNames: ['input'],
outputVarNames: ['x', 'y', 'z', 'a[A1]', 'b[A2,B1]', 'c', 'w'],
outputVarNames: ['x', 'y', 'z', 'a[A1]', 'b[A2,B1]', 'c', 'd[A1]', 'w'],
customLookups: true,
customOutputs: true
})
Expand All @@ -109,9 +110,11 @@ Lookup* __lookup1;
Lookup* _a_data[2];
Lookup* _b_data[2][2];
Lookup* _c_data;
Lookup* _d_game_inputs[2];
double _a[2];
double _b[2][2];
double _c;
double _d[2];
double _final_time;
double _initial_time;
double _input;
Expand All @@ -123,7 +126,7 @@ double _y;
double _z;
// Internal variables
const int numOutputs = 7;
const int numOutputs = 8;
// Array dimensions
const size_t _dima[2] = { 0, 1 };
Expand Down Expand Up @@ -220,6 +223,10 @@ void evalAux0() {
_x = _input;
// w = WITH LOOKUP(x,([(0,0)-(2,2)],(0,0),(0.1,0.01),(0.5,0.7),(1,1),(1.5,1.2),(2,1.3)))
_w = _WITH_LOOKUP(_x, __lookup1);
// d[DimA] = GAME(x)
for (size_t i = 0; i < 2; i++) {
_d[i] = _GAME(_d_game_inputs[i], _x);
}
// y = :NOT: x
_y = !_x;
// z = ABS(y)
Expand Down Expand Up @@ -273,12 +280,15 @@ void replaceLookup(Lookup** lookup, double* points, size_t numPoints) {
void setLookup(size_t varIndex, size_t* subIndices, double* points, size_t numPoints) {
switch (varIndex) {
case 6:
replaceLookup(&_a_data[subIndices[0]], points, numPoints);
replaceLookup(&_d_game_inputs[subIndices[0]], points, numPoints);
break;
case 7:
replaceLookup(&_b_data[subIndices[0]][subIndices[1]], points, numPoints);
replaceLookup(&_a_data[subIndices[0]], points, numPoints);
break;
case 8:
replaceLookup(&_b_data[subIndices[0]][subIndices[1]], points, numPoints);
break;
case 9:
replaceLookup(&_c_data, points, numPoints);
break;
default:
Expand All @@ -288,7 +298,7 @@ void setLookup(size_t varIndex, size_t* subIndices, double* points, size_t numPo
}
const char* getHeader() {
return "x\\ty\\tz\\ta[A1]\\tb[A2,B1]\\tc\\tw";
return "x\\ty\\tz\\ta[A1]\\tb[A2,B1]\\tc\\td[A1]\\tw";
}
void storeOutputData() {
Expand All @@ -298,6 +308,7 @@ void storeOutputData() {
outputVar(_a[0]);
outputVar(_b[1][0]);
outputVar(_c);
outputVar(_d[0]);
outputVar(_w);
}
Expand All @@ -318,25 +329,28 @@ void storeOutput(size_t varIndex, size_t subIndex0, size_t subIndex1, size_t sub
case 5:
outputVar(_input);
break;
case 9:
case 10:
outputVar(_a[subIndex0]);
break;
case 10:
case 11:
outputVar(_b[subIndex0][subIndex1]);
break;
case 11:
case 12:
outputVar(_c);
break;
case 12:
case 13:
outputVar(_x);
break;
case 13:
case 14:
outputVar(_w);
break;
case 14:
case 15:
outputVar(_d[subIndex0]);
break;
case 16:
outputVar(_y);
break;
case 15:
case 17:
outputVar(_z);
break;
default:
Expand Down
Loading

0 comments on commit 338e91e

Please sign in to comment.