Skip to content

Commit

Permalink
fix: allow extra index subscripts in 2D const lists (#110)
Browse files Browse the repository at this point in the history
Fixes #109
  • Loading branch information
ToddFincannon authored Sep 27, 2021
1 parent bd3b3e8 commit f5494af
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 67 deletions.
36 changes: 36 additions & 0 deletions models/arrays_cname/arrays_cname.dat
Original file line number Diff line number Diff line change
Expand Up @@ -411,3 +411,39 @@ y[D4,A2]
0 42
y[D4,A3]
0 43
z[C1,A1,B1]
0 110
z[C1,A1,B2]
0 111
z[C1,A1,B3]
0 112
z[C1,A2,B1]
0 120
z[C1,A2,B2]
0 121
z[C1,A2,B3]
0 122
z[C1,A3,B1]
0 130
z[C1,A3,B2]
0 131
z[C1,A3,B3]
0 132
z[C2,A1,B1]
0 210
z[C2,A1,B2]
0 211
z[C2,A1,B3]
0 212
z[C2,A2,B1]
0 220
z[C2,A2,B2]
0 221
z[C2,A2,B3]
0 222
z[C2,A3,B1]
0 230
z[C2,A3,B2]
0 231
z[C2,A3,B3]
0 232
40 changes: 40 additions & 0 deletions models/arrays_cname/arrays_cname.mdl
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,47 @@ y[DimD,DimA]=
~ 2D constant array with dimensions not in normal order
|

z[C1, DimA, DimB]=
110, 111, 112;
120, 121, 122;
130, 131, 132;
~
~ 2D constant array with additional index subscript (1/2)
|

z[C2, DimA, DimB]=
210, 211, 212;
220, 221, 222;
230, 231, 232;
~
~ 2D constant array with additional index subscript (2/2)
|

INITIAL TIME = 0 ~~|
FINAL TIME = 1 ~~|
TIME STEP = 1 ~~|
SAVEPER = TIME STEP ~~|

\\\---/// Sketch information - do not modify anything except names
V300 Do not put anything below this section - it will be ignored
*View 1
$0-0-0,0,|0||0-0-0|0-0-0|0-0-0|0-0-0|0-0-0|0,0,100,0
///---\\\
:L<%^E!@
9:arrays_cname
15:0,0,0,0,0,0
19:100,0
27:2,
34:0,
5:FINAL TIME
35:Date
36:YYYY-MM-DD
37:2000
38:1
39:1
40:2
41:0
42:1
24:0
25:0
26:0
58 changes: 14 additions & 44 deletions src/EquationGen.js
Original file line number Diff line number Diff line change
Expand Up @@ -1029,51 +1029,21 @@ export default class EquationGen extends ModelReader {
// Emit a single constant into the expression code.
emitConstAtPos(0)
} else {
// Extract a single value from the const list by its index number.
// All const lists with > 1 value are separated on dimensions in the LHS.
// The LHS of a separated variable here will contain only index subscripts.
let numDims = this.var.separationDims.length
if (numDims === 1) {
// Find the index that is in the separation dimension.
let sepDim = sub(this.var.separationDims[0])
for (let ind of this.var.subscripts) {
let i = sepDim.value.indexOf(ind)
if (i >= 0) {
// Emit the constant at this position in the constant list.
emitConstAtPos(i)
break
}
}
} else if (numDims === 2) {
// Calculate an index into a flattened array by converting the indices to numeric form and looking them up
// in a C name array listed in the same Vensim order as the constant array in the model.
let cVarName
let modelLHSReader = new ModelLHSReader()
modelLHSReader.read(this.var.modelLHS)
let cNames = modelLHSReader.names().map(Model.cName)
// Visit dims in normal order. Find the ind in the dim. Compose the C array expression with numeric indices.
for (let i = 0; i < this.var.separationDims.length; i++) {
const dim = this.var.separationDims[i]
const sepDim = sub(dim)
const ind = this.var.subscripts[i]
const j = sepDim.value.indexOf(ind)
if (j >= 0) {
const indexNum = sub(ind).value
if (!cVarName) {
cVarName = `${this.var.varName}[${indexNum}]`
} else {
cVarName += `[${indexNum}]`
}
}
}
// Find the position of the constant in Vensim order from the expanded LHS var list.
let constPos = R.indexOf(cVarName, cNames)
if (constPos >= 0) {
emitConstAtPos(constPos)
// console.error(`${this.var.refId} position = ${constPos}`)
} else {
console.error(`${this.var.refId}${cVarName} not found in C names`)
}
// The LHS of a separated variable here will contain only index subscripts in normal order.
// Calculate an index into a flattened array by converting the indices to numeric form and looking them up
// in a C name array listed in the same Vensim order as the constant array in the model.
let modelLHSReader = new ModelLHSReader()
modelLHSReader.read(this.var.modelLHS)
let cNames = modelLHSReader.names().map(Model.cName)
let cVarName = this.var.varName + R.map(indName => `[${sub(indName).value}]`, this.var.subscripts).join('')
// Find the position of the constant in Vensim order from the expanded LHS var list.
let constPos = R.indexOf(cVarName, cNames)
if (constPos >= 0) {
emitConstAtPos(constPos)
// console.error(`${this.var.refId} position = ${constPos}`)
} else {
console.error(`ERROR: const list element ${this.var.refId}${cVarName} not found in C names`)
}
}
}
Expand Down
45 changes: 22 additions & 23 deletions src/VariableReader.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import ModelReader from './ModelReader.js'
import Model from './Model.js'
import Variable from './Variable.js'
import { sub, isDimension, isIndex, normalizeSubscripts } from './Subscript.js'
import { canonicalName, vlog, replaceInArray, strlist } from './Helpers.js'
import { canonicalName, vlog, replaceInArray, strlist, cartesianProductOf } from './Helpers.js'

// Set true to print extra debugging information to stderr.
const DEBUG_LOG = false
Expand Down Expand Up @@ -116,12 +116,10 @@ export default class VariableReader extends ModelReader {
}
return skip
}
let skipExpansion2 = (indName0, indName1) => {
let skipExpansion2 = indNames => {
let skip = false
for (const exceptSubs of this.var.exceptSubscripts) {
let exceptSub0 = exceptSubs[0]
let exceptSub1 = exceptSubs[1]
if (isException(indName0, exceptSub0) && isException(indName1, exceptSub1)) {
for (let exceptSubs of this.var.exceptSubscripts) {
if (isException(indNames[0], exceptSubs[0]) && isException(indNames[1], exceptSubs[1])) {
skip = true
break
}
Expand Down Expand Up @@ -150,24 +148,25 @@ export default class VariableReader extends ModelReader {
`expanding ${this.var.varName}[${strlist(this.var.subscripts)}] subscripts`,
strlist(this.var.subscripts)
)
let expansionSubscript0 = this.var.subscripts[0]
let expansionSubscript1 = this.var.subscripts[1]
let expansionSubs0 = isIndex(expansionSubscript0)
? [sub(expansionSubscript0).name]
: sub(expansionSubscript0).value
let expansionSubs1 = isIndex(expansionSubscript1)
? [sub(expansionSubscript1).name]
: sub(expansionSubscript1).value
for (let indName0 of expansionSubs0) {
for (let indName1 of expansionSubs1) {
if (!skipExpansion2(indName0, indName1)) {
let v = new Variable(this.var.eqnCtx)
v.varName = this.var.varName
v.subscripts = [indName0, indName1]
v.separationDims = [expansionSubscript0, expansionSubscript1]
debugLog(` ${strlist(v.subscripts)}`)
this.expandedVars.push(v)
// Find the subscripts we need to expand.
let separationDims = []
for (let i = 0; i < expanding.length; i++) {
if (expanding[i]) {
separationDims.push(this.var.subscripts[i])
}
}
let expansionSubs = separationDims.map(s => (isIndex(s) ? [sub(s).name] : sub(s).value))
for (let indNames of cartesianProductOf(expansionSubs)) {
if (!skipExpansion2(indNames)) {
let v = new Variable(this.var.eqnCtx)
v.varName = this.var.varName
v.subscripts = []
for (let i = 0; i < expanding.length; i++) {
v.subscripts.push(expanding[i] ? indNames.shift() : this.var.subscripts[i])
}
v.separationDims = separationDims
debugLog(` ${strlist(v.subscripts)}`)
this.expandedVars.push(v)
}
}
}
Expand Down

0 comments on commit f5494af

Please sign in to comment.