예제 #1
0
 def AddVariable(self, varname, desc='', eqn=''):
     """
     Add a variable to the sector.
     The variable name (varname) is the local name; it will be decorated to create a
     full name. Equations within a sector can use the local name; other sectors need to
     use GetVariableName to get the full name.
     :param varname: str
     :param desc: str
     :param eqn: str
     :return: None
     """
     if '__' in varname:
         raise ValueError('Cannot use "__" inside local variable names: ' +
                          varname)
     if desc is None:
         desc = ''
     if type(eqn) == Equation:
         equation = eqn
     else:
         equation = Equation(varname, desc, [
             Term(eqn, is_blob=True),
         ])
     if varname in self.GetVariables():
         Logger('[ID={0}] Variable Overwritten: {1}',
                priority=3,
                data_to_format=(self.ID, varname))
     self.EquationBlock.AddEquation(equation)
     # self.Equations[varname] = eqn
     Logger('[ID={0}] Variable Added: {1} = {2} # {3}',
            priority=2,
            data_to_format=(self.ID, varname, eqn, desc))
예제 #2
0
 def test_list(self):
     block = EquationBlock()
     eq = Equation('x', rhs=[Term('y')])
     block.AddEquation(eq)
     block.AddEquation(Equation('a'))
     # Always sorted
     self.assertEqual(['a', 'x'], block.GetEquationList())
예제 #3
0
 def test_str(self):
     t = Term('x')
     t.Constant = 0.
     self.assertEqual('', str(t))
     t.Constant = 1.
     self.assertEqual('+x', str(t))
     t.Constant = -1.
     self.assertEqual('-x', str(t))
     t.Constant = 2.
     self.assertEqual('+{0}*x'.format(str(2.)), str(t))
     t.Constant = -2.
     self.assertEqual('-{0}*x'.format(str(2.)), str(t))
예제 #4
0
    def AddCashFlow(self, term, eqn=None, desc=None, is_income=True):
        """
        Add a cash flow to the sector. Will add to the financial asset equation (F), and
        the income equation (INC) if is_income is True.

        Except: There is a list of exclusions to which cash flows are not considered income.
        That setting will override the is_income parameter. This allows us to carve out exceptions
        to the standard behaviour, which generally is to assume that cash flows are associated with
        income.

        :param term: str
        :param eqn: str
        :param desc: str
        :param is_income: bool
        :return: None
        """
        term = term.strip()
        if len(term) == 0:
            return
        term_obj = Term(term)
        if not term_obj.IsSimple:  # pragma: no cover  - Not implemented; cannot hit the line below.
            raise LogicError(
                'Must supply a single variable as the term to AddCashFlow')
        # term = term.replace(' ', '')
        # if not (term[0] in ('+', '-')):
        #     term = '+' + term
        # if len(term) < 2:
        #     raise ValueError('Invalid cash flow term')
        self.EquationBlock['F'].AddTerm(term)
        if is_income:
            # Need to see whether it is excluded
            mod = self.GetModel()
            for obj, excluded in mod.IncomeExclusions:
                if obj.ID == self.ID:
                    if term_obj.Term == excluded:
                        is_income = False
                        break
        if is_income:
            self.EquationBlock['INC'].AddTerm(term)
        if eqn is None:
            return
        # Remove the +/- from the term
        term = term_obj.Term
        if term in self.GetVariables():
            rhs = self.EquationBlock[term].RHS()
            if rhs == '' or rhs == '0.0':
                self.SetEquationRightHandSide(term, eqn)
        else:
            self.AddVariable(term, desc, eqn)
예제 #5
0
    def AddTermToEquation(self, varname, term):
        """
        Add a new term to an existing equation.

        The term variable may be either a string or (non-Blob) Term object.

        :param varname: str
        :param term: Term
        :return: None
        """
        term = Term(term)
        Logger('Adding term {0} to Equation {1} in Sector {2} [ID={3}]',
               priority=2,
               data_to_format=(term, varname, self.Code, self.ID))
        try:
            self.EquationBlock[varname].AddTerm(term)
        except KeyError:
            raise KeyError('Variable {0} not in Sector {1}'.format(
                varname, self.Code))
예제 #6
0
 def SetEquationRightHandSide(self, varname, rhs):
     """
     Set the right hand side of the equation for an existing variable.
     :param varname: str
     :param rhs: str
     :return: None
     """
     try:
         self.EquationBlock[varname].TermList = [
             Term(rhs, is_blob=True),
         ]
     except KeyError:
         raise KeyError('Variable {0} does not exist'.format(varname))
     # Could try: Equation.ParseString(rhs), but is too slow in unit tests...
     # if varname not in self.Equations:
     #     raise KeyError('Variable {0} does not exist'.format(varname))
     Logger('[ID={0}] Equation set: {1} = {2} ',
            priority=2,
            data_to_format=(self.ID, varname, rhs))
예제 #7
0
 def test_copy(self):
     t = Term('x')
     t2 = Term(t)
     self.assertEqual('x', t2.Term)
예제 #8
0
 def test_simple_3(self):
     t = Term('x')
     self.assertTrue(t.IsSimple)
     self.assertEqual('x', t.Term)
예제 #9
0
 def test_simple_2(self):
     # Original comment: constants not supported yet as "Simple"
     # 2019-05-04: Not sure why no support for constants?
     t = Term('2')
     self.assertTrue(t.IsSimple)
     self.assertEqual('2', t.Term)
예제 #10
0
 def test_interior_2(self):
     with self.assertRaises(LogicError):
         t = Term('-(y+x)')
예제 #11
0
 def test_sign_4(self):
     t = Term('-(+x)')
     self.assertEqual(-1.0, t.Constant)
예제 #12
0
 def test_sign_3(self):
     t = Term('-(-x)')
     self.assertEqual(1.0, t.Constant)
예제 #13
0
 def test_sign_2(self):
     t = Term(' -x')
     self.assertEqual(-1.0, t.Constant)
예제 #14
0
 def test_multiply(self):
     t = Term('a*b')
     self.assertEqual('+a*b', str(t))
예제 #15
0
 def test_access(self):
     block = EquationBlock()
     eq = Equation('x', rhs=[Term('y')])
     block.AddEquation(eq)
     out = block['x']
     self.assertEqual('y', out.RHS())
예제 #16
0
 def test_AddTermFail(self):
     eq = Equation('x', 'desc', 'y')
     t2 = Term('y^2', is_blob=True)
     with self.assertRaises(LogicError):
         eq.AddTerm(t2)
예제 #17
0
 def test_str_2(self):
     t1 = Term('y')
     t2 = Term('-z')
     eq = Equation('x', 'define x', (t2, t1))
     self.assertEqual('-z+y', eq.GetRightHandSide())
예제 #18
0
 def bad_ctor(self):
     t1 = Term('x')
     t2 = Term('y^2', is_blob=True)
     with self.assertRaises(LogicError):
         Equation('lhs', '', (t1, t2))
예제 #19
0
 def test_str_1(self):
     t1 = Term('y')
     t2 = Term('-z')
     eq = Equation('x', 'define x', (t1, t2))
     self.assertEqual('y-z', eq.GetRightHandSide())
예제 #20
0
 def test_simple_2(self):
     # NOTE: constants not supported yet as "Simple"
     with self.assertRaises(NotImplementedError):
         t = Term('2')
예제 #21
0
 def test_blob(self):
     t = Term('(bazoonga*kablooie)^2', is_blob=True)
     self.assertEqual('(bazoonga*kablooie)^2', str(t))
예제 #22
0
 def test_fail_bracket(self):
     with self.assertRaises(SyntaxError):
         Term('+(x ')
예제 #23
0
 def test_str_not_simple(self):
     with self.assertRaises(NotImplementedError):
         t = Term('f(x)')
예제 #24
0
 def test_sign_1(self):
     t = Term('x')
     self.assertEqual(1.0, t.Constant)