void 
AssignmentCycles::addRuleDependencies(const Model& m, const Rule& object)
{
  unsigned int ns;
  std::string thisId = object.getVariable();

  /* loop thru the list of names in the Math
    * if they refer to a Reaction, an Assignment Rule
    * or an Initial Assignment add to the map
    * with the variable as key
    */
  List* variables = object.getMath()->getListOfNodes( ASTNode_isName );
  for (ns = 0; ns < variables->getSize(); ns++)
  {
    ASTNode* node = static_cast<ASTNode*>( variables->get(ns) );
    string   name = node->getName() ? node->getName() : "";

    if (m.getReaction(name))
    {
      mIdMap.insert(pair<const std::string, std::string>(thisId, name));
    }
    else if (m.getRule(name) && m.getRule(name)->isAssignment())
    {
      mIdMap.insert(pair<const std::string, std::string>(thisId, name));
    }
    else if (m.getInitialAssignment(name))
    {
      mIdMap.insert(pair<const std::string, std::string>(thisId, name));
    }
  }

  delete variables;
}
/*
 * @return the error message to use when logging constraint violations.
 * This method is called by logFailure.
 *
 * Returns a message that the given @p id and its corresponding object are
 * in  conflict with an object previously defined.
 */
const string
CiElementMathCheck::getMessage (const ASTNode& node, const SBase& object)
{

  ostringstream msg;

  //msg << getPreamble();
  char * formula = SBML_formulaToString(&node);
  msg << "The formula '" << formula;
  msg << "' in the " << getFieldname() << " element of the <" << object.getElementName();
  msg << "> ";
  switch(object.getTypeCode()) {
  case SBML_INITIAL_ASSIGNMENT:
  case SBML_EVENT_ASSIGNMENT:
  case SBML_ASSIGNMENT_RULE:
  case SBML_RATE_RULE:
    //LS DEBUG:  could use other attribute values, or 'isSetActualId'.
    break;
  default:
    if (object.isSetId()) {
      msg << "with id '" << object.getId() << "' ";
    }
    break;
  }
  if (object.getLevel() == 2 && object.getVersion() == 1)
    msg << "uses '" << node.getName() << "' that is not the id of a species/compartment/parameter.";
  else if (object.getLevel() < 3)
    msg << "uses '" << node.getName() << "' that is not the id of a species/compartment/parameter/reaction.";
  else
    msg << "uses '" << node.getName() << "' that is not the id of a species/compartment/parameter/reaction/speciesReference.";
  safe_free(formula);

  return msg.str();
}
/**
  * 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 
FunctionDefinitionRecursion::addDependencies(const Model& m, 
                                         const FunctionDefinition& object)
{
  unsigned int ns;
  std::string thisId = object.getId();

  /* loop thru the list of names in the Math
    * if they refer to a FunctionDefinition add to the map
    * with the variable as key
    */
  List* variables = object.getMath()->getListOfNodes( ASTNode_isFunction );
  for (ns = 0; ns < variables->getSize(); ns++)
  {
    ASTNode* node = static_cast<ASTNode*>( variables->get(ns) );
    string   name = node->getName() ? node->getName() : "";

    if (m.getFunctionDefinition(name))
    {
      mIdMap.insert(pair<const std::string, std::string>(thisId, name));
    }
  }

  delete variables;
}
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);

}
/**
 * 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)));
    }
};
/*
 * @return the error message to use when logging constraint violations.
 * This method is called by logFailure.
 *
 * Returns a message that the given @p id and its corresponding object are
 * in  conflict with an object previously defined.
 */
const string
FunctionApplyMathCheck::getMessage (const ASTNode& node, const SBase& object)
{

  ostringstream msg;

  //msg << getPreamble();
  char * formula = SBML_formulaToString(&node);
  msg << "The formula '" << formula;
  msg << "' in the " << getFieldname() << " element of the <" << object.getElementName();
  msg << "> ";
  switch(object.getTypeCode()) {
  case SBML_INITIAL_ASSIGNMENT:
  case SBML_EVENT_ASSIGNMENT:
  case SBML_ASSIGNMENT_RULE:
  case SBML_RATE_RULE:
    //LS DEBUG:  could use other attribute values, or 'isSetActualId'.
    break;
  default:
    if (object.isSetId()) {
      msg << "with id '" << object.getId() << "' ";
    }
    break;
  }
  msg << "uses '" << node.getName() << "' which is not a function definition id.";
  safe_free(formula);

  return msg.str();
}
/**
  * Checks any <ci> elements in the MathML of the ASTnode 
  * contain the id of an appropriate component of the model
  *
  * If an inconsistency is found, an error message is logged.
  */
void 
LocalParameterMathCheck::checkCiElement (const Model& m, 
                                        const ASTNode& node, 
                                        const SBase & sb)
{
  std::string name = node.getName();
  const KineticLaw * kl;

  if (m.getCompartment(name) == NULL &&
      m.getSpecies(name)     == NULL &&
      m.getParameter(name)   == NULL &&
      m.getReaction(name)    == NULL)
  {

    /* check whether we are in a kinetic law since there
     * may be local parameters to this law that are allowed
     */

    if (sb.getTypeCode() == SBML_KINETIC_LAW)
    {
      kl = m.getReaction(mKLCount)->getKineticLaw();

      if (kl->getParameter(name) == NULL && mLocalParameters.contains(name))
      {
        logMathConflict(node, sb);
      }
    }
    else if (mLocalParameters.contains(name))
    {
        logMathConflict(node, sb);
    }
  }
    
}
void TestASTNode::testConstructor()
{
	ASTNode* node = new ASTNode("value", PROGRAM, 1);

	CPPUNIT_ASSERT("value" == node->getName());
	CPPUNIT_ASSERT_EQUAL(PROGRAM, node->getType());
	CPPUNIT_ASSERT_EQUAL(1, node->getStatementNumber());
}
/*
  * Checks that the functionDefinition referred to by a &lt;ci&gt; element exists
  *
  * If <ci> does not refer to functionDefinition id, an error message is logged.
  */
void 
FunctionApplyMathCheck::checkExists (const Model& m, const ASTNode& node, 
                                                const SBase & sb)
{
  std::string name = node.getName();

  if (!m.getFunctionDefinition(name))
    logMathConflict(node, sb);
}
/**
 * @return the error message to use when logging constraint violations.
 * This method is called by logFailure.
 *
 * Returns a message that the given id and its corresponding object are
 * in  conflict with an object previously defined.
 */
const string
CiElementMathCheck::getMessage (const ASTNode& node, const SBase& object)
{

  ostringstream msg;

  //msg << getPreamble();
  char * formula = SBML_formulaToString(&node);
  msg << "\nThe formula '" << formula;
  msg << "' in the " << getFieldname() << " element of the " << getTypename(object);
  if (object.getLevel() == 2 && object.getVersion() == 1)
    msg << " uses '" << node.getName() << "' that is not the id of a species/compartment/parameter.";
  else
    msg << " uses '" << node.getName() << "' that is not the id of a species/compartment/parameter/reaction.";
  safe_free(formula);

  return msg.str();
}
Beispiel #12
0
std::string AST::getCalledProcedure(int stmtNum)
{
    ASTNode* node = getStatementNode(stmtNum);

    if (node->getType() == CALL) {
        return node->getName();
    } else {
        return "";
    }
}
bool
containsId(const ASTNode* ast, std::string id)
{
  bool present = false;
  List* variables = ast->getListOfNodes(ASTNode_isName);
  IdList vars;
  for (unsigned int i = 0; i < variables->getSize(); i++)
  {
    ASTNode* node = static_cast<ASTNode*>(variables->get(i));
    string   name = node->getName() ? node->getName() : "";
    vars.append(name);
  }
  if (vars.contains(id))
  {
    present = true;
  }
  delete variables;

  return present;
}
void 
AssignmentRuleOrdering::checkRuleForVariable(const Model& m, const Rule& object)
{
  /* list the <ci> elements */
  List* variables = object.getMath()->getListOfNodes( ASTNode_isName );
  std::string variable = object.getVariable();

  if (variables)
  {
    for (unsigned int i = 0; i < variables->getSize(); i++)
    {
      ASTNode* node = static_cast<ASTNode*>( variables->get(i) );
      const char *   name = node->getName() ? node->getName() : "";
      if (!(strcmp(variable.c_str(), name)))
        logRuleRefersToSelf(*(object.getMath()), object);
    }
    // return value of ASTNode::getListOfNodes() needs to be
    // deleted by caller.
    delete variables;
  }

}
/**
 * Checks that all variables referenced in FunctionDefinition bodies are
 * bound variables (function arguments).
 */
void
FunctionDefinitionVars::check_ (const Model& m, const FunctionDefinition& fd)
{
  if ( fd.getLevel() == 1         ) return;
  if ( !fd.isSetMath()            ) return;
  if ( fd.getBody()  == NULL      ) return;
  if (  fd.getNumArguments() == 0 ) return;


  List* variables = fd.getBody()->getListOfNodes( ASTNode_isName );


  for (unsigned int n = 0; n < variables->getSize(); ++n)
  {
    ASTNode* node = static_cast<ASTNode*>( variables->get(n) );
    string   name = node->getName() ? node->getName() : "";

    if ( fd.getArgument(name) == NULL ) 
    {
      /* if this is the csymbol time - technically it is allowed 
       * in L2v1 and L2v2
       */
      if (node->getType() == AST_NAME_TIME)
      {
        if (fd.getLevel() > 2
          || (fd.getLevel() == 2 && fd.getVersion() > 2))
        {
          logUndefined(fd, name);
        }
      }
      else
      {
        logUndefined(fd, name);
      }
    }
  }
  
  delete variables;
}
/**
 * @return the error message to use when logging constraint violations.
 * This method is called by logFailure.
 *
 * Returns a message that the given id and its corresponding object are
 * in  conflict with an object previously defined.
 */
const string
LocalParameterMathCheck::getMessage (const ASTNode& node, const SBase& object)
{

  ostringstream msg;

  //msg << getPreamble();

  msg << "\nThe formula '";
  msg << "' in the " << getFieldname() << " element of the " << getTypename(object);
  msg << " uses '" << node.getName() << "' that is the id of a local parameter.";

  return msg.str();
}
/*
 * Checks that all variables referenced in FunctionDefinition bodies are
 * bound variables (function arguments).
 */
void
KineticLawVars::check_ (const Model& m, const Reaction& r)
{
  unsigned int n;
  
  /* create list of all species in the reaction */
  for (n = 0; n < r.getNumReactants(); n++)
  {
    mSpecies.append(r.getReactant(n)->getSpecies());
  }
  for (n = 0; n < r.getNumProducts(); n++)
  {
    mSpecies.append(r.getProduct(n)->getSpecies());
  }
  for (n = 0; n < r.getNumModifiers(); n++)
  {
    mSpecies.append(r.getModifier(n)->getSpecies());
  }

  if ( r.isSetKineticLaw() && r.getKineticLaw()->isSetMath() )
  {
    const ASTNode* math  = r.getKineticLaw()->getMath();
    List*    names = math->getListOfNodes( ASTNode_isName );

    for (n = 0; n < names->getSize(); ++n)
    {
      ASTNode*    node = static_cast<ASTNode*>( names->get(n) );
      string   name = node->getName() ? node->getName() : "";

      if (m.getSpecies(name) != NULL && !mSpecies.contains(name) )
        logUndefined(r, name);
    }
    delete names;
  }

  mSpecies.clear();
}
/*
  * Checks any &lt;ci&gt; elements in the MathML of the ASTnode 
  * contain the id of an appropriate component of the model
  *
  * If an inconsistency is found, an error message is logged.
  */
void 
CiElementMathCheck::checkCiElement (const Model& m, 
                                        const ASTNode& node, 
                                        const SBase & sb)
{
  std::string name = node.getName();
  const KineticLaw * kl;

  /* leave out this check if the ci element is a local parameter in a kineticLaw
   * caught by LocalParameterMathCheck instead
   */
  if (!mLocalParameters.contains(name))
  {
    bool allowReactionId = true;
    bool allowSpeciesRef = false;

    if ( (m.getLevel() == 2) && (m.getVersion() == 1) )
      allowReactionId = false;

    if (m.getLevel() > 2)
      allowSpeciesRef = true;

    if (m.getCompartment(name) == NULL &&
        m.getSpecies(name)     == NULL &&
        m.getParameter(name)   == NULL &&
        (!allowReactionId || m.getReaction(name) == NULL ) &&
        (!allowSpeciesRef || m.getSpeciesReference(name) == NULL ) )
    {
      /* check whether we are in a kinetic law since there
      * may be local parameters
      */

      if (sb.getTypeCode() == SBML_KINETIC_LAW)
      {
        kl = m.getReaction(mKLCount)->getKineticLaw();

        if (kl->getParameter(name) == NULL)
        {
          logMathConflict(node, sb);
        }
      }
      else
      {
          logMathConflict(node, sb);
      }
    }
  }
    
}
void 
AssignmentRuleOrdering::checkRuleForLaterVariables(const Model& m, 
                                                   const Rule& object,
                                                   unsigned int n)
{
  /* list the <ci> elements of this rule*/
  List* variables = object.getMath()->getListOfNodes( ASTNode_isName );

  if (variables)
  {
    unsigned int index;
    for (unsigned int i = 0; i < variables->getSize(); i++)
    {
      ASTNode* node = static_cast<ASTNode*>( variables->get(i) );
      const char *   name = node->getName() ? node->getName() : "";
  
      if (mVariableList.contains(name))
      {
        // this <ci> is a variable
        // check that it occurs later
        index = 0; 
        while(index < mVariableList.size())
        {
          if (!strcmp(name, mVariableList.at(index).c_str()))
            break;
          index++;
        }
        if (index > n)
          logForwardReference(*(object.getMath()), object, name);
      }
    }
    // return value of ASTNode::getListOfNodes() needs to be
    // deleted by caller.
    delete variables;
  }
}
/**
 * @return the error message to use when logging constraint violations.
 * This method is called by logFailure.
 *
 * Returns a message that the given id and its corresponding object are
 * in  conflict with an object previously defined.
 */
const string
FunctionApplyMathCheck::getMessage (const ASTNode& node, const SBase& object)
{

  ostringstream msg;

  //msg << getPreamble();
  char * formula = SBML_formulaToString(&node);
  msg << "\nThe formula '" << formula;
  msg << "' in the " << getFieldname() << " element of the " << getTypename(object);
  msg << " uses '" << node.getName() << "' which is not a function definition id.";
  safe_free(formula);

  return msg.str();
}
/**
 * @return the error message to use when logging constraint violations.
 * This method is called by logFailure.
 *
 * Returns a message that the given id and its corresponding object are
 * in  conflict with an object previously defined.
 */
const string
FunctionNoArgsMathCheck::getMessage (const ASTNode& node, const SBase& object)
{

  ostringstream msg;

  //msg << getPreamble();
  char * formula = SBML_formulaToString(&node);
  msg << "\nThe formula '" << formula;
  msg << "' in the " << getFieldname() << " element of the ";
  msg << getTypename(object);
  msg << " uses the function '" << node.getName() << "' which requires ";
  msg << "a different number of arguments than the number supplied.";
  safe_free(formula);

  return msg.str();
}
/**
  * Checks the MathML of the ASTnode 
  * is appropriate for the function being performed
  *
  * If an inconsistency is found, an error message is logged.
  */
void
NumberArgsMathCheck::checkMath (const Model& m, const ASTNode& node, const SBase & sb)
{
  ASTNodeType_t type = node.getType();

  switch (type) 
  {
  case AST_FUNCTION_ABS:
  case AST_FUNCTION_ARCCOS:
  case AST_FUNCTION_ARCCOSH:
  case AST_FUNCTION_ARCCOT:
  case AST_FUNCTION_ARCCOTH:
  case AST_FUNCTION_ARCCSC:
  case AST_FUNCTION_ARCCSCH:
  case AST_FUNCTION_ARCSEC:
  case AST_FUNCTION_ARCSECH:
  case AST_FUNCTION_ARCSIN:
  case AST_FUNCTION_ARCSINH:
  case AST_FUNCTION_ARCTAN:
  case AST_FUNCTION_ARCTANH:
  case AST_FUNCTION_CEILING:
  case AST_FUNCTION_COS:
  case AST_FUNCTION_COSH:
  case AST_FUNCTION_COT:
  case AST_FUNCTION_COTH:
  case AST_FUNCTION_CSC:
  case AST_FUNCTION_CSCH:
  case AST_FUNCTION_EXP:
  case AST_FUNCTION_FACTORIAL:
  case AST_FUNCTION_FLOOR:
  case AST_FUNCTION_LN:
  case AST_FUNCTION_SEC:
  case AST_FUNCTION_SECH:
  case AST_FUNCTION_SIN:
  case AST_FUNCTION_SINH:
  case AST_FUNCTION_TAN:
  case AST_FUNCTION_TANH:
  case AST_LOGICAL_NOT:

    checkUnary(m, node, sb);
      break;

    case AST_DIVIDE:
    case AST_POWER:
    case AST_RELATIONAL_NEQ:
    case AST_FUNCTION_DELAY:
    case AST_FUNCTION_POWER:
    case AST_FUNCTION_LOG:       // a log ASTNode has a child for base

    checkBinary(m, node, sb);
      break;

    case AST_TIMES:
    case AST_PLUS:
    case AST_LOGICAL_AND:
    case AST_LOGICAL_OR:
    case AST_LOGICAL_XOR:
    case AST_RELATIONAL_EQ:
    case AST_RELATIONAL_GEQ:
    case AST_RELATIONAL_GT:
    case AST_RELATIONAL_LEQ:
    case AST_RELATIONAL_LT:
    case AST_FUNCTION_PIECEWISE:

     checkNary(m, node, sb);
      break;

    case AST_FUNCTION_ROOT:
    case AST_MINUS:
      
      checkSpecialCases(m, node, sb);
      break;

      
    case AST_FUNCTION:
      /* the case for a functionDefinition has its own rule
         from l2v4*/

      if (m.getLevel() < 3 && m.getVersion() < 4)
      {
        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() + 1 != fdMath->getNumChildren())
	          {
              logMathConflict(node, sb);
	          }
          }

        }
      }
      break;

    default:

      checkChildren(m, node, sb);
      break;

  }

}
/*
 * Checks that all variables referenced in FunctionDefinition bodies are
 * bound variables (function arguments).
 */
void
FunctionDefinitionVars::check_ (const Model& m, const FunctionDefinition& fd)
{
  if ( fd.getLevel() == 1         ) return;
  if ( !fd.isSetMath()            ) return;
  if ( fd.getBody()  == NULL      ) return;
  //if (  fd.getNumArguments() == 0 ) return;


  List* variables = fd.getBody()->getListOfNodes( ASTNode_isName );


  for (unsigned int n = 0; n < variables->getSize(); ++n)
  {
    ASTNode* node = static_cast<ASTNode*>( variables->get(n) );
    string   name = node->getName() ? node->getName() : "";

    if ( fd.getArgument(name) == NULL ) 
    {
      /* if this is the csymbol time - technically it is allowed 
       * in L2v1 and L2v2
       */
      if (node->getType() == AST_NAME_TIME)
      {
        if (fd.getLevel() > 2
          || (fd.getLevel() == 2 && fd.getVersion() > 2))
        {
          logUndefined(fd, name);
        }
      }
      else
      {
        logUndefined(fd, name);
      }
    }
  }

  if ((m.getLevel() == 2 && m.getVersion() == 5)
    || (m.getLevel() == 3 && m.getVersion() > 1))
  { // check we dont use delay csymbol
    delete variables;
    variables = fd.getBody()->getListOfNodes( ASTNode_isFunction );
    
    for (unsigned int n = 0; n < variables->getSize(); ++n)
    {
      ASTNode* node = static_cast<ASTNode*>( variables->get(n) );

      if (node->getType() == AST_FUNCTION_DELAY)
      {
        logUndefined(fd, node->getName());
      }
    }
  }


  //Check we don't use a function defined in a plugin (like rateOf)
  delete variables;
  variables = fd.getBody()->getListOfNodes(ASTNode_isFunction);

  for (unsigned int n = 0; n < variables->getSize(); ++n)
  {
    ASTNode* node = static_cast<ASTNode*>(variables->get(n));

    const ASTBasePlugin* plugin = node->getASTPlugin(node->getType());
    if (plugin != NULL)
    {
      if (plugin->allowedInFunctionDefinition(node->getType()) == 0)
      {
        logUndefined(fd, node->getName());
      }
    }
  }
  delete variables;
}
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);

}
void 
AssignmentCycles::checkForImplicitCompartmentReference(const Model& m)
{
  mIdMap.clear();

  unsigned int i, ns;
  std::string id;

  for (i = 0; i < m.getNumInitialAssignments(); i++)
  {
    if (m.getInitialAssignment(i)->isSetMath())
    {
      id = m.getInitialAssignment(i)->getSymbol();
      if (m.getCompartment(id) 
        && m.getCompartment(id)->getSpatialDimensions() > 0)
      {
        List* variables = m.getInitialAssignment(i)->getMath()
                                        ->getListOfNodes( ASTNode_isName );
        for (ns = 0; ns < variables->getSize(); ns++)
        {
          ASTNode* node = static_cast<ASTNode*>( variables->get(ns) );
          string   name = node->getName() ? node->getName() : "";
          if (!name.empty() && !alreadyExistsInMap(mIdMap, pair<const std::string, std::string>(id, name)))
            mIdMap.insert(pair<const std::string, std::string>(id, name));
        }
        delete variables;
      }
    }
  }

  for (i = 0; i < m.getNumRules(); i++)
  {
    if (m.getRule(i)->isSetMath() && m.getRule(i)->isAssignment())
    {
      id = m.getRule(i)->getVariable();
      if (m.getCompartment(id) 
        && m.getCompartment(id)->getSpatialDimensions() > 0)
      {
        List* variables = m.getRule(i)->getMath()->getListOfNodes( ASTNode_isName );
        for (ns = 0; ns < variables->getSize(); ns++)
        {
          ASTNode* node = static_cast<ASTNode*>( variables->get(ns) );
          string   name = node->getName() ? node->getName() : "";
          if (!name.empty() && !alreadyExistsInMap(mIdMap, pair<const std::string, std::string>(id, name)))
            mIdMap.insert(pair<const std::string, std::string>(id, name));
        }
        delete variables;
      }
    }
  }

  IdIter it;
  IdRange range;

  for (i = 0; i < m.getNumCompartments(); i++)
  {
    std::string id = m.getCompartment(i)->getId();
    range = mIdMap.equal_range(id);
    for (it = range.first; it != range.second; it++)
    {
      const Species *s = m.getSpecies((*it).second);
      if (s && s->getCompartment() == id
        && s->getHasOnlySubstanceUnits() == false)
      {
        logImplicitReference(m, id, s);
      }
    }
  }
}
/**
  * 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;
}