/*
  * 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);
    }
  }
}
Beispiel #12
0
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;
}
Beispiel #13
0
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);
      }
    }
  }
    
}
Beispiel #15
0
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);
  }
}
Beispiel #20
0
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);

}
Beispiel #26
0
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;
}