def test_substitute(self): # Partial evaluation. x = Variable('x') y = Variable('y') z = Variable('z') power_dict = {x: 5, y: 2, z: 3} m = ChebyshevVector(power_dict) x_eval = {x: -2.1, y: 1.5} m_eval = ChebyshevVector({z: 3}) c_eval = 16 * (-2.1)**5 - 20 * (-2.1)**3 + 5 * (-2.1) c_eval *= 2 * 1.5**2 - 1 p = Polynomial({m_eval: c_eval}) self.assertAlmostEqual(m.substitute(x_eval), p) # Complete evaluation. x_eval[z] = 5 m_eval = ChebyshevVector({}) c_eval *= 4 * 5**3 - 3 * 5 p = Polynomial({m_eval: c_eval}) self.assertAlmostEqual(m.substitute(x_eval), p) # Cancellation. x_eval = {z: 0} p = Polynomial({}) self.assertAlmostEqual(m.substitute(x_eval), p)
def test_derivative_jacobian(self): for Vector in Vectors: # Derivative. x = Variable('x') y = Variable('y') z = Variable('z') m0 = Vector({x: 4, y: 1}) m1 = Vector({x: 5, y: 2}) p = Polynomial({m0: 2.5, m1: -3}) px = m0.derivative(x) * 2.5 + m1.derivative(x) * (-3) py = m0.derivative(y) * 2.5 + m1.derivative(y) * (-3) pz = Polynomial({}) self.assertEqual(p.derivative(x), px) self.assertEqual(p.derivative(y), py) self.assertEqual(p.derivative(z), pz) # Jacobian. for pi, qi in zip(p.jacobian([z, x, y]), np.array([pz, px, py])): self.assertEqual(pi, qi) # Differentiation of zero polynomial must return a polynomial. p = Polynomial({}) px = p.derivative(x) self.assertEqual(px, 0) self.assertTrue(isinstance(px, Polynomial))
def test_substitute(self): for Vector in Vectors: # Partial evaluation. x = Variable('x') y = Variable('y') z = Variable('z') v0 = Vector({x: 1, y: 2}) v1 = Vector({x: 3, z: 5}) p = Polynomial({v0: 3.5, v1: .5}) eval_dict = {x: 2, y: .3} p_eval = v0.substitute(eval_dict) * 3.5 + v1.substitute( eval_dict) * .5 self.assertAlmostEqual(p.substitute(eval_dict), p_eval) # Complete evaluation. eval_dict[z] = -3.12 p_eval = v0.substitute(eval_dict) * 3.5 + v1.substitute( eval_dict) * .5 self.assertAlmostEqual(p.substitute(eval_dict), p_eval) # Cancellation. eval_dict = {x: 0} p_eval = Polynomial({}) self.assertAlmostEqual(p.substitute(eval_dict), p_eval) # Must always return a polynomial. p = Polynomial({}).substitute({x: 3}) self.assertAlmostEqual(p, Polynomial({})) self.assertTrue(isinstance(p, Polynomial))
def test_abs(self): for Vector in Vectors: x = Variable('x') y = Variable('y') v0 = Vector({x: 1, y: 3}) v1 = Vector({x: 2, y: 2}) v2 = Vector({x: 4, y: 1}) p = Polynomial({v0: 1 / 3, v1: -5.2, v2: .22233}) p_abs = Polynomial({v0: 1 / 3, v1: 5.2, v2: .22233}) self.assertEqual(abs(p), p_abs)
def test_new_sos_polynomial(self): # Fit free polynomial in 2 points, and minimize value at a third. for Vector in Vectors: # Normal polynomial. prog = SosProgram() basis = Vector.construct_basis(self.x, 3) poly, gram, cons = prog.add_sos_polynomial(basis) prog.add_linear_cost(poly(self.zero)) prog.add_linear_constraint(poly(self.one) == 1) prog.add_linear_constraint(poly(self.two) == 2) prog.solve() poly_opt = prog.substitute_minimizer(poly) self.assertAlmostEqual(prog.minimum(), 0, places=4) self.assertAlmostEqual(poly_opt(self.zero), 0, places=4) self.assertAlmostEqual(poly_opt(self.one), 1, places=4) self.assertAlmostEqual(poly_opt(self.two), 2, places=4) # Reconstruct polynomial from Gram matrix. gram_opt = prog.substitute_minimizer(gram) self.assertTrue(self._is_psd(gram_opt)) poly_opt_gram = Polynomial.quadratic_form(basis, gram_opt) self.assertAlmostEqual(poly_opt, poly_opt_gram) # Even polynomial. prog = SosProgram() poly, gram, cons = prog.add_even_sos_polynomial(basis) prog.add_linear_cost(poly(self.zero)) prog.add_linear_constraint(poly(self.one) == 1) prog.add_linear_constraint(poly(self.two) == 2) prog.solve() poly_opt = prog.substitute_minimizer(poly) self.assertAlmostEqual(prog.minimum(), 0, places=4) self.assertAlmostEqual(poly_opt(self.zero), 0, places=4) self.assertAlmostEqual(poly_opt(self.one), 1, places=4) self.assertAlmostEqual(poly_opt(self.two), 2, places=4) # Reconstruct polynomial from Gram matrices. gram_opt_e, gram_opt_o = [ prog.substitute_minimizer(gi) for gi in gram ] self.assertTrue(self._is_psd(gram_opt_e)) self.assertTrue(self._is_psd(gram_opt_o)) basis_e = [v for v in basis if v.is_even()] basis_o = [v for v in basis if v.is_odd()] poly_opt_gram = Polynomial.quadratic_form(basis_e, gram_opt_e) poly_opt_gram += Polynomial.quadratic_form(basis_o, gram_opt_o) self.assertAlmostEqual(poly_opt, poly_opt_gram, places=4)
def test_round(self): for Vector in Vectors: x = Variable('x') y = Variable('y') v0 = Vector({x: 1, y: 3}) v1 = Vector({x: 2, y: 2}) v2 = Vector({x: 4, y: 1}) p = Polynomial({v0: 1 / 3, v1: -5.2, v2: .22233}) p0 = Polynomial({v1: -5}) self.assertEqual(round(p), p0) p1 = Polynomial({v0: .3, v1: -5.2, v2: .2}) self.assertEqual(round(p, 1), p1) p4 = Polynomial({v0: .3333, v1: -5.2, v2: .2223}) self.assertEqual(round(p, 4), p4)
def test_iter(self): for Vector in Vectors: x = Variable('x') y = Variable('y') z = Variable('z') v0 = Vector({x: 4, y: 1}) v1 = Vector({x: 5, z: 2}) v2 = Vector({x: 6}) coef_dict = {v0: 5, v1: 2.5, v2: 3} p = Polynomial(coef_dict) for v, c in p: self.assertEqual(c, coef_dict[v]) self.assertEqual(set(p.vectors()), set(coef_dict)) self.assertEqual(set(p.coefficients()), set(coef_dict.values())) self.assertEqual(set(p.variables()), set([x, y, z]))
def test_eq_ne(self): for Vector in Vectors: # Comparisons with different lengths. x = Variable('x') y = Variable('y') v0 = Vector({x: 4, y: 1}) v1 = Vector({x: 5, y: 2}) v2 = Vector({x: 6}) p1 = Polynomial({v0: 5, v1: 2.5, v2: 3}) p2 = Polynomial({v1: 2.5, v0: 5, v2: 3}) p3 = Polynomial({v0: 5, v2: 3}) p4 = Polynomial({v0: 5, v1: 0, v2: 3}) self.assertTrue(p1 == p2) self.assertTrue(p1 != p3) self.assertTrue(p2 != p3) self.assertTrue(p3 == p4) # Comparison to 0. self.assertFalse(p1 == 0) self.assertTrue(p1 != 0) p = Polynomial({}) self.assertTrue(p == 0) self.assertFalse(p != 0) # Comparison with different vector type. m = MonomialVector({x: 4, y: 1}) c = ChebyshevVector({x: 4, y: 1}) pm = Polynomial({m: 1}) pc = Polynomial({c: 1}) self.assertTrue(pm != pc)
def test_getter_setter(self): for Vector in Vectors: # Getter. x = Variable('x') y = Variable('y') v0 = Vector({x: 4, y: 1}) v1 = Vector({x: 5, y: 2}) v2 = Vector({x: 5, y: 12}) p = Polynomial({v0: 2, v1: 3.22}) self.assertEqual(p[v0], 2) self.assertEqual(p[v1], 3.22) self.assertEqual(p[v2], 0) self.assertEqual(len(p), 2) # Setter. p[v0] = 1.11 p[v2] = 6 self.assertEqual(p[v0], 1.11) self.assertEqual(p[v1], 3.22) self.assertEqual(p[v2], 6) self.assertEqual(len(p), 3) # Delete instead of setting to zero. p[v2] = 0 self.assertEqual(p[v2], 0) self.assertEqual(len(p), 2) # Do not set if zero. p[v2] = 0 self.assertEqual(p[v2], 0) # Non-vector in the vectors. with self.assertRaises(TypeError): p[2] = 5 with self.assertRaises(TypeError): p[x] = 5 # Vector of different types. m = MonomialVector({x: 4, y: 1}) c = ChebyshevVector({x: 4, y: 2}) p = Polynomial({m: 2.1}) with self.assertRaises(TypeError): p[c] = 5
def test_in_monomial_basis(self): # Zero-dimensional. m = ChebyshevVector({}) p = Polynomial({MonomialVector({}): 1}) self.assertEqual(m.in_monomial_basis(), p) # One-dimensional. x = Variable('x') m = ChebyshevVector({x: 9}) p = Polynomial({ MonomialVector({x: 1}): 9, MonomialVector({x: 3}): -120, MonomialVector({x: 5}): 432, MonomialVector({x: 7}): -576, MonomialVector({x: 9}): 256, }) self.assertEqual(m.in_monomial_basis(), p) # Two-dimensional. y = Variable('y') m = ChebyshevVector({x: 4, y: 3}) p = Polynomial({ MonomialVector({y: 1}): -3, MonomialVector({y: 3}): 4, MonomialVector({ x: 2, y: 1 }): 24, MonomialVector({ x: 2, y: 3 }): -32, MonomialVector({ x: 4, y: 1 }): -24, MonomialVector({ x: 4, y: 3 }): 32, }) self.assertEqual(m.in_monomial_basis(), p)
def test_to_scalar(self): for Vector in Vectors: # Zero polynomial. p = Polynomial({}) self.assertEqual(p.to_scalar(), 0) # Polynomial equal to scalar. x = Variable('x') v0 = Vector({}) v1 = Vector({x: 2}) p = Polynomial({v0: 2.5}) self.assertEqual(p.to_scalar(), 2.5) # Polynomial not equal to scalar. p = Polynomial({v1: 2.5}) with self.assertRaises(RuntimeError): p.to_scalar()
def test_pow(self): for Vector in Vectors: x = Variable('x') y = Variable('y') v0 = Vector({x: 1, y: 3}) v1 = Vector({x: 2, y: 2}) p = Polynomial({v0: 3, v1: 5}) p0 = Polynomial({Vector({}): 1}) self.assertEqual(p**0, p0) p_pow = Polynomial({v0: 3, v1: 5}) for i in range(1, 5): self.assertEqual(p**i, p_pow) p_pow *= p # 0 ** 0 is undefined. p = Polynomial({}) with self.assertRaises(ValueError): p**0
def substitute_minimizer(self, expr): if isinstance(expr, Polynomial): p_opt = Polynomial({}) for v, c in expr: c_opt = self.result.GetSolution(c) if isinstance(c_opt, Expression): c_opt = c_opt.Evaluate() p_opt[v] = c_opt return p_opt else: return self.result.GetSolution(expr)
def test_len(self): for Vector in Vectors: x = Variable('x') y = Variable('y') v0 = Vector({x: 4, y: 1}) v1 = Vector({x: 5, y: 2}) v2 = Vector({x: 6}) p = Polynomial({v0: 5, v1: 2.5, v2: 3}) self.assertEqual(len(p), 3)
def test_pos_neg(self): for Vector in Vectors: x = Variable('x') y = Variable('y') v0 = Vector({x: 1, y: 3}) v1 = Vector({x: 2, y: 2}) v2 = Vector({x: 4, y: 1}) p = Polynomial({v0: 1 / 3, v1: -5.2, v2: .22}) q = Polynomial({v0: -1 / 3, v1: 5.2, v2: -.22}) p_pos = +p p_neg = -p self.assertEqual(p_pos, p) self.assertEqual(p_neg, q) # Positive and negative must return a copy. p_pos[v0] = 3 p_neg[v0] = 3 self.assertTrue(p_pos != p) self.assertTrue(p_neg != q)
def test_quadratic_form(self): for Vector in Vectors: x = Variable.multivariate('x', 2) basis = Vector.construct_basis(x, 1) Q = np.array([[1, 2, 3], [2, 4, 5], [3, 5, 6]]) p = Polynomial.quadratic_form(basis, Q) p_target = basis[0] * basis[0] + (basis[0] * basis[1]) * 4 + \ (basis[0] * basis[2]) * 6 + (basis[1] * basis[1]) * 4 + \ (basis[1] * basis[2]) * 10 + (basis[2] * basis[2]) * 6 self.assertEqual(p, p_target)
def test_degree(self): for Vector in Vectors: # Degrees 8 and 5. x = Variable('x') y = Variable('y') v0 = Vector({x: 4, y: 1}) v1 = Vector({x: 5, y: 3}) p = Polynomial({v0: 2.5, v1: 3}) self.assertEqual(p.degree(), 8) p[v1] = 0 self.assertEqual(p.degree(), 5) # Degree 0. v = Vector({}) p = Polynomial({v: 2.5}) self.assertEqual(p.degree(), 0) # Degree 0 for empty polynomial. p = Polynomial({}) self.assertEqual(p.degree(), 0)
def test_make_polynomial(self): for Vector in Vectors: # Make a polynomial out of a number. p = Vector.make_polynomial(1) self.assertEqual(p, Polynomial({Vector({}): 1})) p = Vector.make_polynomial(-3.14) self.assertEqual(p, Polynomial({Vector({}): -3.14})) # Make a polynomial out of a variable. x = Variable('x') p = Vector.make_polynomial(x) self.assertEqual(p, Polynomial({Vector({x: 1}): 1})) # Type error otherwise. with self.assertRaises(TypeError): p = Vector.make_polynomial('a') with self.assertRaises(TypeError): p = Vector.make_polynomial(MonomialVector({})) with self.assertRaises(TypeError): p = Vector.make_polynomial(Polynomial({}))
def test_radd(self): for Vector in Vectors: x = Variable('x') y = Variable('y') v0 = Vector({x: 4, y: 1}) v1 = Vector({x: 5, y: 2}) p = Polynomial({v0: 2.5, v1: 3}) self.assertEqual(p, 0 + p) with self.assertRaises(TypeError): 2 + p with self.assertRaises(TypeError): 'a' + p
def test_call(self): for Vector in Vectors: # Partial evaluation. x = Variable('x') y = Variable('y') z = Variable('z') v0 = Vector({x: 1, y: 2}) v1 = Vector({x: 3, z: 5}) p = Polynomial({v0: 3.5, v1: .5}) eval_dict = {x: 2, y: .3, z: -3.12} value = v0(eval_dict) * 3.5 + v1(eval_dict) * .5 self.assertAlmostEqual(p(eval_dict), value)
def test_in_monomial_basis(self): # Zero polynomial. p = Polynomial({}) p_mon = p.in_monomial_basis() self.assertEqual(p_mon, p) self.assertTrue(isinstance(p_mon, Polynomial)) # Non-zero polynomial. x = Variable('x') y = Variable('y') z = Variable('z') m0 = ChebyshevVector({x: 4, y: 3}) m1 = ChebyshevVector({x: 1, z: 3}) p = Polynomial({m0: 4, m1: 3}) p_mon = m0.in_monomial_basis() * 4 + m1.in_monomial_basis() * 3 self.assertEqual(p.in_monomial_basis(), p_mon)
def test_add_iadd_sub_isub(self): for Vector in Vectors: # Addition. x = Variable('x') y = Variable('y') v0 = Vector({x: 4, y: 1}) v1 = Vector({x: 5, y: 2}) v2 = Vector({x: 6}) p0 = Polynomial({v1: 2.5, v2: 3}) p1 = Polynomial({v1: 2, v0: 3.33}) p01 = Polynomial({v0: 3.33, v1: 4.5, v2: 3}) self.assertEqual(p0 + p1, p01) with self.assertRaises(TypeError): p0 + 2 with self.assertRaises(TypeError): p0 + 'a' # Iterative addition. p0 += p1 self.assertEqual(p0, p01) with self.assertRaises(TypeError): p0 += 2 with self.assertRaises(TypeError): p0 += 'a' # Subtraction. p0 = Polynomial({v1: 2.5, v2: 3}) p1 = Polynomial({v1: 2, v0: 3.33}) p01 = Polynomial({v0: -3.33, v1: .5, v2: 3}) self.assertEqual(p0 - p1, p01) with self.assertRaises(TypeError): p0 - 2 with self.assertRaises(TypeError): p0 - 'a' # Iterative subtraction. p0 -= p1 self.assertEqual(p0, p01) with self.assertRaises(TypeError): p0 -= 2 with self.assertRaises(TypeError): p0 -= 'a'
def test_init(self): for Vector in Vectors: # Empty initialization. p = Polynomial({}) self.assertEqual(p.coef_dict, {}) # Simple initialization. x = Variable('x') y = Variable('y') z = Variable('z') v0 = Vector({x: 4, y: 1}) v1 = Vector({x: 4, z: 2}) coef_dict = {v0: 2, v1: 3.22} p = Polynomial(coef_dict) self.assertEqual(p.coef_dict, coef_dict) # Removes zeros. coef_dict[v1] = 0 p = Polynomial(coef_dict) self.assertEqual(p.coef_dict, {v0: 2}) # Non-vector in the vectors. with self.assertRaises(TypeError): Polynomial({v0: 2, 2: 3.22}) with self.assertRaises(TypeError): Polynomial({v0: 2, x: 3.22}) with self.assertRaises(TypeError): Polynomial({3: 2, 4: 3.22}) # Vectors of different types. m = MonomialVector({x: 4, y: 1}) c = ChebyshevVector({x: 4, z: 2}) with self.assertRaises(TypeError): Polynomial({m: 2, c: 3.22})
def test_mul_imul_rmul(self): for Vector in Vectors: # Multiplication by scalar. x = Variable('x') y = Variable('y') v0 = Vector({x: 4, y: 1}) v1 = Vector({x: 5, y: 2}) v2 = Vector({x: 6}) p = Polynomial({v1: 2.5, v2: 3}) p6 = Polynomial({v1: 15, v2: 18}) self.assertEqual(p * 6, p6) self.assertEqual(6 * p, p6) p0 = Polynomial({}) self.assertEqual(p * 0, p0) self.assertEqual(0 * p, p0) # Iterative multiplication by scalar. p *= 6 self.assertEqual(p, p6) # Multiplication by polynomial. p0 = Polynomial({v0: 3.1, v1: 5.5}) p1 = Polynomial({v0: -2, v2: 2.9}) p01 = (v0 * v0) * 3.1 * (-2) + \ (v0 * v2) * 3.1 * 2.9 + \ (v1 * v0) * 5.5 * (-2) + \ (v1 * v2) * 5.5 * 2.9 self.assertEqual(p0 * p1, p01) # Iterative multiplication by polynomial. p0 *= p1 self.assertEqual(p0, p01) # Multiplication by zero polynomial must return a polynomial. q = Polynomial({}) p0q = p0 * q self.assertEqual(p0q, 0) self.assertTrue(isinstance(p0q, Polynomial))
def test_repr(self): for Vector in Vectors: # Only + signs. x = Variable('x') y = Variable('y') v0 = Vector({x: 4, y: 1}) v1 = Vector({x: 5, y: 2}) p = Polynomial({v0: 2.5, v1: 3}) r = '2.5' + v0.__repr__() + '+3' + v1.__repr__() self.assertEqual(p.__repr__(), r) self.assertEqual(p._repr_latex_(), '$' + r + '$') # With - signs. p = Polynomial({v0: 2.5, v1: -3}) r = '2.5' + v0.__repr__() + '-3' + v1.__repr__() self.assertEqual(p.__repr__(), r) self.assertEqual(p._repr_latex_(), '$' + r + '$') p = Polynomial({v0: -2.5, v1: 3}) r = '-2.5' + v0.__repr__() + '+3' + v1.__repr__() self.assertEqual(p.__repr__(), r) self.assertEqual(p._repr_latex_(), '$' + r + '$') # 0 if all the coefficients are 0. p = Polynomial({}) self.assertEqual(p.__repr__(), '0') self.assertEqual(p._repr_latex_(), '$0$') # Suppress 1 coefficients. p = Polynomial({v0: 2.5, v1: 1}) r = '2.5' + v0.__repr__() + '+' + v1.__repr__() self.assertEqual(p.__repr__(), r) self.assertEqual(p._repr_latex_(), '$' + r + '$') p = Polynomial({v0: 1, v1: 3.44}) r = v0.__repr__() + '+3.44' + v1.__repr__() self.assertEqual(p.__repr__(), r) self.assertEqual(p._repr_latex_(), '$' + r + '$') # Vector equal to one. v2 = Vector({}) p = Polynomial({v2: 5.33, v0: 2, v1: 3}) r = '5.33+2' + v0.__repr__() + '+3' + v1.__repr__() self.assertEqual(p.__repr__(), r) self.assertEqual(p._repr_latex_(), '$' + r + '$') # Just represent - if coefficient is -1. w0 = Vector({x: 1}) w1 = Vector({y: 1}) p = Polynomial({w0: 1, w1: -1}) r = w0.__repr__() + '-' + w1.__repr__() self.assertEqual(p.__repr__(), r) self.assertEqual(p._repr_latex_(), '$' + r + '$')
def add_polynomial(self, basis, name='c'): coef = self.add_variables(len(basis), name) poly = Polynomial(dict(zip(basis, coef))) return poly, coef
def add_sos_polynomial(self, basis, name='Q'): gram, cons = self.add_psd_variable(len(basis), name) poly = Polynomial.quadratic_form(basis, gram) return poly, gram, cons
def test_is_odd_is_even(self): for Vector in Vectors: # Even. x = Variable('x') y = Variable('y') v0 = Vector({x: 4, y: 2}) v1 = Vector({x: 1, y: 1}) p = Polynomial({v0: 2.5, v1: 3}) self.assertTrue(p.is_even()) self.assertFalse(p.is_odd()) # Not even nor odd. v0[y] += 1 self.assertFalse(p.is_odd()) self.assertFalse(p.is_even()) # Odd. v1[y] += 1 self.assertTrue(p.is_odd()) self.assertFalse(p.is_even()) # Degree 0. v = Vector({}) p = Polynomial({v: 1}) self.assertTrue(p.is_even()) self.assertFalse(p.is_odd()) # Empty polynomial is 0, hence even. p = Polynomial({}) self.assertTrue(p.is_even()) self.assertFalse(p.is_odd())
def substitute_minimizer(self, expr): if isinstance(expr, Polynomial): return Polynomial({v: c.value for v, c in expr}) else: return expr.value
def test_integral_definite_integral(self): for Vector in Vectors: # Indefinite. x = Variable('x') y = Variable('y') z = Variable('z') m0 = Vector({x: 4, y: 1}) m1 = Vector({x: 5, y: 2}) p = Polynomial({m0: 2.5, m1: -3}) px = m0.integral(x) * 2.5 + m1.integral(x) * (-3) py = m0.integral(y) * 2.5 + m1.integral(y) * (-3) pz = m0.integral(z) * 2.5 + m1.integral(z) * (-3) self.assertEqual(p.integral(x), px) self.assertEqual(p.integral(y), py) self.assertEqual(p.integral(z), pz) # Definite. lbs = [-3, -2, 2.12] ubs = [-1, 4, 5] px = px.substitute({x: -1}) - px.substitute({x: -3}) self.assertEqual(p.definite_integral([x], lbs[:1], ubs[:1]), px) pxy = px.integral(y) pxy = pxy.substitute({y: 4}) - pxy.substitute({y: -2}) self.assertEqual(p.definite_integral([x, y], lbs[:2], ubs[:2]), pxy) pxyz = pxy.integral(z) pxyz = pxyz.substitute({z: 5}) - pxyz.substitute({z: 2.12}) self.assertEqual(p.definite_integral([x, y, z], lbs, ubs), pxyz) # Definite wrong lengths. with self.assertRaises(ValueError): p.definite_integral([x, y], lbs, ubs) with self.assertRaises(ValueError): p.definite_integral([x, y, z], lbs[:2], ubs) with self.assertRaises(ValueError): p.definite_integral([x, y, z], lbs, ubs[:2]) # Integration of zero polynomial must return a polynomial. p = Polynomial({}) px = p.integral(x) self.assertEqual(px, 0) self.assertTrue(isinstance(px, Polynomial))