31 double trunc(
double x)
32 {
return (x < 0.0) ? -floor(fabs(x)) : floor(x);}
91 else if (rhs.mStatus & known)
95 std::cout <<
" *: " << *
this <<
" * " << rhs <<
" = " << ret << std::endl;
106 if ((this->getStatus() & invalid) || (rhs.
getStatus() & invalid))
113 v1 =
this; v2 = &rhs;
128 if ((this->mStatus & known) && (rhs.
mStatus & known))
130 else if (this->mStatus & known)
131 ret.
Or(generalize(this->mDouble) / rhs);
136 std::cout <<
" /: " << *
this <<
" / " << rhs <<
" = " << ret << std::endl;
147 if ((this->getStatus() & invalid) || (rhs.
getStatus() & invalid))
151 if (this->getStatus() & zero)
159 v1 =
this; v2 = &rhs;
163 if ((v1->
mStatus & negative) && (v2->
mStatus & positive)) ret.
Or(negative | zero | positive);
165 if ((v1->
mStatus & positive) && (v2->
mStatus & negative)) ret.
Or(negative | zero | positive);
172 if ((this->mStatus & negative) && (rhs.
mStatus & known)) ret.
Or(*
this + generalize(rhs.
mDouble));
174 if ((this->mStatus & positive) && (rhs.
mStatus & known)) ret.
Or(*
this + generalize(rhs.
mDouble));
176 if ((this->mStatus & known) && (rhs.
mStatus & negative)) ret.
Or(generalize(this->mDouble) + rhs);
178 if ((this->mStatus & known) && (rhs.
mStatus & positive)) ret.
Or(generalize(this->mDouble) + rhs);
181 std::cout <<
" +: " << *
this <<
" + " << rhs <<
" = " << ret << std::endl;
190 ret.
mStatus =
Status(this->mStatus & (zero | invalid | known));
192 if (this->mStatus & known) ret.
mDouble = -this->mDouble;
194 if (this->mStatus & positive) ret.
Or(negative);
196 if (this->mStatus & negative) ret.
Or(positive);
203 return *
this + rhs.
invert();
211 if ((this->getStatus() & invalid) || (rhs.
getStatus() & invalid))
215 v1 =
this; v2 = &rhs;
217 if ((v1->
mStatus & negative) && (v2->
mStatus & negative)) ret.
Or(negative | positive | invalid);
221 if ((v1->
mStatus & negative) && (v2->
mStatus & positive)) ret.
Or(negative | positive | invalid);
241 if ((this->mStatus & known) && ((rhs.
mStatus & negative)
245 if (this->mDouble == 1.0)
248 ret.
Or(generalize(this->mDouble) ^ rhs);
252 if (((this->mStatus & negative)
253 || (this->mStatus & zero)
254 || (this->mStatus & positive)) && (rhs.
mStatus & known))
260 if (this->mStatus & negative) ret.
Or(positive);
262 if (this->mStatus & zero) ret.
Or(zero);
264 if (this->mStatus & positive) ret.
Or(positive);
268 if (this->mStatus & negative) ret.
Or(negative);
270 if (this->mStatus & zero) ret.
Or(zero);
272 if (this->mStatus & positive) ret.
Or(positive);
280 std::cout <<
" ^: " << *
this <<
" ^ " << rhs <<
" = " << ret << std::endl;
302 if (d == 0.0)
return zero;
303 else if (d > 0.0)
return positive;
304 else if (d < 0.0)
return negative;
310 if ((this->mStatus & known) && (v.
mStatus & known) && (this->mDouble != v.
mDouble))
313 CValue tmp = generalize(this->mDouble);
326 if (mStatus == positive)
return true;
328 if ((mStatus == known) && (mDouble > 0.0))
return true;
335 if (mStatus & positive)
return true;
337 if ((mStatus & known) && (mDouble > 0.0))
return true;
344 if (mStatus == zero)
return true;
346 if ((mStatus == known) && (mDouble == 0.0))
return true;
353 if (mStatus & zero)
return true;
355 if ((mStatus & known) && (mDouble == 0.0))
return true;
362 if (mStatus == negative)
return true;
364 if ((mStatus == known) && (mDouble < 0.0))
return true;
371 if (mStatus & negative)
return true;
373 if ((mStatus & known) && (mDouble < 0.0))
return true;
380 if (mStatus == invalid)
return true;
387 if (mStatus & invalid)
return true;
394 if (mStatus != rhs.
mStatus)
return false;
396 if ((mStatus & known) && (mDouble != rhs.
mDouble))
return false;
405 mIrreversibleKineticsWithProducts(false),
406 mReversibleNonSplitable(false)
413 if (!mpFunction)
return false;
416 if (rt) os <<
"<h3>";
418 os << mpFunction->getObjectName();
420 if (rt) os <<
"</h3>";
424 if (mIrreversibleKineticsWithProducts)
426 os <<
write(1, rt,
"The kinetic function is marked as irreversible but at least one of its variables is labeled as product.\n",
"");
431 bool isReversible = (mpFunction->isReversible() ==
TriTrue);
433 std::ostringstream tmpss;
438 eee = mOriginalFunction.writeAnalysis(tmpss, rt, isReversible);
445 mOriginalFunction.writeTable(os, rt);
449 if (mReversibleNonSplitable)
451 os <<
write(1, rt,
"Copasi is not able to split the reversible kinetic function into two irreversible functions.\n",
"");
454 else if (isReversible)
456 std::ostringstream tmpss1;
457 bool eee1 = mFPart.writeAnalysis(tmpss1, rt,
false);
459 std::ostringstream tmpss2;
460 bool eee2 = mBPart.writeAnalysis(tmpss2, rt,
false);
462 if (eee1 || eee2) ret =
true;
464 if (eee1 || eee2 || verbose)
466 os <<
"The function was split into forward and backwards parts. Forward part:\n";
468 if (rt) os <<
"<br>";
471 mFPart.writeTable(os, rt);
472 os <<
" Backwards part:\n";
474 if (rt) os <<
"<br>";
477 mBPart.writeTable(os, rt);
491 assert(mUnchangedParameters.size() >= 2);
494 if (!mUnchangedParameters[1].containsPositive())
496 os <<
write(1, rt,
"The kinetic function cannot take positive values for positive parameter values.\n",
497 "This means the reaction will never proceed in the forward direction.");
501 if (!mUnchangedParameters[1].containsZero())
503 os <<
write(1, rt,
"The kinetic function never equals zero for positive parameter values.\n",
504 "This is unexpected for reversible reactions.");
508 if (!mUnchangedParameters[1].containsNegative())
510 os <<
write(1, rt,
"The kinetic function cannot take negative values for positive parameter values.\n",
511 "This means the reaction will never proceed in the backwards direction.");
515 if (mUnchangedParameters[1].isInvalid())
517 os <<
write(2, rt,
"The kinetic function is always invalid for positive parameter values.\n",
"");
520 else if (mUnchangedParameters[1].containsInvalid())
522 os <<
write(1, rt,
"The kinetic function can be invalid even if metabolite concentrations and parameter values are positive.\n",
"");
527 if ((mUnchangedParameters.size() > 2) && (!(mUnchangedParameters[1] == mUnchangedParameters[2])))
529 if (!mUnchangedParameters[2].containsPositive())
531 os <<
write(1, rt,
"The kinetic function cannot take positive values for the actual parameter values.\n",
532 "This means the reaction will never proceed in the forward direction.");
536 if (!mUnchangedParameters[2].containsZero())
538 os <<
write(1, rt,
"The kinetic function never equals zero for the actual parameter values.\n",
539 "This is unexpected for reversible reactions.");
543 if (!mUnchangedParameters[2].containsNegative())
545 os <<
write(1, rt,
"The kinetic function cannot take negative values for the actual parameter values.\n",
546 "This means the reaction will never proceed in the backwards direction.");
550 if (mUnchangedParameters[2].isInvalid())
552 os <<
write(2, rt,
"The kinetic function is always invalid for the actual parameter values.\n",
"");
555 else if (mUnchangedParameters[2].containsInvalid())
557 os <<
write(1, rt,
"The kinetic function can be invalid for the actual parameter values even if metabolite concentrations are positive.\n",
"");
565 imax = mSubstrateZero.size();
567 for (i = 0; i < imax; ++i)
569 assert(mSubstrateZero[i].second.size() >= 2);
572 if (mSubstrateZero[i].second[1].isNegative())
574 os <<
write(0, rt,
"The kinetic function is always negative for positive parameter values if substrate \""
575 + mSubstrateZero[i].first.second
576 +
"\" is set to zero.\n" ,
577 "This is the expected behaviour for reversible reactions. Without substrates the reaction can only proceed backwards.");
579 else if (mSubstrateZero[i].second[1].containsNegative())
581 os <<
write(1, rt,
"Copasi could not show that the kinetic function is always negative for positive parameter values if substrate \""
582 + mSubstrateZero[i].first.second
583 +
"\" is set to zero.\n" ,
"");
588 os <<
write(2, rt,
"The kinetic function is never negative for positive parameter values if substrate \""
589 + mSubstrateZero[i].first.second
590 +
"\" is set to zero.\n" ,
591 "This means the reaction never proceeds backwards even if no substrate is present. This is unexpected for a reversible reaction.");
595 if (mSubstrateZero[i].second[1].isInvalid())
597 os <<
write(2, rt,
"The kinetic function is always invalid for positive parameter values if substrate \""
598 + mSubstrateZero[i].first.second
599 +
"\" is set to zero.\n" ,
"");
602 else if (mSubstrateZero[i].second[1].containsInvalid())
604 os <<
write(1, rt,
"The kinetic function can be invalid for positive parameter values if substrate \""
605 + mSubstrateZero[i].first.second
606 +
"\" is set to zero.\n" ,
"");
611 if ((mSubstrateZero[i].second.size() > 2) && (!(mSubstrateZero[i].second[1] == mSubstrateZero[i].second[2])))
613 if (mSubstrateZero[i].second[2].isNegative())
615 os <<
write(0, rt,
"The kinetic function is always negative for the actual parameter values if substrate \""
616 + mSubstrateZero[i].first.second
617 +
"\" is set to zero.\n" ,
618 "This is the expected behaviour for reversible reactions. Without substrates the reaction can only proceed backwards.");
620 else if (mSubstrateZero[i].second[2].containsNegative())
622 os <<
write(1, rt,
"Copasi could not show that the kinetic function is always negative for the actual parameter values if substrate \""
623 + mSubstrateZero[i].first.second
624 +
"\" is set to zero.\n" ,
"");
629 os <<
write(2, rt,
"The kinetic function is never negative for the actual parameter values if substrate \""
630 + mSubstrateZero[i].first.second
631 +
"\" is set to zero.\n" ,
632 "This means the reaction never proceeds backwards even if no substrate is present. This is unexpected for a reversible reaction.");
636 if (mSubstrateZero[i].second[2].isInvalid())
638 os <<
write(2, rt,
"The kinetic function is always invalid for the actual parameter values if substrate \""
639 + mSubstrateZero[i].first.second
640 +
"\" is set to zero.\n" ,
"");
643 else if (mSubstrateZero[i].second[2].containsInvalid())
645 os <<
write(1, rt,
"The kinetic function can be invalid for the actual parameter values if substrate \""
646 + mSubstrateZero[i].first.second
647 +
"\" is set to zero.\n" ,
"");
654 imax = mProductZero.size();
656 for (i = 0; i < imax; ++i)
658 assert(mProductZero[i].second.size() >= 2);
661 if (mProductZero[i].second[1].isPositive())
663 os <<
write(0, rt,
"The kinetic function is always positive for positive parameter values if product \""
664 + mProductZero[i].first.second
665 +
"\" is set to zero.\n" ,
666 "This is the expected behaviour for reversible reactions. With products absent the reaction can only proceed forward.");
668 else if (mProductZero[i].second[1].containsPositive())
670 os <<
write(1, rt,
"Copasi could not show that the kinetic function is always positive for positive parameter values if product \""
671 + mProductZero[i].first.second
672 +
"\" is set to zero.\n" ,
"");
677 os <<
write(2, rt,
"The kinetic function is never positive for positive parameter values if product \""
678 + mProductZero[i].first.second
679 +
"\" is set to zero.\n" ,
680 "This means the reaction never proceeds forward even if no product is present. This is unexpected for a reversible reaction.");
684 if (mProductZero[i].second[1].isInvalid())
686 os <<
write(2, rt,
"The kinetic function is always invalid for positive parameter values if product \""
687 + mProductZero[i].first.second
688 +
"\" is set to zero.\n" ,
"");
691 else if (mProductZero[i].second[1].containsInvalid())
693 os <<
write(1, rt,
"The kinetic function can be invalid for positive parameter values if product \""
694 + mProductZero[i].first.second
695 +
"\" is set to zero.\n" ,
"");
700 if ((mProductZero[i].second.size() > 2) && (!(mProductZero[i].second[1] == mProductZero[i].second[2])))
702 if (mProductZero[i].second[2].isPositive())
704 os <<
write(0, rt,
"The kinetic function is always positive for the actual parameter values if product \""
705 + mProductZero[i].first.second
706 +
"\" is set to zero.\n" ,
707 "This is the expected behaviour for reversible reactions. With products absent the reaction can only proceed forward.");
709 else if (mProductZero[i].second[2].containsPositive())
711 os <<
write(1, rt,
"Copasi could not show that the kinetic function is always positive for the actual parameter values if product \""
712 + mProductZero[i].first.second
713 +
"\" is set to zero.\n" ,
"");
718 os <<
write(2, rt,
"The kinetic function is never positive for the actual parameter values if product \""
719 + mProductZero[i].first.second
720 +
"\" is set to zero.\n" ,
721 "This means the reaction never proceeds forward even if no product is present. This is unexpected for a reversible reaction.");
725 if (mProductZero[i].second[2].isInvalid())
727 os <<
write(2, rt,
"The kinetic function is always invalid for the actual parameter values if substrate \""
728 + mProductZero[i].first.second
729 +
"\" is set to zero.\n" ,
"");
732 else if (mProductZero[i].second[2].containsInvalid())
734 os <<
write(1, rt,
"The kinetic function can be invalid for the actual parameter values if substrate \""
735 + mProductZero[i].first.second
736 +
"\" is set to zero.\n" ,
"");
745 assert(mUnchangedParameters.size() >= 2);
748 if (mUnchangedParameters[1].isPositive())
750 os <<
write(0, rt,
"The kinetic function is positive for positive parameter values.\n",
"");
754 os <<
write(1, rt,
"Copasi could not show that the kinetic function is positive for positive parameter values.\n",
"");
758 if (mUnchangedParameters[1].isZero())
760 os <<
write(2, rt,
"The kinetic function is always zero for positive parameter values.\n",
"");
763 else if (mUnchangedParameters[1].containsZero())
765 os <<
write(1, rt,
"The kinetic function can be zero even if substrate concentrations and parameter values are positive.\n",
"");
769 if (mUnchangedParameters[1].isNegative())
771 os <<
write(2, rt,
"The kinetic function is always negative for positive parameter values.\n",
"");
774 else if (mUnchangedParameters[1].containsNegative())
776 os <<
write(1, rt,
"The kinetic function can be negative even if substrate concentrations and parameter values are positive.\n",
"");
780 if (mUnchangedParameters[1].isInvalid())
782 os <<
write(2, rt,
"The kinetic function is always invalid for positive parameter values.\n",
"");
785 else if (mUnchangedParameters[1].containsInvalid())
787 os <<
write(1, rt,
"The kinetic function can be invalid even if substrate concentrations and parameter values are positive.\n",
"");
792 if ((mUnchangedParameters.size() > 2) && (!(mUnchangedParameters[1] == mUnchangedParameters[2])))
794 if (mUnchangedParameters[2].isPositive())
796 os <<
write(0, rt,
"The kinetic function is positive for the actual parameter values.\n",
"");
800 os <<
write(1, rt,
"Copasi could not show that the kinetic function is positive for the actual parameter values.\n",
"");
804 if (mUnchangedParameters[2].isZero())
806 os <<
write(2, rt,
"The kinetic function is always zero for the actual parameter values.\n",
"");
809 else if (mUnchangedParameters[2].containsZero())
811 os <<
write(1, rt,
"The kinetic function can be zero for the actual parameter values even if substrate concentrations are positive.\n",
"");
815 if (mUnchangedParameters[2].isNegative())
817 os <<
write(2, rt,
"The kinetic function is always negative for the actual parameter values.\n",
"");
820 else if (mUnchangedParameters[2].containsNegative())
822 os <<
write(1, rt,
"The kinetic function can be negative for the actual parameter values even if substrate concentrations are positive.\n",
"");
826 if (mUnchangedParameters[2].isInvalid())
828 os <<
write(2, rt,
"The kinetic function is always invalid for the actual parameter values.\n",
"");
831 else if (mUnchangedParameters[2].containsInvalid())
833 os <<
write(1, rt,
"The kinetic function can be invalid for the actual parameter values even if substrate concentrations are positive.\n",
"");
841 imax = mSubstrateZero.size();
843 for (i = 0; i < imax; ++i)
845 assert(mSubstrateZero[i].second.size() >= 2);
848 if (mSubstrateZero[i].second[1].isZero())
850 os <<
write(0, rt,
"The kinetic function is always zero for positive parameter values if substrate \""
851 + mSubstrateZero[i].first.second
852 +
"\" is set to zero.\n" ,
"");
854 else if (mSubstrateZero[i].second[1].containsZero())
856 os <<
write(1, rt,
"Copasi could not show that the kinetic function is always zero for positive parameter values if substrate \""
857 + mSubstrateZero[i].first.second
858 +
"\" is set to zero.\n" ,
"");
863 os <<
write(2, rt,
"The kinetic function is never zero for positive parameter values if substrate \""
864 + mSubstrateZero[i].first.second
865 +
"\" is set to zero.\n" ,
"");
869 if (mSubstrateZero[i].second[1].isInvalid())
871 os <<
write(2, rt,
"The kinetic function is always invalid for positive parameter values if substrate \""
872 + mSubstrateZero[i].first.second
873 +
"\" is set to zero.\n" ,
"");
876 else if (mSubstrateZero[i].second[1].containsInvalid())
878 os <<
write(1, rt,
"The kinetic function can be invalid for positive parameter values if substrate \""
879 + mSubstrateZero[i].first.second
880 +
"\" is set to zero.\n" ,
"");
885 if ((mSubstrateZero[i].second.size() > 2) && (!(mSubstrateZero[i].second[1] == mSubstrateZero[i].second[2])))
887 if (mSubstrateZero[i].second[2].isZero())
889 os <<
write(0, rt,
"The kinetic function is always zero for the actual parameter values if substrate \""
890 + mSubstrateZero[i].first.second
891 +
"\" is set to zero.\n" ,
"");
893 else if (mSubstrateZero[i].second[2].containsZero())
895 os <<
write(1, rt,
"Copasi could not show that the kinetic function is always zero for the actual parameter values if substrate \""
896 + mSubstrateZero[i].first.second
897 +
"\" is set to zero.\n" ,
"");
902 os <<
write(2, rt,
"The kinetic function is never zero for the actual parameter values if substrate \""
903 + mSubstrateZero[i].first.second
904 +
"\" is set to zero.\n" ,
"");
908 if (mSubstrateZero[i].second[2].isInvalid())
910 os <<
write(2, rt,
"The kinetic function is always invalid for the actual parameter values if substrate \""
911 + mSubstrateZero[i].first.second
912 +
"\" is set to zero.\n" ,
"");
915 else if (mSubstrateZero[i].second[2].containsInvalid())
917 os <<
write(1, rt,
"The kinetic function can be invalid for the actual parameter values if substrate \""
918 + mSubstrateZero[i].first.second
919 +
"\" is set to zero.\n" ,
"");
941 os <<
"<font color=\"#505080\"><TABLE>\n";
944 os <<
" <TD></TD>\n";
946 size_t j, jmax = mUnchangedParameters.size();
948 for (j = 0; j < jmax; ++j)
949 os <<
" <TD>" << mUnchangedParameters[j] <<
"</TD>\n";
953 imax = mSubstrateZero.size();
955 for (i = 0; i < imax; ++i)
959 os <<
" <TD>Substrate \"" << mSubstrateZero[i].first.second <<
"\" set to 0:</TD>\n";
962 size_t j, jmax = mSubstrateZero[i].second.size();
964 for (j = 0; j < jmax; ++j)
965 os <<
" <TD>" << mSubstrateZero[i].second[j] <<
"</TD>\n";
970 imax = mProductZero.size();
972 for (i = 0; i < imax; ++i)
976 os <<
" <TD>Product \"" << mProductZero[i].first.second <<
"\" set to 0: </TD>\n";
979 size_t j, jmax = mProductZero[i].second.size();
981 for (j = 0; j < jmax; ++j)
982 os <<
" <TD>" << mProductZero[i].second[j] <<
"</TD>\n";
987 os <<
"</TABLE></font>\n";
996 size_t i, imax = fp.
size();
997 callParameters.resize(imax);
999 for (i = 0; i < imax; ++i)
1026 callParameters.resize(imax);
1028 for (i = 0; i < imax; ++i)
1078 while (itNode.
next() != itNode.
end())
1080 if (*itNode == NULL)
1131 if (callParameters.size() < pENV->
getIndex() + 1)
1137 Result = callParameters[pENV->
getIndex()];
1148 Result = itNode.
context()[0].invert();
1226 if (dynamic_cast<const CMassAction*>(f))
return;
1235 std::vector<CValue> callParameters;
1262 std::vector<CValue> tmpValueVector;
1266 for (i = 0; i < imax; ++i)
1270 tmpValueVector.clear();
1277 tmpValueVector.push_back(tmpValue);
1284 tmpValueVector.push_back(tmpValue);
1295 tmpValueVector.push_back(tmpValue);
1306 tmpValueVector.clear();
1313 tmpValueVector.push_back(tmpValue);
1320 tmpValueVector.push_back(tmpValue);
1329 tmpValueVector.push_back(tmpValue);
1342 std::pair<CFunction *, CFunction *> tmp;
1345 if ((tmp.first == NULL) || (tmp.second == NULL))
1370 case 0: color =
"\"#008000\"";
break;
1372 case 1: color =
"\"#909000\"";
break;
1374 case 2: color =
"\"#800000\"";
break;
1376 case 3: color =
"\"#c04040\"";
break;
1378 default: color =
"\"#0000a0\"";
break;
1383 if (rt) ret +=
"<p><font color=" + color +
">";
1385 ret += (text +
"\n");
1389 if (rt) ret +=
"<br>";
1391 ret += longText +
"\n";
1394 if (rt) ret +=
"</font></p>";
bool containsZero() const
void orValue(const double &value)
const CEvaluationTree * getCalledTree() const
const std::string & getObjectName() const
static CValue evaluateNode(const CEvaluationNode *node, const std::vector< CValue > &callParameters, Mode mode)
CValue operator/(const CValue &rhs) const
const C_FLOAT64 & getValue() const
CCopasiObject * get(const std::string &key)
CValue operator-(const CValue &rhs) const
const Type & getType() const
size_t getNumberOfParametersByUsage(CFunctionParameter::Role usage) const
static void constructCallParametersActualValues(std::vector< CValue > &callParameters, const CReaction *reaction)
static CValue generalize(const double &d)
FunctionInformation mBPart
const Result & getResult() const
const CNodeIteratorMode::State & next()
const std::vector< CEvaluationNode * > getListOfChildNodes() const
static void constructCallParameters(const CFunctionParameters &fp, std::vector< CValue > &callParameters, bool posi)
const C_FLOAT64 & getInitialValue() const
bool containsNegative() const
static Type type(const Type &type)
const Status & getStatus() const
std::ostream & operator<<(std::ostream &os, const CFunctionAnalyzer::CValue &v)
CValue operator^(const CValue &rhs) const
const CFunctionParameters & getFunctionParameters() const
const TriLogic & isReversible() const
std::pair< CFunction *, CFunction * > splitFunction(const CEvaluationNode *node, const std::string &name1, const std::string &name2) const
const Value & getValue() const
static std::string write(int level, bool rt, const std::string &text, const std::string &longText)
bool containsPositive() const
bool mReversibleNonSplitable
FunctionInformation mOriginalFunction
bool mIrreversibleKineticsWithProducts
Context * parentContextPtr()
CValue operator*(const CValue &rhs) const
bool operator==(const CValue &rhs) const
void checkKineticFunction(const CFunction *f, const CReaction *reaction=NULL)
static Type subType(const Type &type)
static CKeyFactory * getKeyFactory()
const CFunction * mpFunction
The class for handling a chemical kinetic function.
bool containsInvalid() const
const CModelEntity::Status & getStatus() const
CNodeIteratorMode::State end() const
const std::vector< std::vector< std::string > > & getParameterMappings() const
bool writeResult(std::ostream &os, bool rt, bool verbose) const
CEvaluationNode * getRoot()
CFunctionParameters & getVariables()
FunctionInformation mFPart
CValue operator+(const CValue &rhs) const