Skip to content

Content of file t_nomials.py

"""Tests for Monomial, Posynomial, and Signomial classes"""
import sys
import math
import unittest
from gpkit import Variable, Monomial, Posynomial, Signomial, SignomialsEnabled
from gpkit import VectorVariable, NomialArray
from gpkit.nomials import NomialMap
from gpkit.exceptions import InvalidPosynomial
import gpkit


class TestMonomial(unittest.TestCase):
    """TestCase for the Monomial class"""

    def test_init(self):
        "Test multiple ways to create a Monomial"
        m = Monomial({"x": 2, "y": -1}, 5)
        m2 = Monomial({"x": 2, "y": -1}, 5)
        x, = m.varkeys["x"]
        y, = m.varkeys["y"]
        self.assertEqual(m.exp, {x: 2, y: -1})
        self.assertEqual(m.c, 5)
        self.assertEqual(m, m2)

        # default c and a
        v = Variable("x")
        x, = v.varkeys["x"]
        self.assertEqual(v.exp, {x: 1})
        self.assertEqual(v.c, 1)

        # single (string) var with non-default c
        v = 0.1*Variable("tau")
        tau, = v.varkeys["tau"]  # pylint: disable=no-member
        self.assertEqual(v.exp, {tau: 1})  # pylint: disable=no-member
        self.assertEqual(v.c, .1)  # pylint: disable=no-member

        # variable names not compatible with python namespaces
        crazy_varstr = "what the !!!/$**?"
        m = Monomial({"x": 1, crazy_varstr: .5}, 25)
        crazy_varkey, = m.varkeys[crazy_varstr]
        self.assertTrue(crazy_varkey in m.exp)

        # non-positive c raises
        self.assertRaises(InvalidPosynomial, Monomial, -2)
        self.assertRaises(InvalidPosynomial, Monomial, -1)
        self.assertRaises(InvalidPosynomial, Monomial, 0)
        self.assertRaises(InvalidPosynomial, Monomial, 0.0)

        # can create nameless Variables
        x1 = Variable()
        x2 = Variable()
        V = Variable("V")
        vel = Variable("V")
        self.assertNotEqual(x1, x2)
        self.assertEqual(V, vel)

        # test label kwarg
        x = Variable("x", label="dummy variable")
        self.assertEqual(list(x.exp)[0].descr["label"], "dummy variable")
        _ = hash(m)
        _ = hash(x)
        _ = hash(Monomial(x))

    def test_repr(self):
        "Simple tests for __repr__, which prints more than str"
        x = Variable("x")
        y = Variable("y")
        m = 5*x**2/y
        r = m.__repr__()
        self.assertEqual(type(r), str)
        if sys.platform[:3] != "win":
            self.assertEqual(repr(m), "gpkit.Monomial(5·x²/y)")

    def test_latex(self):
        "Test latex string creation"
        x = Variable("x")
        m = Monomial({"x": 2, "y": -1}, 5).latex()
        self.assertEqual(type(m), str)
        self.assertEqual((5*x).latex(), "5x")

    def test_str_with_units(self):
        "Make sure __str__() works when units are involved"
        S = Variable("S", units="m^2")
        rho = Variable("rho", units="kg/m^3")
        x = rho*S
        xstr = x.str_without()
        self.assertEqual(type(xstr), str)
        self.assertTrue("S" in xstr and "rho" in xstr)

    def test_add(self):
        x = Variable("x")
        y = Variable("y", units="ft")
        with self.assertRaises(gpkit.DimensionalityError):
            _ = x + y

    def test_eq_ne(self):
        "Test equality and inequality comparators"
        # simple one
        x = Variable("x")
        y = Variable("y")
        self.assertNotEqual(x, y)
        self.assertFalse(x == y)

        xx = Variable("x")
        self.assertEqual(x, xx)
        self.assertFalse(x != xx)

        self.assertEqual(x, x)
        self.assertFalse(x != x)  # pylint: disable=comparison-with-itself

        m = Monomial({}, 1)
        self.assertEqual(m, 1)
        self.assertEqual(m, Monomial({}))

        # several vars
        m1 = Monomial({"a": 3, "b": 2, "c": 1}, 5)
        m2 = Monomial({"a": 3, "b": 2, "c": 1}, 5)
        m3 = Monomial({"a": 3, "b": 2, "c": 1}, 6)
        m4 = Monomial({"a": 3, "b": 2}, 5)
        self.assertEqual(m1, m2)
        self.assertNotEqual(m1, m3)
        self.assertNotEqual(m1, m4)

        # numeric
        self.assertEqual(Monomial(3), 3)
        self.assertEqual(Monomial(3), Monomial(3))
        self.assertNotEqual(Monomial(3), 2)
        self.assertNotEqual(Variable("x"), 3)
        self.assertNotEqual(Monomial(3), Variable("x"))

    def test_div(self):
        "Test Monomial division"
        x = Variable("x")
        y = Variable("y")
        z = Variable("z")
        t = Variable("t")
        a = 36*x/y
        # sanity check
        self.assertEqual(a, Monomial({"x": 1, "y": -1}, 36))
        # divide by scalar
        self.assertEqual(a/9, 4*x/y)
        # divide by Monomial
        b = a / z
        self.assertEqual(b, 36*x/y/z)
        # make sure x unchanged
        self.assertEqual(a, Monomial({"x": 1, "y": -1}, 36))
        # mixed new and old vars
        c = a / (0.5*t**2/x)
        self.assertEqual(c, Monomial({"x": 2, "y": -1, "t": -2}, 72))

    def test_mul(self):
        "Test monomial multiplication"
        x = Monomial({"x": 1, "y": -1}, 4)
        # test integer division
        self.assertEqual(x/5, Monomial({"x": 1, "y": -1}, 0.8))
        # divide by scalar
        self.assertEqual(x*9, Monomial({"x": 1, "y": -1}, 36))
        # divide by Monomial
        y = x * Variable("z")
        self.assertEqual(y, Monomial({"x": 1, "y": -1, "z": 1}, 4))
        # make sure x unchanged
        self.assertEqual(x, Monomial({"x": 1, "y": -1}, 4))
        # mixed new and old vars
        z = x * Monomial({"x": -1, "t": 2}, .5)
        self.assertEqual(z, Monomial({"x": 0, "y": -1, "t": 2}, 2))

        x0 = Variable("x0")
        self.assertEqual(0.0, 0.0*x0)
        x1 = Variable("x1")
        n_hat = [1, 0]
        p = n_hat[0]*x0 + n_hat[1]*x1
        self.assertEqual(p, x0)

        self.assertNotEqual((x+1), (x+1)*gpkit.units("m"))

    def test_pow(self):
        "Test Monomial exponentiation"
        x = Monomial({"x": 1, "y": -1}, 4)
        self.assertEqual(x, Monomial({"x": 1, "y": -1}, 4))
        # identity
        self.assertEqual(x/x, Monomial({}, 1))
        # square
        self.assertEqual(x*x, x**2)
        # divide
        y = Monomial({"x": 2, "y": 3}, 5)
        self.assertEqual(x/y, x*y**-1)
        # make sure x unchanged
        self.assertEqual(x, Monomial({"x": 1, "y": -1}, 4))

    def test_numerical_precision(self):
        "not sure what to test here, placeholder for now"
        c1, c2 = 1/700, 123e8
        m1 = Monomial({"x": 2, "y": 1}, c1)
        m2 = Monomial({"y": -1, "z": 3/2}, c2)
        self.assertEqual(math.log((m1**4 * m2**3).c),  # pylint: disable=no-member
                         4*math.log(c1) + 3*math.log(c2))
Module 'math' has no 'log' member, but source is unavailable. Consider adding this module to extension-pkg-whitelist if you want to perform analysis based on run-time introspection of living objects.
no description found
def test_units(self): "make sure multiplication with units works (issue 492)" # have had issues where Quantity.__mul__ causes wrong return type m = 1.2 * gpkit.units.ft * Variable("x", "m")**2 self.assertTrue(isinstance(m, Monomial)) if m.units: self.assertEqual(m.units, 1*gpkit.ureg.ft*gpkit.ureg.m**2) # also multiply at the end, though this has not been a problem m = 0.5 * Variable("x", "m")**2 * gpkit.units.kg self.assertTrue(isinstance(m, Monomial)) if m.units: self.assertEqual(m.units, 1*gpkit.ureg.kg*gpkit.ureg.m**2) # and with vectors... v = 0.5 * VectorVariable(3, "x", "m")**2 * gpkit.units.kg self.assertTrue(isinstance(v, NomialArray)) self.assertEqual(v[0].units, 1*gpkit.ureg.kg*gpkit.ureg.m**2) v = 0.5 * gpkit.units.kg * VectorVariable(3, "x", "m")**2 self.assertTrue(isinstance(v, NomialArray)) self.assertEqual(v[0].units, 1*gpkit.ureg.kg*gpkit.ureg.m**2) class TestSignomial(unittest.TestCase): """TestCase for the Signomial class""" def test_init(self): "Test Signomial construction" x = Variable("x") y = Variable("y") with SignomialsEnabled(): if sys.platform[:3] != "win": self.assertEqual(str(1 - x - y**2 - 1), "1 - x - y² - 1") self.assertEqual((1 - x/y**2).latex(), "-\\frac{x}{y^{2}} + 1") _ = hash(1 - x/y**2) self.assertRaises(TypeError, lambda: x-y) def test_chop(self): "Test Signomial deconstruction" x = Variable("x") y = Variable("y") with SignomialsEnabled(): c = x + 5*y**2 - 0.2*x*y**0.78 monomials = c.chop() with self.assertRaises(InvalidPosynomial): c.chop() with SignomialsEnabled(): self.assertIn(-0.2*x*y**0.78, monomials) def test_mult(self): "Test Signomial multiplication" x = Variable("x") with SignomialsEnabled(): self.assertEqual((x+1)*(x-1), x**2 - 1) def test_eq_ne(self): "Test Signomial equality and inequality operators" x = Variable("x") xu = Variable("x", units="ft") with SignomialsEnabled(): self.assertEqual(x - x**2, -x**2 + x) self.assertNotEqual(-x, -xu) # numeric self.assertEqual(Signomial(0), 0) self.assertNotEqual(Signomial(0), 1) self.assertEqual(Signomial(-3), -3) self.assertNotEqual(Signomial(-3), 3) class TestPosynomial(unittest.TestCase): """TestCase for the Posynomial class""" def test_init(self): # pylint:disable=too-many-locals "Test Posynomial construction" x = Variable("x") y = Variable("y") ms = [Monomial({"x": 1, "y": 2}, 3.14), 0.5*Variable("y"), Monomial({"x": 3, "y": 1}, 6), Monomial(2)] exps, cs = [], [] for m in ms: cs += m.cs.tolist() exps += m.exps hmap = NomialMap(zip(exps, cs)) hmap.units_of_product(None) p = Posynomial(hmap) # check arithmetic p2 = 3.14*x*y**2 + y/2 + x**3*6*y + 2 self.assertEqual(p, p2) self.assertEqual(p, sum(ms)) _ = hash(p2) exp1 = Monomial({"m": 1, "v": 2}).exp exp2 = Monomial({"m": 1, "g": 1, "h": 1}).exp hmap = NomialMap({exp1 : 0.5, exp2: 1}) hmap.units_of_product(None) p = Posynomial(hmap) m, = p.varkeys["m"] g, = p.varkeys["g"] h, = p.varkeys["h"] v, = p.varkeys["v"] self.assertTrue(all(isinstance(x, float) for x in p.cs)) self.assertEqual(len(p.exps), 2) self.assertEqual(set(p.vks), set([m, g, h, v])) def test_eq(self): """Test Posynomial __eq__""" x = Variable("x") y = Variable("y") self.assertTrue((1 + x) == (1 + x)) self.assertFalse((1 + x) == 2*(1 + x)) self.assertFalse((1 + x) == 0.5*(1 + x)) self.assertFalse((1 + x) == (1 + y)) x = Variable("x", value=3) y = Variable("y", value=2) self.assertEqual((1 + x**2).value, (4 + y + y**2).value) def test_eq_units(self): p1 = Variable("x") + Variable("y") p2 = Variable("x") + Variable("y") p1u = Variable("x", units="m") + Variable("y", units="m") p2u = Variable("x", units="m") + Variable("y", units="m") self.assertEqual(p1, p2) self.assertEqual(p1u, p2u) self.assertFalse(p1 == p1u) self.assertNotEqual(p1, p1u) def test_simplification(self): "Make sure like monomial terms get automatically combined" x = Variable("x") y = Variable("y") p1 = x + y + y + (x+y) + (y+x**2) + 3*x p2 = 4*y + x**2 + 5*x # ps1 = [list(exp.keys())for exp in p1.exps] # ps2 = [list(exp.keys())for exp in p2.exps] # print("%s, %s" % (ps1, ps2)) # python 3 dict reordering self.assertEqual(p1, p2) def test_posyposy_mult(self): "Test multiplication of Posynomial with Posynomial" x = Variable("x") y = Variable("y") p1 = x**2 + 2*y*x + y**2 p2 = (x+y)**2 # ps1 = [list(exp.keys())for exp in p1.exps] # ps2 = [list(exp.keys())for exp in p2.exps] # print("%s, %s" % (ps1, ps2)) # python 3 dict reordering self.assertEqual(p1, p2) p1 = (x+y)*(2*x+y**2) p2 = 2*x**2 + 2*y*x + y**2*x + y**3 # ps1 = [list(exp.keys())for exp in p1.exps] # ps2 = [list(exp.keys())for exp in p2.exps] # print("%s, %s" % (ps1, ps2)) # python 3 dict reordering self.assertEqual(p1, p2) def test_constraint_gen(self): "Test creation of Constraints via operator overloading" x = Variable("x") y = Variable("y") p = x**2 + 2*y*x + y**2 self.assertEqual((p <= 1).as_hmapslt1({}), [p.hmap]) self.assertEqual((p <= x).as_hmapslt1({}), [(p/x).hmap]) def test_integer_division(self): "Make sure division by integer doesn't use Python integer division" x = Variable("x") y = Variable("y") p = 4*x + y self.assertEqual(p/3, p/3) equiv1 = all((p/3).cs == [1/3, 4/3]) equiv2 = all((p/3).cs == [4/3, 1/3]) self.assertTrue(equiv1 or equiv2) def test_diff(self): "Test differentiation (!!)" x = Variable("x") y = Variable("y") self.assertEqual(x.diff(x), 1) self.assertEqual(x.diff(y), 0) self.assertEqual((y**2).diff(y), 2*y) self.assertEqual((x + y**2).diff(y), 2*y) self.assertEqual((x + y**2).diff(x.key), 1) self.assertEqual((x + x*y**2).diff(y), 2*x*y) # pylint: disable=no-member self.assertEqual((2*y).diff(y), 2) # pylint: disable=no-member # test with units x = Variable("x", units="ft") d = (3*x**2).diff(x) self.assertEqual(d, 6*x) # test negative exponent d = (1 + 1/y).diff(y) with SignomialsEnabled(): expected = -y**-2 self.assertEqual(d, expected) def test_mono_lower_bound(self): "Test monomial approximation" x = Variable("x") y = Variable("y") p = y**2 + 1 self.assertEqual(y.mono_lower_bound({y: 1}), y) # pylint is confused because it thinks p is a Signomial # pylint: disable=no-member self.assertEqual(p.mono_lower_bound({y: 1}), 2*y) self.assertEqual(p.mono_lower_bound({y: 0}), 1) self.assertEqual((x*y**2 + 1).mono_lower_bound({y: 1, x: 1}), 2*y*x**0.5) # test with units d = Variable("d", units="ft") h = Variable("h", units="ft") p = (d*h**2 + h*d**2) m = p.mono_lower_bound({d: 1, h: 1}) self.assertEqual(m, 2*(d*h)**1.5) # test substitution TESTS = [TestPosynomial, TestMonomial, TestSignomial] if __name__ == "__main__": # pragma: no cover # pylint: disable=wrong-import-position from gpkit.tests.helpers import run_tests run_tests(TESTS)