From d92343e0806f228537f905956d053777accf9e97 Mon Sep 17 00:00:00 2001 From: Todd Fincannon Date: Mon, 27 Sep 2021 15:45:25 -0700 Subject: [PATCH] fix: expand variables allowing for any number of indices in EXCEPT clause (#118) Fixes #117 --- models/except/except.dat | 44 ++++++++++++++++++ models/except/except.mdl | 11 ++++- src/Helpers.js | 2 +- src/VariableReader.js | 96 +++++++++++----------------------------- 4 files changed, 79 insertions(+), 74 deletions(-) diff --git a/models/except/except.dat b/models/except/except.dat index b8532b91..543c4c7c 100644 --- a/models/except/except.dat +++ b/models/except/except.dat @@ -42,6 +42,50 @@ e[A3,C2] 0 5 e[A3,C3] 0 5 +except3[E1,F1,G1] +0 3 +except3[E1,F1,G2] +0 3 +except3[E1,F2,G1] +0 3 +except3[E1,F2,G2] +0 3 +except3[E2,F1,G1] +0 3 +except3[E2,F1,G2] +0 3 +except3[E2,F2,G1] +0 3 +except4[E1,F1,G1,H1] +0 4 +except4[E1,F1,G1,H2] +0 4 +except4[E1,F1,G2,H1] +0 4 +except4[E1,F1,G2,H2] +0 4 +except4[E1,F2,G1,H1] +0 4 +except4[E1,F2,G1,H2] +0 4 +except4[E1,F2,G2,H1] +0 4 +except4[E1,F2,G2,H2] +0 4 +except4[E2,F1,G1,H1] +0 4 +except4[E2,F1,G1,H2] +0 4 +except4[E2,F1,G2,H1] +0 4 +except4[E2,F1,G2,H2] +0 4 +except4[E2,F2,G1,H1] +0 4 +except4[E2,F2,G1,H2] +0 4 +except4[E2,F2,G2,H1] +0 4 f[A1,C1] 0 6 FINAL TIME diff --git a/models/except/except.mdl b/models/except/except.mdl index c1dcc2b5..a04e43aa 100755 --- a/models/except/except.mdl +++ b/models/except/except.mdl @@ -5,6 +5,10 @@ SubA2: A2 ~~| DimC: C1, C2, C3 ~~| SubC: C2, C3 ~~| DimD: D1, D2 -> (DimA: SubA, A1) ~~| +DimE: E1, E2 ~~| +DimF: F1, F2 ~~| +DimG: G1, G2 ~~| +DimH: H1, H2 ~~| a[DimA] = 1 ~~| b[SubA] = 2 ~~| @@ -14,6 +18,8 @@ e[DimA, SubC] = 5 ~~| f[A1, C1] = 6 ~~| g[DimA] :EXCEPT: [A1] = 7 ~~| h[DimA] :EXCEPT: [SubA] = 8 ~~| +j[DimD] = 10, 20 ~~| +k[DimA] :EXCEPT: [A1] = a[DimA] + j[DimD] ~~| o[SubA] :EXCEPT: [SubA2] = 9 ~~| p[DimA, DimC] :EXCEPT: [A1, C1] = 10 ~~| q[DimA, DimC] :EXCEPT: [SubA, C2] = 11 ~~| @@ -26,8 +32,9 @@ v[SubA] :EXCEPT: [A1] = a[SubA] ~~| w[DimA] :EXCEPT: [SubA] = a[DimA] ~~| x[DimA] :EXCEPT: [SubA] = c[DimA, C1] ~~| y[SubA, SubC] :EXCEPT: [A3, C3] = c[SubA, SubC] ~~| -j[DimD] = 10, 20 ~~| -k[DimA] :EXCEPT: [A1] = a[DimA] + j[DimD] ~~| + +except3[DimE, DimF, DimG] :EXCEPT: [E2, F2, G2] = 3 ~~| +except4[DimE, DimF, DimG, DimH] :EXCEPT: [E2, F2, G2, H2] = 4 ~~| INITIAL TIME = 0 ~~| FINAL TIME = 1 ~~| diff --git a/src/Helpers.js b/src/Helpers.js index 5e586ee5..71e286b7 100644 --- a/src/Helpers.js +++ b/src/Helpers.js @@ -128,7 +128,7 @@ export let listConcat = (a, x, addSpaces = false) => { export let cdbl = x => { // Convert a number into a C double constant. let s = x.toString() - if (!s.includes('.') && !s.includes('e')) { + if (!s.includes('.') && !s.toLowerCase().includes('e')) { s += '.0' } return s diff --git a/src/VariableReader.js b/src/VariableReader.js index 72412491..486f0b94 100644 --- a/src/VariableReader.js +++ b/src/VariableReader.js @@ -94,80 +94,34 @@ export default class VariableReader extends ModelReader { } expandVars(expanding) { // Expand the indicated subscripts into variable objects in the expandedVars list. - let isException = (indName, exceptSub) => { - // Compare the LHS index name directly to an exception index subscript. - let result = false - if (isIndex(exceptSub)) { - result = indName === exceptSub - } else if (isDimension(exceptSub)) { - result = R.contains(indName, sub(exceptSub).value) - } - return result - } - let skipExpansion = (indName, expansionPos) => { - // Look for this index in each of the exception subscript lists at expansionsPos. - let skip = false - for (const exceptSubs of this.var.exceptSubscripts) { - let exceptSub = exceptSubs[expansionPos] - if (isException(indName, exceptSub)) { - skip = true - break - } - } - return skip - } - let skipExpansion2 = indNames => { - let skip = false - for (let exceptSubs of this.var.exceptSubscripts) { - if (isException(indNames[0], exceptSubs[0]) && isException(indNames[1], exceptSubs[1])) { - skip = true - break + debugLog(`expanding ${this.var.varName}[${strlist(this.var.subscripts)}] subscripts`, strlist(this.var.subscripts)) + let expansion = [] + let separationDims = [] + // Construct an array with an array at each subscript position. If the subscript is expanded at that position, + // it will become an array of indices. Otherwise, it remains an index or dimension as a single-valued array. + for (let i = 0; i < this.var.subscripts.length; i++) { + let subscript = this.var.subscripts[i] + let value + if (expanding[i]) { + separationDims.push(subscript) + if (isDimension(subscript)) { + value = sub(subscript).value } } - return skip + expansion.push(value || [subscript]) } - let numSubscriptsToExpand = expanding.reduce((n, x) => n + (!!x ? 1 : 0), 0) - if (numSubscriptsToExpand === 1) { - let expansionPos = expanding[0] ? 0 : 1 - let expansionSubscript = this.var.subscripts[expansionPos] - // An exception subscript can be an index. Expand on a single index or on all indices of a dimension. - let expansionSubs = isIndex(expansionSubscript) ? [sub(expansionSubscript).name] : sub(expansionSubscript).value - debugLog(`expanding ${this.var.varName}[${strlist(this.var.subscripts)}] subscript`, expansionSubscript) - for (let indName of expansionSubs) { - if (!skipExpansion(indName, expansionPos)) { - let v = new Variable(this.var.eqnCtx) - v.varName = this.var.varName - v.subscripts = replaceInArray(expansionSubscript, indName, this.var.subscripts) - v.separationDims.push(expansionSubscript) - debugLog(` ${strlist(v.subscripts)}`) - this.expandedVars.push(v) - } - } - } else if (numSubscriptsToExpand === 2) { - debugLog( - `expanding ${this.var.varName}[${strlist(this.var.subscripts)}] subscripts`, - strlist(this.var.subscripts) - ) - // 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) - } + // Generate an array of fully expanded subscripts. + let expandedSubs = cartesianProductOf(expansion) + for (let subs of expandedSubs) { + // Skip expansions that match exception subscripts. + if (!R.any(e => R.equals(e, subs), this.var.exceptSubscripts)) { + // Add a new variable to the expanded vars. + let v = new Variable(this.var.eqnCtx) + v.varName = this.var.varName + v.subscripts = subs + v.separationDims = separationDims + debugLog(` ${strlist(v.subscripts)}`) + this.expandedVars.push(v) } } }