diff --git a/models/arrays_cname/arrays_cname.dat b/models/arrays_cname/arrays_cname.dat index 8aa91ace..4ae53bc3 100644 --- a/models/arrays_cname/arrays_cname.dat +++ b/models/arrays_cname/arrays_cname.dat @@ -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 diff --git a/models/arrays_cname/arrays_cname.mdl b/models/arrays_cname/arrays_cname.mdl index 5427444e..cfe32687 100755 --- a/models/arrays_cname/arrays_cname.mdl +++ b/models/arrays_cname/arrays_cname.mdl @@ -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 diff --git a/src/EquationGen.js b/src/EquationGen.js index 9f0453ab..9ebb5daf 100644 --- a/src/EquationGen.js +++ b/src/EquationGen.js @@ -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`) } } } diff --git a/src/VariableReader.js b/src/VariableReader.js index cda9bf90..72412491 100644 --- a/src/VariableReader.js +++ b/src/VariableReader.js @@ -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 @@ -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 } @@ -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) } } }