/* * Checks that the units of the function are consistent * for a function returning value with same units as argument(s) * * If inconsistent units are found, an error message is logged. */ void ArgumentsUnitsCheck::checkSameUnitsAsArgs (const Model& m, const ASTNode& node, const SBase & sb, bool inKL, int reactNo) { /* check that node has children */ if (node.getNumChildren() == 0) { return; } UnitDefinition * ud; UnitDefinition * tempUD = NULL; unsigned int n; unsigned int i = 0; UnitFormulaFormatter *unitFormat = new UnitFormulaFormatter(&m); ud = unitFormat->getUnitDefinition(node.getChild(i), inKL, reactNo); /* get the first child that is not a parameter with undeclared units */ while (unitFormat->getContainsUndeclaredUnits() && i < node.getNumChildren()-1) { delete ud; i++; unitFormat->resetFlags(); ud = unitFormat->getUnitDefinition(node.getChild(i), inKL, reactNo); } /* check that all children have the same units * unless one of the children is a parameter with undeclared units * which is not tested */ for (n = i+1; n < node.getNumChildren(); n++) { unitFormat->resetFlags(); tempUD = unitFormat->getUnitDefinition(node.getChild(n), inKL, reactNo); if (!unitFormat->getContainsUndeclaredUnits()) { if (!UnitDefinition::areIdenticalSIUnits(ud, tempUD)) { logInconsistentSameUnits(node, sb); } } delete tempUD; } delete unitFormat; delete ud; for (n = 0; n < node.getNumChildren(); n++) { checkUnits(m, *node.getChild(n), sb, inKL, reactNo); } }
/* * Checks that the second argument of a piecewise returns a boolean * * If not, an error message is logged. */ void PieceBooleanMathCheck::checkPiece (const Model& m, const ASTNode& node, const SBase & sb) { unsigned int numChildren = node.getNumChildren(); unsigned int numPieces = numChildren; if ((numChildren % 2) != 0) numPieces--; for (unsigned int n = 1; n < numPieces; n += 2) { // if we have a mangled node for some reason // usually we have read an incorrect node // need to be sure there is a child // NOTE: piecewise hits this issue because old behaviour // meant it lost the piece and otherwise qualifiers ASTNode * child = node.getChild(n); if (child != NULL) { // need to pass the model here in case we have used a functionDefinition // as the piece child if (!child->returnsBoolean(&m)) { logMathConflict(node, sb); } } } }
/** * Constructor that makes a ConverterASTNode from an ASTNode. */ ConverterASTNode::ConverterASTNode(const ASTNode &templ): ASTNode(templ.getType()) { if (this->getType() == AST_RATIONAL) { this->mDenominator = templ.getDenominator(); this->mInteger = templ.getNumerator(); } else if (this->getType() == AST_REAL || this->getType() == AST_REAL_E) { this->mExponent = templ.getExponent(); this->mReal = templ.getMantissa(); } if (this->getType() == AST_PLUS || this->getType() == AST_MINUS || this->getType() == AST_TIMES || this->getType() == AST_DIVIDE || this->getType() == AST_POWER) { this->mChar = templ.getCharacter(); } else if (this->getType() == AST_INTEGER) { this->mInteger = templ.getInteger(); } if ((!this->isOperator()) && (!this->isNumber())) { this->setName(templ.getName()); } unsigned int counter; for (counter = 0; counter < templ.getNumChildren(); counter++) { this->addChild(new ConverterASTNode(*templ.getChild(counter))); } };
/** * Checks that the units of the arguments * of the function are dimensionless * and that there is only one argument * * If inconsistent units are found, an error message is logged. */ void ArgumentsUnitsCheckWarnings::checkDimensionlessArgs (const Model& m, const ASTNode& node, const SBase & sb, bool inKL, int reactNo) { /* check that node has children */ if (node.getNumChildren() == 0) { return; } UnitDefinition *dim = new UnitDefinition(m.getSBMLNamespaces()); Unit *unit = new Unit(m.getSBMLNamespaces()); unit->setKind(UNIT_KIND_DIMENSIONLESS); unit->initDefaults(); UnitDefinition * tempUD; dim->addUnit(unit); UnitFormulaFormatter *unitFormat = new UnitFormulaFormatter(&m); tempUD = unitFormat->getUnitDefinition(node.getChild(0), inKL, reactNo); if (tempUD->getNumUnits() != 0 && !UnitDefinition::areEquivalent(dim, tempUD)) { logInconsistentDimensionless(node, sb); } delete tempUD; delete dim; delete unit; delete unitFormat; }
/** * Checks that the arguments of the branches of a piecewise are consistent * * If not, an error message is logged. */ void PiecewiseValueMathCheck::checkPiecewiseArgs (const Model& m, const ASTNode& node, const SBase & sb) { unsigned int numChildren = node.getNumChildren(); /* arguments must return consistent types */ for (unsigned int n = 0; n < numChildren; n += 2) { if (returnsNumeric(m, node.getChild(n)) && !returnsNumeric(m, node.getLeftChild())) { logMathConflict(node, sb); } else if (node.getChild(n)->isBoolean() && !node.getLeftChild()->isBoolean()) { logMathConflict(node, sb); } } }
/** * Checks that the functions have either one or two arguments */ void NumberArgsMathCheck::checkSpecialCases(const Model& m, const ASTNode& node, const SBase & sb) { if (node.getNumChildren() < 1 || node.getNumChildren() > 2) { logMathConflict(node, sb); } for (unsigned int n = 0; n < node.getNumChildren(); n++) { checkMath(m, *node.getChild(n), sb); } }
bool ArraysASTPlugin::hasUnambiguousPackageInfixGrammar(const ASTNode *child) const { ASTBase* function = const_cast<ASTBase*>(getParentASTObject()); if (function == NULL) return false; if (function->getType() != AST_ORIGINATES_IN_PACKAGE) return false; if (function->getPackageName() != "arrays") return false; // cast the function to an ASTNode ASTNode* newAST = dynamic_cast<ASTNode*>(function); if (newAST == NULL) { return false; } const ArraysASTPlugin* aap = static_cast<const ArraysASTPlugin*>(function->getPlugin("arrays")); switch(aap->getASTType()) { case AST_LINEAR_ALGEBRA_SELECTOR: if (newAST->getNumChildren() == 0) return true; if (newAST->getChild(0) == child) return false; //The *first* child of the selector needs parentheses in some situations! return true; //All other children are separated by commas, and thus don't need parentheses. case AST_LINEAR_ALGEBRA_VECTOR_CONSTRUCTOR: #if (0) case AST_LINEAR_ALGEBRA_MATRIX_CONSTRUCTOR: case AST_LINEAR_ALGEBRA_DETERMINANT: case AST_LINEAR_ALGEBRA_TRANSPOSE: case AST_LINEAR_ALGEBRA_VECTOR_PRODUCT: case AST_LINEAR_ALGEBRA_SCALAR_PRODUCT: case AST_LINEAR_ALGEBRA_OUTER_PRODUCT: case AST_LINEAR_ALGEBRA_MATRIXROW_CONSTRUCTOR: #endif case AST_QUALIFIER_CONDITION: case AST_LOGICAL_EXISTS: case AST_LOGICAL_FORALL: case AST_QUALIFIER_LOWLIMIT: case AST_STATISTICS_MEAN: case AST_STATISTICS_MEDIAN: case AST_STATISTICS_MODE: case AST_STATISTICS_MOMENT: case AST_QUALIFIER_MOMENTABOUT: case AST_SERIES_PRODUCT: case AST_STATISTICS_SDEV: case AST_SERIES_SUM: case AST_QUALIFIER_UPLIMIT: case AST_STATISTICS_VARIANCE: return true; //Everything is either a function or has unambiguous syntax. case AST_ARRAYS_UNKNOWN: return false; } return false; }
/* * Checks that the arguments of numeric functions are consistent * * If not, an error message is logged. */ void NumericArgsMathCheck::checkNumericArgs (const Model& m, const ASTNode& node, const SBase & sb) { unsigned int n; for (n = 0; n < node.getNumChildren(); n++) { if (!returnsNumeric(m, node.getChild(n))) { logMathConflict(node, sb); } } }
/* * Checks that the arguments to logical operators are all boolean * * If not, an error message is logged. */ void LogicalArgsMathCheck::checkMathFromLogical (const Model&, const ASTNode& node, const SBase & sb) { unsigned int n; for (n = 0; n < node.getNumChildren(); n++) { if (!node.getChild(n)->isBoolean()) { logMathConflict(node, sb); } } }
ASTBase* ASTLambdaFunctionNode::getChild (unsigned int n) const { /* HACK TO REPLICATE OLD AST */ /* do not return a node with the bvar type * return the child of the bvar type */ if (ASTFunctionBase::getNumChildren() <= n) { return NULL; } if (ASTFunctionBase::getChild(n)->getType() == AST_QUALIFIER_BVAR) { ASTBase * base = ASTFunctionBase::getChild(n); ASTNode * bvar = dynamic_cast<ASTNode*>(base); //if (base->getFunction() != NULL) //{ // bvar = static_cast<ASTFunction*>(base->getFunction()); //} //else //{ // bvar = static_cast<ASTFunction*>(base); //} if (bvar != NULL) { if (bvar->getNumChildren() > 0) { return bvar->getChild(0); } else { return NULL; } } else { return NULL; } } else { return ASTFunctionBase::getChild(n); } }
ASTBase* ASTNaryFunctionNode::getChild (unsigned int n) const { if (this->getType() != AST_FUNCTION_ROOT) { return ASTFunctionBase::getChild(n); } else { /* HACK TO REPLICATE OLD AST */ /* do not return a node with the degree type * return the child of the degree */ if (ASTFunctionBase::getNumChildren() <= n) { return NULL; } if (ASTFunctionBase::getChild(n)->getType() == AST_QUALIFIER_DEGREE) { ASTBase * base = ASTFunctionBase::getChild(n); ASTNode * degree = dynamic_cast<ASTNode*>(base); if (degree != NULL) { if (degree->getNumChildren() > 0) { return degree->getChild(0); } else { return NULL; } } else { return NULL; } } else { return ASTFunctionBase::getChild(n); } } }
bool ArraysASTPlugin::isWellFormedNode(int type) const { bool valid = hasCorrectNumberArguments(type); ASTBase* function = const_cast<ASTBase*>(getMath()); // so getMath will only return teh node if it is a vector or matrix if (function == NULL) { function = const_cast<ASTBase*>(getParentASTObject()); if (function == NULL) { return false; } } // cast the function to an ASTNode ASTNode * newAST = dynamic_cast<ASTNode*>(function); // double check we are working with the right thing if (newAST == NULL) { return false; } else if (newAST->getExtendedType() != type) { return false; } unsigned int numChildren = newAST->getNumChildren(); unsigned int i = 0; // check number of arguments while (valid && i < numChildren) { valid = newAST->getChild(i)->isWellFormedNode(); i++; } return valid; }
pair<string, list<string> > MMOMath::_generateAlgebraic (pair<list<string>, ASTNode*> function, list<string> args, ASTNode *node) { ASTNode *repNode = new ASTNode (*function.second); _processNode (repNode); list<string>::iterator defArgs = function.first.begin (); list<string> variables; for (list<string>::iterator it = args.begin (); it != args.end (); it++) { repNode->renameSIdRefs (*defArgs, *it); defArgs++; } string ret = MMOUtils::getInstance ()->getExp (repNode); _getVariables (repNode, &variables); int childs = node->getNumChildren (), i; for (i = 0; i < childs; i++) { node->removeChild (0); } if (_type == MATH_ZERO_CROSSING) { node->setType (repNode->getType ()); childs = repNode->getNumChildren (); for (i = 0; i < childs; i++) { node->addChild (new ASTNode (*repNode->getChild (i))); } } else { node->setType (AST_NAME); node->setName (ret.c_str ()); node->setId ("REPLACED_FUNCTION"); } delete repNode; return (pair<string, list<string> > (ret, variables)); }
/* * Checks that the second argument of a piecewise returns a boolean * * If not, an error message is logged. */ void PieceBooleanMathCheck::checkPiece (const Model&, const ASTNode& node, const SBase & sb) { unsigned int numChildren = node.getNumChildren(); unsigned int numPieces = numChildren; #ifdef LIBSBML_USE_LEGACY_MATH if ((numChildren % 2) != 0) numPieces--; #else numPieces = 2 * node.getNumPiece(); if (numPieces > numChildren) { // the piecewise is not correct return; } #endif for (unsigned int n = 1; n < numPieces; n += 2) { // if we have a mangled node for some reason // usually we have read an incorrect node // need to be sure there is a child // NOTE: piecewise hits this issue because old behaviour // meant it lost the piece and otherwise qualifiers ASTNode * child = node.getChild(n); if (child != NULL) { if (!child->returnsBoolean()) { logMathConflict(node, sb); } } } }
void ArraysASTPlugin::visitMatrix( const ASTNode *parent, const ASTNode *node, StringBuffer_t *sb, const L3ParserSettings* settings) const { //Note: if there is one or zero rows, or if any of the rows have zero children, a matrix is declared as a function, and 'visitMatrix' won't be called. unsigned int numChildren = node->getNumChildren(); StringBuffer_appendChar(sb, '{'); for (unsigned int child=0; child<numChildren; child++) { ASTNode* row = node->getChild(child); if (child>0) { StringBuffer_appendChar(sb, ';'); StringBuffer_appendChar(sb, ' '); } for (unsigned int c2=0; c2<row->getNumChildren(); c2++) { if (c2>0) { StringBuffer_appendChar(sb, ','); StringBuffer_appendChar(sb, ' '); } L3FormulaFormatter_visit(row, row->getChild(c2), sb, settings); } } StringBuffer_appendChar(sb, '}'); }
bool ASTNaryFunctionNode::isLog10() const { bool valid = false; if (getType() == AST_FUNCTION_LOG) { // a log can have either one child that is not the logbase qualifier // or two where the first is the logbase of 10 if (getNumChildren() == 1) { ASTBase * base1 = ASTFunctionBase::getChild(0); if (base1->isQualifier() == false) { valid = true; } } else if (getNumChildren() == 2) { ASTBase * base1 = ASTFunctionBase::getChild(0); ASTFunction* fun = dynamic_cast<ASTFunction*>(base1); if (fun != NULL) { if (fun->getType() == AST_QUALIFIER_LOGBASE && fun->getNumChildren() == 1) { ASTBase *base2 = fun->getChild(0); if (base2->getType() == AST_INTEGER) { ASTNumber *child = static_cast<ASTNumber*>(base2); if (child->getInteger() == 10) { valid = true; } } } } else { // here we are working the ASTNode so the casting // is more difficult ASTNode* newAST = dynamic_cast<ASTNode*>(base1); if (newAST != NULL && newAST->getType() == AST_QUALIFIER_LOGBASE && newAST->getNumChildren() == 1 ) { ASTNode* newAST1 = newAST->getChild(0); if (newAST1->getType() == AST_INTEGER) { if (newAST1->getInteger() == 10) { valid = true; } } } else { if (newAST != NULL && newAST->getType() == AST_INTEGER) { if (newAST->getInteger() == 10) { valid = true; } } } } } } return valid; }
int ASTNaryFunctionNode::removeChild (unsigned int n) { int removed = LIBSBML_OPERATION_FAILED; if (this->getType() != AST_FUNCTION_ROOT) { removed = ASTFunctionBase::removeChild(n); } else { /* HACK TO REPLICATE OLD AST */ /* Hack to remove memory since the overall * remove does not remove memory * but the old api does not give access to the new * intermediate parents so these can never * be explicilty deleted by the user * * in this case the first remove is accessible */ if (ASTFunctionBase::getChild(n)->getType() == AST_QUALIFIER_DEGREE) { ASTBase * base = ASTFunctionBase::getChild(n); ASTNode * degree = dynamic_cast<ASTNode*>(base); if (degree != NULL && degree->getNumChildren() == 1) { removed = degree->removeChild(0); if (removed == LIBSBML_OPERATION_SUCCESS) { ASTBase * removedAST = NULL; removedAST = this->ASTFunctionBase::getChild(n); removed = ASTFunctionBase::removeChild(n); if (removedAST != NULL) delete removedAST; } } } else { removed = ASTFunctionBase::removeChild(n); } } /* HACK TO REPLICATE OLD AST */ // if we now have an odd number of children the last one // should be subject NOT the degree if (removed == LIBSBML_OPERATION_SUCCESS) { unsigned int size = getNumChildren(); unsigned int numChildren = ASTFunctionBase::getNumChildren(); if ((unsigned int)(size%2) == 1) { ASTBase * child = ASTFunctionBase::getChild(numChildren-1); if (child->getType() == AST_QUALIFIER_DEGREE) { ASTNode * degree = dynamic_cast<ASTNode *>(child); if (degree != NULL && degree->getNumChildren() == 1) { ASTNode *pChild = degree->getChild(0); degree->removeChild(0); ASTBase * temp = this->ASTFunctionBase::getChild(numChildren-1); this->ASTFunctionBase::removeChild(numChildren-1); delete temp; this->addChild(pChild); } } } } return removed; }
/* * Checks that the units of the piecewise function are consistent * * If inconsistent units are found, an error message is logged. */ void ArgumentsUnitsCheck::checkUnitsFromPiecewise (const Model& m, const ASTNode& node, const SBase & sb, bool inKL, int reactNo) { /* check that node has children */ if (node.getNumChildren() == 0) { return; } /* piecewise(a0, a1, a2, a3, ...) * a0 and a2, a(n_even) must have same units * a1, a3, a(n_odd) must be dimensionless */ unsigned int n; UnitDefinition *dim = new UnitDefinition(m.getSBMLNamespaces()); Unit *unit = new Unit(m.getSBMLNamespaces()); unit->setKind(UNIT_KIND_DIMENSIONLESS); unit->initDefaults(); UnitDefinition * tempUD; UnitDefinition * tempUD1 = NULL; dim->addUnit(unit); UnitFormulaFormatter *unitFormat = new UnitFormulaFormatter(&m); tempUD = unitFormat->getUnitDefinition(node.getChild(0), inKL, reactNo); for(n = 2; n < node.getNumChildren(); n+=2) { tempUD1 = unitFormat->getUnitDefinition(node.getChild(n), inKL, reactNo); if (!unitFormat->getContainsUndeclaredUnits()) { if (!UnitDefinition::areEquivalent(tempUD, tempUD1)) { logInconsistentPiecewise(node, sb); } } delete tempUD1; } delete tempUD; for(n = 1; n < node.getNumChildren(); n+=2) { tempUD = unitFormat->getUnitDefinition(node.getChild(n), inKL, reactNo); if (!UnitDefinition::areEquivalent(tempUD, dim)) { logInconsistentPiecewiseCondition(node, sb); } delete tempUD; } delete dim; delete unit; delete unitFormat; for(n = 0; n < node.getNumChildren(); n++) { checkUnits(m, *node.getChild(n), sb, inKL, reactNo); } }
int ASTPiecewiseFunctionNode::addChild(ASTBase* child, bool inRead) { // now here what I want to do is just keep track of the number // of children being added so the mNumPiece and mHasOtherwise // variables can be given appropriate values // but not if we are reading a stream because then we already know if (inRead == false) { if (child->getType() != AST_CONSTRUCTOR_PIECE && child->getType() != AST_CONSTRUCTOR_OTHERWISE) { // this child does not have a piece/otherwise but if // the rest of the function does then it needs to fit in with that unsigned int currentNum = getNumChildren(); if (usingChildConstructors() == false) { if ((currentNum+1)%2 == 0) { setNumPiece(getNumPiece()+1); setHasOtherwise(false); } else { setHasOtherwise(true); } return ASTFunctionBase::addChild(child); } else { ASTBase * lastChild = ASTFunctionBase::getChild(ASTFunctionBase::getNumChildren()-1); if (lastChild == NULL) { // we have a serious issue going on but may as well just // add the child return ASTFunctionBase::addChild(child); } else if (lastChild->getType() == AST_CONSTRUCTOR_PIECE) { ASTNode * piece = dynamic_cast<ASTNode*>(lastChild); if (piece == NULL) { return LIBSBML_OPERATION_FAILED; } if (piece->getNumChildren() == 1) { return piece->addChild((ASTNode*)(child)); } else { ASTNode * otherwise = new ASTNode(AST_CONSTRUCTOR_OTHERWISE); if (otherwise->addChild((ASTNode*)(child)) == LIBSBML_OPERATION_SUCCESS) { setHasOtherwise(true); return ASTFunctionBase::addChild(otherwise); } else { return LIBSBML_OPERATION_FAILED; } } } else { ASTNode * otherwise = dynamic_cast<ASTNode*>(lastChild); if (otherwise == NULL || otherwise->getNumChildren() != 1) { return LIBSBML_OPERATION_FAILED; } ASTNode * piece = new ASTNode(AST_CONSTRUCTOR_PIECE); // add teh child from teh otherwise if (piece->addChild(otherwise->getChild(0)) != LIBSBML_OPERATION_SUCCESS) { return LIBSBML_OPERATION_FAILED; } else { if (piece->addChild((ASTNode*)(child)) == LIBSBML_OPERATION_SUCCESS) { this->removeChild(currentNum-1); setHasOtherwise(false); setNumPiece(getNumPiece() + 1); return ASTFunctionBase::addChild(piece); } else { return LIBSBML_OPERATION_FAILED; } } } } } else { if (child->getType() == AST_CONSTRUCTOR_PIECE) { setNumPiece(getNumPiece()+1); } else { setHasOtherwise(true); } return ASTFunctionBase::addChild(child); } } else { return ASTFunctionBase::addChild(child); } }
bool ArraysASTPlugin::isPackageInfixFunction() const { ASTBase* function = const_cast<ASTBase*>(getParentASTObject()); if (function == NULL) return false; if (function->getType() != AST_ORIGINATES_IN_PACKAGE) return false; if (function->getPackageName() != "arrays") return false; // cast the function to an ASTNode ASTNode* newAST = dynamic_cast<ASTNode*>(function); if (newAST == NULL) { return false; } unsigned int numChildren = newAST->getNumChildren(); unsigned int child = 0; const ArraysASTPlugin* aap = static_cast<const ArraysASTPlugin*>(newAST->getPlugin("arrays")); switch(aap->getASTType()) { case AST_LINEAR_ALGEBRA_SELECTOR: case AST_LINEAR_ALGEBRA_VECTOR_CONSTRUCTOR: return false; #if (0) case AST_LINEAR_ALGEBRA_MATRIX_CONSTRUCTOR: //An empty matrix or a matrix with only one row looks like a vector, so we have to use the functional form if (numChildren<=1) return true; //Also, none of the rows may be empty for the { ... ; ... } to be parseable: for (child=0; child<numChildren; child++) { if(newAST->getChild(child)->getNumChildren() == 0) { return true; } } return false; case AST_LINEAR_ALGEBRA_DETERMINANT: case AST_LINEAR_ALGEBRA_TRANSPOSE: case AST_LINEAR_ALGEBRA_VECTOR_PRODUCT: case AST_LINEAR_ALGEBRA_SCALAR_PRODUCT: case AST_LINEAR_ALGEBRA_OUTER_PRODUCT: case AST_LINEAR_ALGEBRA_MATRIXROW_CONSTRUCTOR: return true; #endif case AST_LOGICAL_EXISTS: case AST_LOGICAL_FORALL: case AST_STATISTICS_MEAN: case AST_STATISTICS_MEDIAN: case AST_STATISTICS_MODE: case AST_STATISTICS_MOMENT: case AST_SERIES_PRODUCT: case AST_STATISTICS_SDEV: case AST_SERIES_SUM: case AST_STATISTICS_VARIANCE: case AST_ARRAYS_UNKNOWN: return true; case AST_QUALIFIER_CONDITION: case AST_QUALIFIER_LOWLIMIT: case AST_QUALIFIER_MOMENTABOUT: case AST_QUALIFIER_UPLIMIT: return false; } return false; }
CK_CPPSTART START_TEST (test_element_vector) { const char* s = wrapMathML ( "<vector>" " <apply>" " <cos/>" " <cn type=\"integer\"> 5 </cn>" " </apply>" " <ci> y </ci>" "</vector>\n" ); N = readMathMLFromStringWithNamespaces(s, NS); fail_unless( N != NULL ); fail_unless( N->getType() == AST_ORIGINATES_IN_PACKAGE); fail_unless( N->getExtendedType() == AST_LINEAR_ALGEBRA_VECTOR_CONSTRUCTOR); fail_unless( N->getNumChildren() == 2); fail_unless( N->getPackageName() == "arrays"); ASTNode * child = N->getChild(0); fail_unless( child != NULL ); fail_unless( child->getType() == AST_FUNCTION_COS); fail_unless( child->getExtendedType() == AST_FUNCTION_COS); fail_unless( child->getNumChildren() == 1); fail_unless( child->getPackageName() == "core"); ASTNode *c1 = child->getChild(0); fail_unless( c1 != NULL ); fail_unless( c1->getType() == AST_INTEGER); fail_unless( c1->getExtendedType() == AST_INTEGER); fail_unless( c1->getNumChildren() == 0); fail_unless( c1->getInteger() == 5); child = N->getChild(1); fail_unless( child != NULL ); fail_unless( child->getType() == AST_NAME); fail_unless( child->getExtendedType() == AST_NAME); fail_unless( strcmp(child->getName(), "y") == 0); fail_unless( child->getNumChildren() == 0); ArraysASTPlugin* plugin = static_cast<ArraysASTPlugin*>(N->getPlugin("arrays")); fail_unless(plugin != NULL); fail_unless(plugin->getASTType() == AST_LINEAR_ALGEBRA_VECTOR_CONSTRUCTOR); plugin = static_cast<ArraysASTPlugin*>(child->getPlugin("arrays")); fail_unless(plugin != NULL); fail_unless(plugin->getASTType() == AST_ARRAYS_UNKNOWN); }
bool ASTNaryFunctionNode::isSqrt() const { bool valid = false; if (getType() == AST_FUNCTION_ROOT) { // a sqrt can have either one child that is not the degree qualifier // or two where the first is the degree of 2 if (getNumChildren() == 1) { /* HACK to replicate OLD AST whic says a sqrt must have two children*/ valid = false; //ASTBase * base1 = getChild(0); //if (base1->isQualifier() == false) //{ // valid = true; //} } else if (getNumChildren() == 2) { ASTBase * base1 = ASTFunctionBase::getChild(0); ASTFunction* fun = dynamic_cast<ASTFunction*>(base1); if (fun != NULL) { if (fun->getType() == AST_QUALIFIER_DEGREE && fun->getNumChildren() == 1) { ASTBase *base2 = fun->getChild(0); if (base2->getType() == AST_INTEGER) { ASTNumber *child = static_cast<ASTNumber*>(base2); if (child->getInteger() == 2) { valid = true; } } } } else { // here we are working the ASTNode so the casting // is more difficult ASTNode* newAST = dynamic_cast<ASTNode*>(base1); if (newAST != NULL && newAST->getType() == AST_QUALIFIER_DEGREE && newAST->getNumChildren() == 1) { ASTNode* newAST1 = newAST->getChild(0); if (newAST1->getType() == AST_INTEGER) { if (newAST1->getInteger() == 2) { valid = true; } } } else { if (newAST != NULL && newAST->getType() == AST_INTEGER) { if (newAST->getInteger() == 2) { valid = true; } } } } } } return valid; }
ASTBase* ASTPiecewiseFunctionNode::getChild (unsigned int n) const { /* HACK TO REPLICATE OLD AST */ /* do not return a node with teh piece or otherwise type * return the correct child of the piece type * or the child of the otherwise */ unsigned int numChildren = ASTFunctionBase::getNumChildren(); if (numChildren == 0) { return NULL; } // determine index that we actually want unsigned int childNo = (unsigned int)(n/2); unsigned int pieceIndex = (unsigned int)(n%2); ASTBase * base = NULL; if (childNo < numChildren) { base = ASTFunctionBase::getChild(childNo); } if (getHasOtherwise() == true && childNo == numChildren - 1) { if (base == NULL) { return NULL; } if (base->getType() == AST_CONSTRUCTOR_OTHERWISE) { ASTNode * otherwise = dynamic_cast<ASTNode*>(base); if (otherwise != NULL) { if (otherwise->getNumChildren() > 0) { return otherwise->getChild(0); } else { return NULL; } } else { return NULL; } } else { return base; } } else if (base != NULL && base->getType() == AST_CONSTRUCTOR_PIECE) { ASTNode * piece = dynamic_cast<ASTNode*>(base); if (piece != NULL) { if (piece->getNumChildren() > pieceIndex) { return piece->getChild(pieceIndex); } else { return NULL; } } else { return NULL; } } else if (n < numChildren) { return ASTFunctionBase::getChild(n); } else { return NULL; } }
bool ASTBinaryFunctionNode::isSqrt() const { bool valid = false; ASTBase * base1 = NULL; if (getType() == AST_FUNCTION_ROOT) { if (getNumChildren() == 2) { base1 = getChild(0); ASTFunction* fun = dynamic_cast<ASTFunction*>(base1); if (fun != NULL) { if (fun->getType() == AST_QUALIFIER_DEGREE && fun->getNumChildren() == 1) { ASTBase *base2 = fun->getChild(0); if (base2->getType() == AST_INTEGER) { ASTNumber *child = static_cast<ASTNumber*>(base2); if (child->getInteger() == 2) { valid = true; } } } } else { // here we are working the ASTNode so the casting // is more difficult ASTNode* newAST = dynamic_cast<ASTNode*>(base1); if (newAST != NULL && newAST->getType() == AST_QUALIFIER_DEGREE && newAST->getNumChildren() == 1) { ASTNode* newAST1 = newAST->getChild(0); if (newAST1->getType() == AST_INTEGER) { if (newAST1->getInteger() == 2) { valid = true; } } } else { if (newAST != NULL && newAST->getType() == AST_INTEGER) { if (newAST->getInteger() == 2) { valid = true; } } } } } } return valid; }
END_TEST START_TEST (test_element_matrix) { const char* s = wrapMathML ( "<matrix>" "<matrixrow>" "<apply>" "<cos/>" "<cn type=\"integer\"> 5 </cn>" "</apply>" "<ci> y </ci>" "</matrixrow>" "<matrixrow>" "<cn type=\"integer\"> 2 </cn>" "<apply>" "<cos/>" "<cn type=\"integer\"> 5 </cn>" "</apply>" "</matrixrow>" "</matrix>\n" ); N = readMathMLFromStringWithNamespaces(s, NS); fail_unless( N != NULL ); fail_unless( N->getType() == AST_ORIGINATES_IN_PACKAGE); fail_unless( N->getExtendedType() == AST_LINEAR_ALGEBRA_MATRIX_CONSTRUCTOR); fail_unless( N->getNumChildren() == 2); fail_unless( N->getPackageName() == "arrays"); ASTNode * child = N->getChild(0); fail_unless( child != NULL ); fail_unless( child->getType() == AST_ORIGINATES_IN_PACKAGE); fail_unless( child->getExtendedType() == AST_LINEAR_ALGEBRA_MATRIXROW_CONSTRUCTOR); fail_unless( child->getNumChildren() == 2); fail_unless( child->getPackageName() == "arrays"); ASTNode *c1 = child->getChild(0); fail_unless( c1 != NULL ); fail_unless( c1->getType() == AST_FUNCTION_COS); fail_unless( c1->getExtendedType() == AST_FUNCTION_COS); fail_unless( c1->getNumChildren() == 1); fail_unless( c1->getPackageName() == "core"); child = N->getChild(1); fail_unless( child != NULL ); fail_unless( child->getType() == AST_ORIGINATES_IN_PACKAGE); fail_unless( child->getExtendedType() == AST_LINEAR_ALGEBRA_MATRIXROW_CONSTRUCTOR); fail_unless( child->getNumChildren() == 2); fail_unless( child->getPackageName() == "arrays"); c1 = child->getChild(0); fail_unless( c1 != NULL ); fail_unless( c1->getType() == AST_INTEGER); fail_unless( c1->getExtendedType() == AST_INTEGER); fail_unless( c1->getNumChildren() == 0); fail_unless( c1->getInteger() == 2); ArraysASTPlugin* plugin = static_cast<ArraysASTPlugin*>(N->getPlugin("arrays")); fail_unless(plugin != NULL); fail_unless(plugin->getASTType() == AST_LINEAR_ALGEBRA_MATRIX_CONSTRUCTOR); }
int Submodel::convertTimeAndExtentWith(const ASTNode* tcf, const ASTNode* xcf, const ASTNode* klmod) { if (tcf==NULL && xcf==NULL) return LIBSBML_OPERATION_SUCCESS; Model* model = getInstantiation(); if (model==NULL) { //getInstantiation sets its own error messages. return LIBSBML_OPERATION_FAILED; } ASTNode* tcftimes = NULL; ASTNode* tcfdiv = NULL; if (tcf != NULL) { tcftimes = new ASTNode(AST_TIMES); tcftimes->addChild(tcf->deepCopy()); tcfdiv = new ASTNode(AST_DIVIDE); tcfdiv->addChild(tcf->deepCopy()); } ASTNode* rxndivide = NULL; if (klmod != NULL) { rxndivide = new ASTNode(AST_DIVIDE); ASTNode rxnref(AST_NAME); rxndivide->addChild(rxnref.deepCopy()); rxndivide->addChild(klmod->deepCopy()); } List* allelements = model->getAllElements(); for (unsigned int el=0; el<allelements->getSize(); el++) { SBase* element = static_cast<SBase*>(allelements->get(el)); assert(element != NULL); ASTNode* ast1 = NULL; ASTNode* ast2 = NULL; Constraint* constraint = NULL; Delay* delay = NULL; EventAssignment* ea = NULL; InitialAssignment* ia = NULL; KineticLaw* kl = NULL; Priority* priority = NULL; RateRule* rrule = NULL; Rule* rule = NULL; Submodel* submodel = NULL; Trigger* trigger = NULL; string cf = ""; //Reaction math will be converted below, in the bits with the kinetic law. But because of that, we need to handle references *to* the reaction: even if it has no kinetic law, the units have changed, and this needs to be reflected by the flattening routine. if (rxndivide != NULL && element->getTypeCode()==SBML_REACTION && element->isSetId()) { rxndivide->getChild(0)->setName(element->getId().c_str()); for (unsigned int sube=0; sube<allelements->getSize(); sube++) { SBase* subelement = static_cast<SBase*>(allelements->get(sube)); subelement->replaceSIDWithFunction(element->getId(), rxndivide); } } //Submodels need their timeConversionFactor and extentConversionFactor attributes converted. We're moving top-down, so all we need to do here is fix the conversion factor attributes themselves, pointing them to new parameters if need be. if ((tcf !=NULL || xcf != NULL) && element->getTypeCode()==SBML_COMP_SUBMODEL) { submodel = static_cast<Submodel*>(element); if (tcf != NULL) { if (submodel->isSetTimeConversionFactor()) { createNewConversionFactor(cf, tcf, submodel->getTimeConversionFactor(), model); submodel->setTimeConversionFactor(cf); } else { submodel->setTimeConversionFactor(tcf->getName()); } } if (xcf != NULL) { if (submodel->isSetExtentConversionFactor()) { createNewConversionFactor(cf, xcf, submodel->getExtentConversionFactor(), model); submodel->setExtentConversionFactor(cf); } else { submodel->setExtentConversionFactor(xcf->getName()); } } } if (tcf==NULL) { if (klmod !=NULL && element->getTypeCode()==SBML_KINETIC_LAW) { kl = static_cast<KineticLaw*>(element); if (kl->isSetMath()) { ast1 = new ASTNode(AST_TIMES); ast1->addChild(klmod->deepCopy()); ast1->addChild(kl->getMath()->deepCopy()); kl->setMath(ast1); delete ast1; } } } else { // All math 'time' and 'delay' csymbols must still be converted. // Also, several constructs are modified directly. switch(element->getTypeCode()) { //This would be a WHOLE LOT SIMPLER if there was a 'hasMath' class in libsbml. But even so, it would have to // handle the kinetic laws, rate rules, and delays separately. case SBML_KINETIC_LAW: //Kinetic laws are multiplied by 'klmod'. kl = static_cast<KineticLaw*>(element); ast1 = kl->getMath()->deepCopy(); convertCSymbols(ast1, tcfdiv, tcftimes); if (klmod !=NULL) { kl = static_cast<KineticLaw*>(element); if (kl->isSetMath()) { ast2 = new ASTNode(AST_TIMES); ast2->addChild(klmod->deepCopy()); ast2->addChild(ast1); kl->setMath(ast2); delete ast2; } } else { kl->setMath(ast1); delete ast1; } break; case SBML_DELAY: //Delays are multiplied by the time conversion factor. delay = static_cast<Delay*>(element); if (delay->isSetMath()) { ast1 = delay->getMath()->deepCopy(); convertCSymbols(ast1, tcfdiv, tcftimes); tcftimes->addChild(ast1); delay->setMath(tcftimes); tcftimes->removeChild(1); } break; case SBML_RATE_RULE: //Rate rules are divided by the time conversion factor. rrule = static_cast<RateRule*>(element); if (rrule->isSetMath()) { ast1 = rrule->getMath()->deepCopy(); tcfdiv->insertChild(0, rrule->getMath()->deepCopy()); rrule->setMath(tcfdiv); tcfdiv->removeChild(0); } //Fall through to: case SBML_ASSIGNMENT_RULE: case SBML_ALGEBRAIC_RULE: //Rules in general need csymbols converted. rule = static_cast<Rule*>(element); if (rule->isSetMath()) { ast1 = rule->getMath()->deepCopy(); convertCSymbols(ast1, tcfdiv, tcftimes); rule->setMath(ast1); delete ast1; } break; case SBML_EVENT_ASSIGNMENT: //Event assignments need csymbols converted. ea = static_cast<EventAssignment*>(element); if (ea->isSetMath()) { ast1 = ea->getMath()->deepCopy(); convertCSymbols(ast1, tcfdiv, tcftimes); ea->setMath(ast1); delete ast1; } break; case SBML_INITIAL_ASSIGNMENT: //Initial assignments need csymbols converted. ia = static_cast<InitialAssignment*>(element); if (ia->isSetMath()) { ast1 = ia->getMath()->deepCopy(); convertCSymbols(ast1, tcfdiv, tcftimes); ia->setMath(ast1); delete ast1; } break; case SBML_CONSTRAINT: //Constraints need csymbols converted. constraint = static_cast<Constraint*>(element); if (constraint->isSetMath()) { ast1 = constraint->getMath()->deepCopy(); convertCSymbols(ast1, tcfdiv, tcftimes); constraint->setMath(ast1); delete ast1; } break; case SBML_PRIORITY: //Priorities need csymbols converted. priority = static_cast<Priority*>(element); if (priority->isSetMath()) { ast1 = priority->getMath()->deepCopy(); convertCSymbols(ast1, tcfdiv, tcftimes); priority->setMath(ast1); delete ast1; } break; case SBML_TRIGGER: //Triggers need csymbols converted. trigger = static_cast<Trigger*>(element); if (trigger->isSetMath()) { ast1 = trigger->getMath()->deepCopy(); convertCSymbols(ast1, tcfdiv, tcftimes); trigger->setMath(ast1); delete ast1; } break; default: //Do nothing! If we wanted to call a plugin routine, this would be the place. The only other alternative is to #ifdef some code in here that deals with the math-containing package objects explicitly. Which might be the best option, all told. break; } } } delete allelements; return LIBSBML_OPERATION_SUCCESS; }