|
|
@ -119,138 +119,141 @@ namespace storm { |
|
|
|
} |
|
|
|
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::equals(Dd<DdType::CUDD> const& other) const { |
|
|
|
Dd<DdType::CUDD> result(*this); |
|
|
|
result.cuddAdd = result.cuddAdd.Equals(other.getCuddAdd()); |
|
|
|
return result; |
|
|
|
std::set<std::string> metaVariableNames(this->getContainedMetaVariableNames()); |
|
|
|
metaVariableNames.insert(other.getContainedMetaVariableNames().begin(), other.getContainedMetaVariableNames().end()); |
|
|
|
return Dd<DdType::CUDD>(this->getDdManager(), this->getCuddAdd().Equals(other.getCuddAdd()), metaVariableNames); |
|
|
|
} |
|
|
|
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::notEquals(Dd<DdType::CUDD> const& other) const { |
|
|
|
Dd<DdType::CUDD> result(*this); |
|
|
|
result.cuddAdd = result.cuddAdd.NotEquals(other.getCuddAdd()); |
|
|
|
return result; |
|
|
|
std::set<std::string> metaVariableNames(this->getContainedMetaVariableNames()); |
|
|
|
metaVariableNames.insert(other.getContainedMetaVariableNames().begin(), other.getContainedMetaVariableNames().end()); |
|
|
|
return Dd<DdType::CUDD>(this->getDdManager(), this->getCuddAdd().NotEquals(other.getCuddAdd()), metaVariableNames); |
|
|
|
} |
|
|
|
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::less(Dd<DdType::CUDD> const& other) const { |
|
|
|
Dd<DdType::CUDD> result(*this); |
|
|
|
result.cuddAdd = result.cuddAdd.LessThan(other.getCuddAdd()); |
|
|
|
return result; |
|
|
|
std::set<std::string> metaVariableNames(this->getContainedMetaVariableNames()); |
|
|
|
metaVariableNames.insert(other.getContainedMetaVariableNames().begin(), other.getContainedMetaVariableNames().end()); |
|
|
|
return Dd<DdType::CUDD>(this->getDdManager(), this->getCuddAdd().LessThan(other.getCuddAdd()), metaVariableNames); |
|
|
|
} |
|
|
|
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::lessOrEqual(Dd<DdType::CUDD> const& other) const { |
|
|
|
Dd<DdType::CUDD> result(*this); |
|
|
|
result.cuddAdd = result.cuddAdd.LessThanOrEqual(other.getCuddAdd()); |
|
|
|
return result; |
|
|
|
std::set<std::string> metaVariableNames(this->getContainedMetaVariableNames()); |
|
|
|
metaVariableNames.insert(other.getContainedMetaVariableNames().begin(), other.getContainedMetaVariableNames().end()); |
|
|
|
return Dd<DdType::CUDD>(this->getDdManager(), this->getCuddAdd().LessThanOrEqual(other.getCuddAdd()), metaVariableNames); |
|
|
|
} |
|
|
|
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::greater(Dd<DdType::CUDD> const& other) const { |
|
|
|
Dd<DdType::CUDD> result(*this); |
|
|
|
result.cuddAdd = result.cuddAdd.GreaterThan(other.getCuddAdd()); |
|
|
|
return result; |
|
|
|
std::set<std::string> metaVariableNames(this->getContainedMetaVariableNames()); |
|
|
|
metaVariableNames.insert(other.getContainedMetaVariableNames().begin(), other.getContainedMetaVariableNames().end()); |
|
|
|
return Dd<DdType::CUDD>(this->getDdManager(), this->getCuddAdd().GreaterThan(other.getCuddAdd()), metaVariableNames); |
|
|
|
} |
|
|
|
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::greaterOrEqual(Dd<DdType::CUDD> const& other) const { |
|
|
|
Dd<DdType::CUDD> result(*this); |
|
|
|
result.cuddAdd = result.cuddAdd.GreaterThanOrEqual(other.getCuddAdd()); |
|
|
|
return result; |
|
|
|
std::set<std::string> metaVariableNames(this->getContainedMetaVariableNames()); |
|
|
|
metaVariableNames.insert(other.getContainedMetaVariableNames().begin(), other.getContainedMetaVariableNames().end()); |
|
|
|
return Dd<DdType::CUDD>(this->getDdManager(), this->getCuddAdd().GreaterThanOrEqual(other.getCuddAdd()), metaVariableNames); |
|
|
|
} |
|
|
|
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::minimum(Dd<DdType::CUDD> const& other) const { |
|
|
|
std::set<std::string> metaVariableNames(this->getContainedMetaVariableNames()); |
|
|
|
metaVariableNames.insert(other.getContainedMetaVariableNames().begin(), other.getContainedMetaVariableNames().end()); |
|
|
|
|
|
|
|
return Dd<DdType::CUDD>(this->getDdManager(), this->getCuddAdd().Minimum(other.getCuddAdd()), metaVariableNames); |
|
|
|
} |
|
|
|
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::maximum(Dd<DdType::CUDD> const& other) const { |
|
|
|
std::set<std::string> metaVariableNames(this->getContainedMetaVariableNames()); |
|
|
|
metaVariableNames.insert(other.getContainedMetaVariableNames().begin(), other.getContainedMetaVariableNames().end()); |
|
|
|
|
|
|
|
return Dd<DdType::CUDD>(this->getDdManager(), this->getCuddAdd().Maximum(other.getCuddAdd()), metaVariableNames); |
|
|
|
} |
|
|
|
|
|
|
|
void Dd<DdType::CUDD>::existsAbstract(std::set<std::string> const& metaVariableNames) { |
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::existsAbstract(std::set<std::string> const& metaVariableNames) const { |
|
|
|
Dd<DdType::CUDD> cubeDd(this->getDdManager()->getOne()); |
|
|
|
|
|
|
|
std::set<std::string> newMetaVariables = this->getContainedMetaVariableNames(); |
|
|
|
for (auto const& metaVariableName : metaVariableNames) { |
|
|
|
// First check whether the DD contains the meta variable and erase it, if this is the case.
|
|
|
|
if (!this->containsMetaVariable(metaVariableName)) { |
|
|
|
throw storm::exceptions::InvalidArgumentException() << "Cannot abstract from meta variable that is not present in the DD."; |
|
|
|
} |
|
|
|
this->getContainedMetaVariableNames().erase(metaVariableName); |
|
|
|
newMetaVariables.erase(metaVariableName); |
|
|
|
|
|
|
|
DdMetaVariable<DdType::CUDD> const& metaVariable = this->getDdManager()->getMetaVariable(metaVariableName); |
|
|
|
cubeDd *= metaVariable.getCube(); |
|
|
|
} |
|
|
|
|
|
|
|
this->cuddAdd = this->cuddAdd.OrAbstract(cubeDd.getCuddAdd()); |
|
|
|
return Dd<DdType::CUDD>(this->getDdManager(), this->cuddAdd.OrAbstract(cubeDd.getCuddAdd()), newMetaVariables); |
|
|
|
} |
|
|
|
|
|
|
|
void Dd<DdType::CUDD>::universalAbstract(std::set<std::string> const& metaVariableNames) { |
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::universalAbstract(std::set<std::string> const& metaVariableNames) const { |
|
|
|
Dd<DdType::CUDD> cubeDd(this->getDdManager()->getOne()); |
|
|
|
|
|
|
|
std::set<std::string> newMetaVariables = this->getContainedMetaVariableNames(); |
|
|
|
for (auto const& metaVariableName : metaVariableNames) { |
|
|
|
// First check whether the DD contains the meta variable and erase it, if this is the case.
|
|
|
|
if (!this->containsMetaVariable(metaVariableName)) { |
|
|
|
throw storm::exceptions::InvalidArgumentException() << "Cannot abstract from meta variable that is not present in the DD."; |
|
|
|
} |
|
|
|
this->getContainedMetaVariableNames().erase(metaVariableName); |
|
|
|
newMetaVariables.erase(metaVariableName); |
|
|
|
|
|
|
|
DdMetaVariable<DdType::CUDD> const& metaVariable = this->getDdManager()->getMetaVariable(metaVariableName); |
|
|
|
cubeDd *= metaVariable.getCube(); |
|
|
|
} |
|
|
|
|
|
|
|
this->cuddAdd = this->cuddAdd.UnivAbstract(cubeDd.getCuddAdd()); |
|
|
|
return Dd<DdType::CUDD>(this->getDdManager(), this->cuddAdd.UnivAbstract(cubeDd.getCuddAdd()), newMetaVariables); |
|
|
|
} |
|
|
|
|
|
|
|
void Dd<DdType::CUDD>::sumAbstract(std::set<std::string> const& metaVariableNames) { |
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::sumAbstract(std::set<std::string> const& metaVariableNames) const { |
|
|
|
Dd<DdType::CUDD> cubeDd(this->getDdManager()->getOne()); |
|
|
|
|
|
|
|
std::set<std::string> newMetaVariables = this->getContainedMetaVariableNames(); |
|
|
|
for (auto const& metaVariableName : metaVariableNames) { |
|
|
|
// First check whether the DD contains the meta variable and erase it, if this is the case.
|
|
|
|
if (!this->containsMetaVariable(metaVariableName)) { |
|
|
|
throw storm::exceptions::InvalidArgumentException() << "Cannot abstract from meta variable that is not present in the DD."; |
|
|
|
} |
|
|
|
this->getContainedMetaVariableNames().erase(metaVariableName); |
|
|
|
newMetaVariables.erase(metaVariableName); |
|
|
|
|
|
|
|
DdMetaVariable<DdType::CUDD> const& metaVariable = this->getDdManager()->getMetaVariable(metaVariableName); |
|
|
|
cubeDd *= metaVariable.getCube(); |
|
|
|
} |
|
|
|
|
|
|
|
this->cuddAdd = this->cuddAdd.ExistAbstract(cubeDd.getCuddAdd()); |
|
|
|
return Dd<DdType::CUDD>(this->getDdManager(), this->cuddAdd.ExistAbstract(cubeDd.getCuddAdd()), newMetaVariables); |
|
|
|
} |
|
|
|
|
|
|
|
void Dd<DdType::CUDD>::minAbstract(std::set<std::string> const& metaVariableNames) { |
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::minAbstract(std::set<std::string> const& metaVariableNames) const { |
|
|
|
Dd<DdType::CUDD> cubeDd(this->getDdManager()->getOne()); |
|
|
|
|
|
|
|
std::set<std::string> newMetaVariables = this->getContainedMetaVariableNames(); |
|
|
|
for (auto const& metaVariableName : metaVariableNames) { |
|
|
|
// First check whether the DD contains the meta variable and erase it, if this is the case.
|
|
|
|
if (!this->containsMetaVariable(metaVariableName)) { |
|
|
|
throw storm::exceptions::InvalidArgumentException() << "Cannot abstract from meta variable that is not present in the DD."; |
|
|
|
} |
|
|
|
this->getContainedMetaVariableNames().erase(metaVariableName); |
|
|
|
newMetaVariables.erase(metaVariableName); |
|
|
|
|
|
|
|
DdMetaVariable<DdType::CUDD> const& metaVariable = this->getDdManager()->getMetaVariable(metaVariableName); |
|
|
|
cubeDd *= metaVariable.getCube(); |
|
|
|
} |
|
|
|
|
|
|
|
this->cuddAdd = this->cuddAdd.MinAbstract(cubeDd.getCuddAdd()); |
|
|
|
return Dd<DdType::CUDD>(this->getDdManager(), this->cuddAdd.MinAbstract(cubeDd.getCuddAdd()), newMetaVariables); |
|
|
|
} |
|
|
|
|
|
|
|
void Dd<DdType::CUDD>::maxAbstract(std::set<std::string> const& metaVariableNames) { |
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::maxAbstract(std::set<std::string> const& metaVariableNames) const { |
|
|
|
Dd<DdType::CUDD> cubeDd(this->getDdManager()->getOne()); |
|
|
|
|
|
|
|
std::set<std::string> newMetaVariables = this->getContainedMetaVariableNames(); |
|
|
|
for (auto const& metaVariableName : metaVariableNames) { |
|
|
|
// First check whether the DD contains the meta variable and erase it, if this is the case.
|
|
|
|
if (!this->containsMetaVariable(metaVariableName)) { |
|
|
|
throw storm::exceptions::InvalidArgumentException() << "Cannot abstract from meta variable that is not present in the DD."; |
|
|
|
} |
|
|
|
this->getContainedMetaVariableNames().erase(metaVariableName); |
|
|
|
newMetaVariables.erase(metaVariableName); |
|
|
|
|
|
|
|
DdMetaVariable<DdType::CUDD> const& metaVariable = this->getDdManager()->getMetaVariable(metaVariableName); |
|
|
|
cubeDd *= metaVariable.getCube(); |
|
|
|
} |
|
|
|
|
|
|
|
this->cuddAdd = this->cuddAdd.MaxAbstract(cubeDd.getCuddAdd()); |
|
|
|
return Dd<DdType::CUDD>(this->getDdManager(), this->cuddAdd.MaxAbstract(cubeDd.getCuddAdd()), newMetaVariables); |
|
|
|
} |
|
|
|
|
|
|
|
bool Dd<DdType::CUDD>::equalModuloPrecision(Dd<DdType::CUDD> const& other, double precision, bool relative) const { |
|
|
@ -410,7 +413,7 @@ namespace storm { |
|
|
|
} |
|
|
|
|
|
|
|
Dd<DdType::CUDD> value = *this * valueEncoding; |
|
|
|
value.sumAbstract(this->getContainedMetaVariableNames()); |
|
|
|
value = value.sumAbstract(this->getContainedMetaVariableNames()); |
|
|
|
return static_cast<double>(Cudd_V(value.getCuddAdd().getNode())); |
|
|
|
} |
|
|
|
|
|
|
@ -430,18 +433,19 @@ namespace storm { |
|
|
|
return static_cast<uint_fast64_t>(this->getCuddAdd().NodeReadIndex()); |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<double> Dd<DdType::CUDD>::toDoubleVector() const { |
|
|
|
return this->toDoubleVector(Odd<DdType::CUDD>(*this)); |
|
|
|
std::vector<double> Dd<DdType::CUDD>::toVector() const { |
|
|
|
return this->toVector(Odd<DdType::CUDD>(*this)); |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<double> Dd<DdType::CUDD>::toDoubleVector(Odd<DdType::CUDD> const& odd) const { |
|
|
|
std::vector<double> Dd<DdType::CUDD>::toVector(Odd<DdType::CUDD> const& odd) const { |
|
|
|
std::vector<double> result(odd.getTotalOffset()); |
|
|
|
std::vector<uint_fast64_t> ddVariableIndices = this->getSortedVariableIndices(); |
|
|
|
toDoubleVectorRec(this->getCuddAdd().getNode(), result, odd, 0, ddVariableIndices.size(), 0, ddVariableIndices); |
|
|
|
toVectorRec(this->getCuddAdd().getNode(), result, odd, 0, ddVariableIndices.size(), 0, ddVariableIndices); |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
void Dd<DdType::CUDD>::toDoubleVectorRec(DdNode const* dd, std::vector<double>& result, Odd<DdType::CUDD> const& odd, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, std::vector<uint_fast64_t> const& ddVariableIndices) const { |
|
|
|
void Dd<DdType::CUDD>::toVectorRec(DdNode const* dd, std::vector<double>& result, Odd<DdType::CUDD> const& odd, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, std::vector<uint_fast64_t> const& ddVariableIndices) const { |
|
|
|
// For the empty DD, we do not need to add any entries.
|
|
|
|
if (dd == this->getDdManager()->getZero().getCuddAdd().getNode()) { |
|
|
|
return; |
|
|
|
} |
|
|
@ -452,12 +456,92 @@ namespace storm { |
|
|
|
} else if (ddVariableIndices[currentLevel] < dd->index) { |
|
|
|
// If we skipped a level, we need to enumerate the explicit entries for the case in which the bit is set
|
|
|
|
// and for the one in which it is not set.
|
|
|
|
toDoubleVectorRec(dd, result, odd.getElseSuccessor(), currentLevel + 1, maxLevel, currentOffset, ddVariableIndices); |
|
|
|
toDoubleVectorRec(dd, result, odd.getThenSuccessor(), currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), ddVariableIndices); |
|
|
|
toVectorRec(dd, result, odd.getElseSuccessor(), currentLevel + 1, maxLevel, currentOffset, ddVariableIndices); |
|
|
|
toVectorRec(dd, result, odd.getThenSuccessor(), currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), ddVariableIndices); |
|
|
|
} else { |
|
|
|
// Otherwise, we simply recursively call the function for both (different) cases.
|
|
|
|
toDoubleVectorRec(Cudd_E(dd), result, odd.getElseSuccessor(), currentLevel + 1, maxLevel, currentOffset, ddVariableIndices); |
|
|
|
toDoubleVectorRec(Cudd_T(dd), result, odd.getThenSuccessor(), currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), ddVariableIndices); |
|
|
|
toVectorRec(Cudd_E(dd), result, odd.getElseSuccessor(), currentLevel + 1, maxLevel, currentOffset, ddVariableIndices); |
|
|
|
toVectorRec(Cudd_T(dd), result, odd.getThenSuccessor(), currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), ddVariableIndices); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
storm::storage::SparseMatrix<double> Dd<DdType::CUDD>::toMatrix() const { |
|
|
|
std::set<std::string> rowVariables; |
|
|
|
std::set<std::string> columnVariables; |
|
|
|
std::vector<uint_fast64_t> ddRowVariableIndices; |
|
|
|
std::vector<uint_fast64_t> ddColumnVariableIndices; |
|
|
|
|
|
|
|
for (auto const& variableName : this->getContainedMetaVariableNames()) { |
|
|
|
DdMetaVariable<DdType::CUDD> const& metaVariable = this->getDdManager()->getMetaVariable(variableName); |
|
|
|
if (variableName.size() > 0 && variableName.back() == '\'') { |
|
|
|
columnVariables.insert(variableName); |
|
|
|
for (auto const& ddVariable : metaVariable.getDdVariables()) { |
|
|
|
ddColumnVariableIndices.push_back(ddVariable.getIndex()); |
|
|
|
} |
|
|
|
} else { |
|
|
|
rowVariables.insert(variableName); |
|
|
|
for (auto const& ddVariable : metaVariable.getDdVariables()) { |
|
|
|
ddRowVariableIndices.push_back(ddVariable.getIndex()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Odd<DdType::CUDD> columnOdd(this->existsAbstract(rowVariables)); |
|
|
|
Odd<DdType::CUDD> rowOdd(this->existsAbstract(columnVariables)); |
|
|
|
|
|
|
|
storm::storage::SparseMatrixBuilder<double> builder; |
|
|
|
toMatrixRec(this->getCuddAdd().getNode(), builder, rowOdd, columnOdd, 0, 0, ddRowVariableIndices.size() + ddColumnVariableIndices.size(), 0, 0, ddRowVariableIndices, ddColumnVariableIndices); |
|
|
|
return builder.build(); |
|
|
|
} |
|
|
|
|
|
|
|
void Dd<DdType::CUDD>::toMatrixRec(DdNode const* dd, storm::storage::SparseMatrixBuilder<double>& builder, Odd<DdType::CUDD> const& rowOdd, Odd<DdType::CUDD> const& columnOdd, uint_fast64_t currentRowLevel, uint_fast64_t currentColumnLevel, uint_fast64_t maxLevel, uint_fast64_t currentRowOffset, uint_fast64_t currentColumnOffset, std::vector<uint_fast64_t> const& ddRowVariableIndices, std::vector<uint_fast64_t> const& ddColumnVariableIndices) const { |
|
|
|
// FIXME: this method currently assumes a strict interleaved order, which does not seem necessary.
|
|
|
|
|
|
|
|
// For the empty DD, we do not need to add any entries.
|
|
|
|
if (dd == this->getDdManager()->getZero().getCuddAdd().getNode()) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// If we are at the maximal level, the value to be set is stored as a constant in the DD.
|
|
|
|
if (currentRowLevel + currentColumnLevel == maxLevel) { |
|
|
|
builder.addNextValue(currentRowOffset, currentColumnOffset, Cudd_V(dd)); |
|
|
|
} else { |
|
|
|
DdNode const* elseElse; |
|
|
|
DdNode const* elseThen; |
|
|
|
DdNode const* thenElse; |
|
|
|
DdNode const* thenThen; |
|
|
|
|
|
|
|
if (ddColumnVariableIndices[currentColumnLevel] < dd->index) { |
|
|
|
elseElse = elseThen = thenElse = thenThen = dd; |
|
|
|
} else if (ddRowVariableIndices[currentColumnLevel] < dd->index) { |
|
|
|
elseElse = thenElse = Cudd_E(dd); |
|
|
|
elseThen = thenThen = Cudd_T(dd); |
|
|
|
} else { |
|
|
|
DdNode const* elseNode = Cudd_E(dd); |
|
|
|
if (ddColumnVariableIndices[currentColumnLevel] < elseNode->index) { |
|
|
|
elseElse = elseThen = elseNode; |
|
|
|
} else { |
|
|
|
elseElse = Cudd_E(elseNode); |
|
|
|
elseThen = Cudd_T(elseNode); |
|
|
|
} |
|
|
|
|
|
|
|
DdNode const* thenNode = Cudd_T(dd); |
|
|
|
if (ddColumnVariableIndices[currentColumnLevel] < thenNode->index) { |
|
|
|
thenElse = thenThen = thenNode; |
|
|
|
} else { |
|
|
|
thenElse = Cudd_E(thenNode); |
|
|
|
thenThen = Cudd_T(thenNode); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Visit else-else.
|
|
|
|
toMatrixRec(elseElse, builder, rowOdd.getElseSuccessor(), columnOdd.getElseSuccessor(), currentRowLevel + 1, currentColumnLevel + 1, maxLevel, currentRowOffset, currentColumnOffset, ddRowVariableIndices, ddColumnVariableIndices); |
|
|
|
// Visit else-then.
|
|
|
|
toMatrixRec(elseThen, builder, rowOdd.getElseSuccessor(), columnOdd.getThenSuccessor(), currentRowLevel + 1, currentColumnLevel + 1, maxLevel, currentRowOffset, currentColumnOffset + columnOdd.getElseOffset(), ddRowVariableIndices, ddColumnVariableIndices); |
|
|
|
// Visit then-else.
|
|
|
|
toMatrixRec(thenElse, builder, rowOdd.getThenSuccessor(), columnOdd.getElseSuccessor(), currentRowLevel + 1, currentColumnLevel + 1, maxLevel, currentRowOffset + rowOdd.getElseOffset(), currentColumnOffset, ddRowVariableIndices, ddColumnVariableIndices); |
|
|
|
// Visit then-then.
|
|
|
|
toMatrixRec(thenThen, builder, rowOdd.getThenSuccessor(), columnOdd.getThenSuccessor(), currentRowLevel + 1, currentColumnLevel + 1, maxLevel, currentRowOffset + rowOdd.getElseOffset(), currentColumnOffset + columnOdd.getElseOffset(), ddRowVariableIndices, ddColumnVariableIndices); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|