X-Git-Url: https://scm.cri.ensmp.fr/git/linpy.git/blobdiff_plain/2b13a146860ac116ce0388d8f7551044c09c55f7..d585b06ccf67b2837519f4b48c6800dcdb924d9d:/linpy/linexprs.py?ds=sidebyside diff --git a/linpy/linexprs.py b/linpy/linexprs.py index ee6e39e..ccfbbfa 100644 --- a/linpy/linexprs.py +++ b/linpy/linexprs.py @@ -20,14 +20,16 @@ import functools import numbers import re -from collections import OrderedDict, defaultdict, Mapping +from collections import defaultdict, Mapping, OrderedDict from fractions import Fraction, gcd __all__ = [ + 'Dummy', 'LinExpr', - 'Symbol', 'Dummy', 'symbols', 'Rational', + 'Symbol', + 'symbols', ] @@ -59,8 +61,8 @@ class LinExpr: def __new__(cls, coefficients=None, constant=0): """ Return a linear expression from a dictionary or a sequence, that maps - symbols to their coefficients, and a constant term. The coefficients and - the constant term must be rational numbers. + symbols to their coefficients, and a constant term. The coefficients + and the constant term must be rational numbers. For example, the linear expression x + 2*y + 1 can be constructed using one of the following instructions: @@ -79,9 +81,9 @@ class LinExpr: >>> LinExpr('x + 2y + 1') A linear expression with a single symbol of coefficient 1 and no - constant term is automatically subclassed as a Symbol instance. A linear - expression with no symbol, only a constant term, is automatically - subclassed as a Rational instance. + constant term is automatically subclassed as a Symbol instance. A + linear expression with no symbol, only a constant term, is + automatically subclassed as a Rational instance. """ if isinstance(coefficients, str): if constant != 0: @@ -105,8 +107,9 @@ class LinExpr: symbol, coefficient = coefficients[0] if coefficient == 1: return symbol - coefficients = [(symbol, Fraction(coefficient)) - for symbol, coefficient in coefficients if coefficient != 0] + coefficients = [(symbol_, Fraction(coefficient_)) + for symbol_, coefficient_ in coefficients + if coefficient_ != 0] coefficients.sort(key=lambda item: item[0].sortkey()) self = object().__new__(cls) self._coefficients = OrderedDict(coefficients) @@ -223,7 +226,8 @@ class LinExpr: Return the product of the linear expression by a rational. """ if isinstance(other, numbers.Rational): - coefficients = ((symbol, coefficient * other) + coefficients = ( + (symbol, coefficient * other) for symbol, coefficient in self._coefficients.items()) constant = self._constant * other return LinExpr(coefficients, constant) @@ -236,7 +240,8 @@ class LinExpr: Return the quotient of the linear expression by a rational. """ if isinstance(other, numbers.Rational): - coefficients = ((symbol, coefficient / other) + coefficients = ( + (symbol, coefficient / other) for symbol, coefficient in self._coefficients.items()) constant = self._constant / other return LinExpr(coefficients, constant) @@ -280,7 +285,7 @@ class LinExpr: make all values integer. """ lcd = functools.reduce(lambda a, b: a*b // gcd(a, b), - [value.denominator for value in self.values()]) + [value.denominator for value in self.values()]) return self * lcd def subs(self, symbol, expression=None): @@ -306,7 +311,7 @@ class LinExpr: for symbol in substitutions: if not isinstance(symbol, Symbol): raise TypeError('symbols must be Symbol instances') - result = self._constant + result = Rational(self._constant) for symbol, coefficient in self._coefficients.items(): expression = substitutions.get(symbol, symbol) result += coefficient * expression @@ -348,10 +353,10 @@ class LinExpr: # Add implicit multiplication operators, e.g. '5x' -> '5*x'. string = LinExpr._RE_NUM_VAR.sub(r'\1*\2', string) tree = ast.parse(string, 'eval') - expr = cls._fromast(tree) - if not isinstance(expr, cls): + expression = cls._fromast(tree) + if not isinstance(expression, cls): raise SyntaxError('invalid syntax') - return expr + return expression def __repr__(self): string = '' @@ -385,7 +390,7 @@ class LinExpr: return '({})'.format(string) @classmethod - def fromsympy(cls, expr): + def fromsympy(cls, expression): """ Create a linear expression from a SymPy expression. Raise TypeError is the sympy expression is not linear. @@ -393,7 +398,7 @@ class LinExpr: import sympy coefficients = [] constant = 0 - for symbol, coefficient in expr.as_coefficients_dict().items(): + for symbol, coefficient in expression.as_coefficients_dict().items(): coefficient = Fraction(coefficient.p, coefficient.q) if symbol == sympy.S.One: constant = coefficient @@ -405,23 +410,25 @@ class LinExpr: symbol = Symbol(symbol.name) coefficients.append((symbol, coefficient)) else: - raise TypeError('non-linear expression: {!r}'.format(expr)) - expr = LinExpr(coefficients, constant) - if not isinstance(expr, cls): - raise TypeError('cannot convert to a {} instance'.format(cls.__name__)) - return expr + raise TypeError('non-linear expression: {!r}'.format( + expression)) + expression = LinExpr(coefficients, constant) + if not isinstance(expression, cls): + raise TypeError('cannot convert to a {} instance'.format( + cls.__name__)) + return expression def tosympy(self): """ Convert the linear expression to a SymPy expression. """ import sympy - expr = 0 + expression = 0 for symbol, coefficient in self.coefficients(): term = coefficient * sympy.Symbol(symbol.name) - expr += term - expr += self.constant - return expr + expression += term + expression += self.constant + return expression class Symbol(LinExpr):