/*
  * 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 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);
  }
}
END_TEST




START_TEST (test_element_selector)
{
  const char* s = wrapMathML
  (
    "  <apply>"
    "    <selector/>"
    "    <ci> A </ci>"
    "    <ci> i </ci>"
    "  </apply>"
  );



  N = readMathMLFromStringWithNamespaces(s, NS);

  fail_unless( N != NULL );
  fail_unless( N->getType() == AST_ORIGINATES_IN_PACKAGE);
  fail_unless( N->getExtendedType() == AST_LINEAR_ALGEBRA_SELECTOR);
  fail_unless( N->getNumChildren() == 2);
  fail_unless( N->getPackageName() == "arrays");

  ASTNode * child = N->getChild(0);

  fail_unless( child != NULL );
  fail_unless( child->getType() == AST_NAME);
  fail_unless( child->getExtendedType() == AST_NAME);
  fail_unless( strcmp(child->getName(), "A") == 0);
  fail_unless( child->getNumChildren() == 0);
  fail_unless( child->getPackageName() == "core");

  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(), "i") == 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_SELECTOR);

}
/*
  * 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;

}
unsigned int
ASTPiecewiseFunctionNode::getNumChildren() const
{
  /* HACK TO REPLICATE OLD AST */
  unsigned int numChildren = 0;
  
  for (unsigned int i = 0; i < getNumPiece(); i++)
  {
    ASTBase * base = ASTFunctionBase::getChild(i);
    ASTNode * piece = dynamic_cast<ASTNode*>(base);

    if (piece != NULL && piece->getType() == AST_CONSTRUCTOR_PIECE)
    {
      numChildren += piece->getNumChildren();
    }
    else
    {
      // fail safe - a piece should have 2 children
      numChildren += 2;
    }
  }
  if (getHasOtherwise() == true)
  {
    numChildren++;
  }

  return numChildren;
}
/**
  * Checks that the functionDefinition referred to by a <ci> element 
  * has the appropriate number of arguments.
  *
  * If not, an error message is logged.
  */
void 
FunctionNoArgsMathCheck::checkNumArgs (const Model& m, const ASTNode& node, 
                                                const SBase & sb)
{
  /* this rule was only introduced level 2 version 4 */
  if (m.getLevel() > 2 || (m.getLevel() == 2 && m.getVersion() > 3))
  {
    if (m.getFunctionDefinition(node.getName()) != NULL)
    {
      /* functiondefinition math */
      const ASTNode * fdMath = m.getFunctionDefinition(node.getName())->getMath();
      if (fdMath != NULL)
      {
      /* We have a definition for this function.  Does the defined number
	        of arguments equal the number used here? */

        if (node.getNumChildren() != m.getFunctionDefinition(node.getName())->getNumArguments())
	      {
          logMathConflict(node, sb);
	      }
      }

    }
  }
}
void NumberArgsMathCheck::checkPiecewise(const Model&, 
                                    const ASTNode& node, const SBase & sb)
{
  if (node.getNumChildren() == 0)
  {
    logMathConflict(node, sb);
  }

}
Beispiel #10
0
/**
 * In MathML, &lt;plus/> and &lt;times/> are n-ary operators but the infix
 * FormulaParser represents them as binary operators.  To ensure a
 * consistent AST representation, this function is part of the n-ary to
 * binary reduction process.
 */
static void
reduceBinary (ASTNode& node)
{
  if (node.getNumChildren() == 2)
  {
    ASTNode* op = new ASTNode( node.getType() );
    node.swapChildren(op);
    node.prependChild(op);
  }
}
/**
  * Checks that the function has only one argument
  */
void NumberArgsMathCheck::checkUnary(const Model& m, 
                                     const ASTNode& node, const SBase & sb)
{
  if (node.getNumChildren() != 1)
  {
    logMathConflict(node, sb);
  }
  else
  {
    checkMath(m, *node.getLeftChild(), sb);
  }
}
Beispiel #12
0
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;
}
int 
ASTLambdaFunctionNode::removeChild(unsigned int n)
{
  int removed = LIBSBML_OPERATION_FAILED;
  /* need to keep track of whether we have removed a bvar */

  unsigned int numBvars = getNumBvars();
  if (numBvars == 0)
  {
    /* we are removing the body - if the index is appropriate */
    return ASTFunctionBase::removeChild(n);
  }

  if (n < numBvars)
  {
    // we are removing a bvar
    setNumBvars(numBvars - 1);

   /* 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
     */
    ASTBase * base = ASTFunctionBase::getChild(n);
    ASTNode * bvar = dynamic_cast<ASTNode*>(base);
   
    if (bvar != NULL && bvar->getNumChildren() == 1)
    {
      removed = bvar->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
  {
    // we are removing the body
    removed = ASTFunctionBase::removeChild(n);
  }

  return removed;
}
/*
  * 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);
    }
  }
    
}
/*
 * 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 units of the delay function are consistent
  *
  * If inconsistent units are found, an error message is logged.
  */
void 
ArgumentsUnitsCheck::checkUnitsFromDelay (const Model& m, 
                                        const ASTNode& node, 
                                        const SBase & sb, bool inKL, int reactNo)
{
  /* check that node has two children */
  if (node.getNumChildren() != 2)
  {
    return;
  }

  if (!m.getSBMLNamespaces()->getNamespaces())
  {
#if 0
    cout << "[DEBUG] XMLNS IS NULL" << endl;
#endif
  }

  /* delay(x, t) 
   * no restrictions on units of x
   * but t must have units of time
   */
  UnitDefinition *time = new UnitDefinition(m.getSBMLNamespaces());
  Unit *unit = new Unit(m.getSBMLNamespaces());
  unit->setKind(UNIT_KIND_SECOND);
  unit->initDefaults();
  UnitDefinition * tempUD;
  time->addUnit(unit);
  
  UnitFormulaFormatter *unitFormat = new UnitFormulaFormatter(&m);

  tempUD = unitFormat->getUnitDefinition(node.getRightChild(), inKL, reactNo);
  
  if (!unitFormat->getContainsUndeclaredUnits())
  {
    if (!UnitDefinition::areEquivalent(time, tempUD)) 
    {
      logInconsistentDelay(node, sb);
    }
  }

  delete time;
  delete tempUD;
  delete unit;
  delete unitFormat;

  checkUnits(m, *node.getLeftChild(), sb, inKL, reactNo);
}
Beispiel #17
0
bool
ArraysASTPlugin::hasCorrectNumberArguments(int type) const
{
  bool correctNumArgs = true;

  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();
  
  switch (type)
  {
  case AST_LINEAR_ALGEBRA_SELECTOR:
    if (numChildren < 1 || numChildren > 3)
    {
      correctNumArgs = false;
    }
    break;
  default:
    break;

  }

  return correctNumArgs;
}
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);
    }
  }
}
int 
ASTBinaryFunctionNode::removeChild (unsigned int n)
{
  int removed = LIBSBML_OPERATION_FAILED;
  if (this->getType() != AST_FUNCTION_LOG)
  {
    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_LOGBASE)
    {
      ASTBase * base = ASTFunctionBase::getChild(n);
      ASTNode * logbase = dynamic_cast<ASTNode*>(base);
      if (logbase != NULL && logbase->getNumChildren() == 1)
      {
        removed = logbase->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);
    }
  }

  return removed;
}
Beispiel #21
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 #22
0
/**
 * Ensures the given ASTNode has the appropriate number of arguments.  If
 * arguments are missing, appropriate defaults (per the MathML 2.0
 * specification) are added:
 *
 *   log (x) -> log (10, x)
 *   root(x) -> root( 2, x)
 */
static void
checkFunctionArgs (ASTNode& node)
{
  if (node.getNumChildren() == 1)
  {
    if (node.getType() == AST_FUNCTION_LOG)
    {
      ASTNode* child = new ASTNode;
      child->setValue(10);

      node.prependChild(child);
    }
    else if (node.getType() == AST_FUNCTION_ROOT)
    {
      ASTNode* child = new ASTNode;
      child->setValue(2);

      node.prependChild(child);
    }
  }
}
/**
  * 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);
    }  
  }
}
Beispiel #24
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 arguments to eq or neq are consistent
  * i.e. have same type both boolean or both numeric
  *
  * If an inconsistency is found, an error message is logged.
  */
void 
EqualityArgsMathCheck::checkArgs (const Model& m, 
                                        const ASTNode& node, 
                                        const SBase & sb)
{
  /* check that node has two children */
  if (node.getNumChildren() != 2)
  {
    return;
  }

  /* arguments must return consistent value types */
  if (returnsNumeric(m, node.getLeftChild()) && 
     !returnsNumeric(m, node.getRightChild()))
  {
    logMathConflict(node, sb);
  }
  else if (node.getLeftChild()->isBoolean() && 
          !node.getRightChild()->isBoolean())
  {
    logMathConflict(node, sb);
  }    
}
/*
  * 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 #27
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, '}');
}
/**
  * Checks that the units of the power function are consistent
  *
  * If inconsistent units are found, an error message is logged.
  * 
  * The two arguments to power, which are of the form power(a, b) 
  * with the meaning a^b, should be as follows: 
  * (1) if the second argument is an integer, 
  *     then the first argument can have any units; 
  * (2) if the second argument b is a rational number n/m, 
  * it must be possible to derive the m-th root of (a{unit})n,
  * where {unit} signifies the units associated with a; 
  * otherwise, (3) the units of the first argument must be “dimensionless”. 
  * The second argument (b) should always have units of “dimensionless”.
  *
  */
void 
PowerUnitsCheck::checkUnitsFromPower (const Model& m, 
                                        const ASTNode& node, 
                                        const SBase & sb, bool inKL, int reactNo)
{

  /* check that node has 2 children */
  if (node.getNumChildren() != 2)
  {
    return;
  }

  double value;
  UnitDefinition dim(m.getSBMLNamespaces());
  Unit unit(m.getSBMLNamespaces());
  unit.setKind(UNIT_KIND_DIMENSIONLESS);
  unit.initDefaults();
  dim.addUnit(&unit);

  UnitFormulaFormatter *unitFormat = new UnitFormulaFormatter(&m);

  UnitDefinition *tempUD = NULL;
  UnitDefinition *unitsArg1, *unitsArgPower;
  unitsArg1 = unitFormat->getUnitDefinition(node.getLeftChild(), inKL, reactNo);
  unsigned int undeclaredUnits = 
    unitFormat->getContainsUndeclaredUnits();

  ASTNode *child = node.getRightChild();
  unitFormat->resetFlags();
  unitsArgPower = unitFormat->getUnitDefinition(child, inKL, reactNo);

  unsigned int undeclaredUnitsPower = 
    unitFormat->getContainsUndeclaredUnits();

  // The second argument (b) should always have units of “dimensionless”.
  // or it has undeclared units that we assume are correct

  if (undeclaredUnitsPower == 0 && !UnitDefinition::areEquivalent(&dim, unitsArgPower))
  {
    logNonDimensionlessPowerConflict(node, sb);
  }

  // The first argument is dimensionless then it doesnt matter 
  // what the power is

  if (undeclaredUnits == 0 && !UnitDefinition::areEquivalent(&dim, unitsArg1))
  {
    // if not argument needs to be an integer or a rational 
    unsigned int isInteger = 0;
    unsigned int isRational = 0;
    unsigned int isExpression = 0;
    /* power must be an integer
     * but need to check that it is not a real
     * number that is integral
     * i.e. mathml <cn> 2 </cn> will record a "real"
     */
    if (child->isRational())
    {
      isRational = 1;
    }
    else if (child->isInteger())
    {
      isInteger = 1;
    }
    else if (child->isReal())
    {
      if (ceil(child->getReal()) == child->getReal())
      {
        isInteger = 1;
      }
    }
    else if (child->getNumChildren() > 0)

    {
      // power might itself be an expression
      tempUD = unitFormat->getUnitDefinition(child, inKL, reactNo);
      UnitDefinition::simplify(tempUD);

      if (tempUD->isVariantOfDimensionless())
      {
        SBMLTransforms::mapComponentValues(&m);
        double value = SBMLTransforms::evaluateASTNode(child);
        SBMLTransforms::clearComponentValues();

#if defined(__linux) 
        if (!std::isnan(value))
#else
        if (!isnan(value))	
#endif   
        {
          if (floor(value) != value)
            isExpression = 1;
          else
            isInteger = 1;
        }
        else
        {
          isExpression = 1;
        }
      }
      else
      {
        /* here the child is an expression with units
        * flag the expression as not checked
        */
        isExpression = 1;
      }
    }
    else 
    {
      // power could be a parameter or a speciesReference in l3
      const Parameter *param = NULL;
      const SpeciesReference *sr = NULL;

      if (child->isName())
      {
        /* Parameters may be declared in two places (the model and the
        * kinetic law's local parameter list), so we have to check both.
        */

        if (sb.getTypeCode() == SBML_KINETIC_LAW)
        {
	        const KineticLaw* kl = dynamic_cast<const KineticLaw*>(&sb);

	        /* First try local parameters and if null is returned, try
	        * the global parameters */
	        if (kl != NULL)
	        {
	          param = kl->getParameter(child->getName());
	        }
        }

	      if (param == NULL)
	      {
	        param = m.getParameter(child->getName());
	      }

        if (param == NULL && m.getLevel() > 2)
        {
          // could be a species reference
          sr = m.getSpeciesReference(child->getName());
        }
        
      }

      if (param != NULL)
      {
        /* We found a parameter with this identifier. */

        if (UnitDefinition::areEquivalent(&dim, unitsArgPower) || undeclaredUnitsPower)
        {
          value = param->getValue();
          if (value != 0)
          {
            if (ceil(value) == value)
            {
              isInteger = 1;
            }
          }

        }
        else
        {
	  /* No parameter definition found for child->getName() */
          logUnitConflict(node, sb);
        }
      }
      else if (sr != NULL)
      {
        // technically here there is an issue
        // stoichiometry is dimensionless
        SBMLTransforms::mapComponentValues(&m);
        double value = SBMLTransforms::evaluateASTNode(child, &m);
        SBMLTransforms::clearComponentValues();
        // but it may not be an integer
	
#if defined(__linux) 
        if (!std::isnan(value))
#else
        if (!isnan(value))	
#endif   
          // we cant check
        {
          isExpression = 1;
        }
        else
        {
          if (ceil(value) == value)
          {
            isInteger = 1;
          }
        }
      }
    }

    if (isRational == 1)
    {
      //FIX-ME will need sorting for double exponents

      //* (2) if the second argument b is a rational number n/m, 
      //* it must be possible to derive the m-th root of (a{unit})n,
      //* where {unit} signifies the units associated with a; 
      unsigned int impossible = 0;
      for (unsigned int n = 0; impossible == 0 && n < unitsArg1->getNumUnits(); n++)
      {
        if ((int)(unitsArg1->getUnit(n)->getExponent()) * child->getInteger() %
          child->getDenominator() != 0)
          impossible = 1;
      }

      if (impossible)
        logRationalPowerConflict(node, sb);

    }
    else if (isExpression == 1)
    {
      logExpressionPowerConflict(node, sb);
    }
    else if (isInteger == 0)
    {
      logNonIntegerPowerConflict(node, sb);
    }

  }




 // if (!areEquivalent(dim, unitsPower)) 
 // {
 //   /* 'v' does not have units of dimensionless. */

 //   /* If the power 'n' is a parameter, check if its units are either
 //    * undeclared or declared as dimensionless.  If either is the case,
 //    * the value of 'n' must be an integer.
 //    */

 //   const Parameter *param = NULL;

 //   if (child->isName())
 //   {
 //     /* Parameters may be declared in two places (the model and the
 //      * kinetic law's local parameter list), so we have to check both.
 //      */

 //     if (sb.getTypeCode() == SBML_KINETIC_LAW)
 //     {
	//      const KineticLaw* kl = dynamic_cast<const KineticLaw*>(&sb);

	//      /* First try local parameters and if null is returned, try
	//      * the global parameters */
	//      if (kl != NULL)
	//      {
	//        param = kl->getParameter(child->getName());
	//      }
 //     }

	//    if (param == NULL)
	//    {
	//      param = m.getParameter(child->getName());
	//    }
 //     
 //   }

 //   if (param != NULL)
 //   {
 //     /* We found a parameter with this identifier. */

 //     if (areEquivalent(dim, unitsArgPower) || unitFormat->hasUndeclaredUnits(child))
 //     {
 //       value = param->getValue();
 //       if (value != 0)
 //       {
 //         if (ceil(value) != value)
 //         {
 //           logUnitConflict(node, sb);
 //         }
 //       }

 //     }
 //     else
 //     {
	///* No parameter definition found for child->getName() */
 //       logUnitConflict(node, sb);
 //     }
 //   }
 //   else if (child->isFunction() || child->isOperator())
 //   {
 //     /* cannot test whether the value will be appropriate */
 //     if (!areEquivalent(dim, unitsArgPower))
 //     {
 //       logUnitConflict(node, sb);
 //     }
 //   }
 //   /* power must be an integer
 //    * but need to check that it is not a real
 //    * number that is integral
 //    * i.e. mathml <cn> 2 </cn> will record a "real"
 //    */
 //   else if (!child->isInteger())
 //   {
 //     if (!child->isReal()) 
 //     {
 //       logUnitConflict(node, sb);
 //     }
 //     else if (ceil(child->getReal()) != child->getReal())
 //     {
 //       logUnitConflict(node, sb);
 //     }
 //   }
 // }
 // else if (!areEquivalent(dim, unitsArgPower)) 
 // {
 //   /* power (3, k) */
 //   logUnitConflict(node, sb);
 // }

  checkUnits(m, *node.getLeftChild(), sb, inKL, reactNo);

  delete unitFormat;
  delete unitsArg1;
  delete unitsArgPower;
}
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;
}
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;
}