Source code for prodigy.util

"""
=================
``prodigy.util``
=================

.. autofunction:: prodigy.util.dedup_list
"""
import itertools
from typing import List, TypeVar, Collection

import sympy

T = TypeVar("T")


[docs] def dedup_list(data: List[T]) -> List[T]: """ Deduplicate a list using a set, preserving the ordering of the list. .. doctest:: >>> dedup_list([1,2,3,3]) [1, 2, 3] """ data_set = set() res = [] for element in data: if element not in data_set: res.append(element) data_set.add(element) return res
[docs] def make_poly_clause(coef: str, variables: Collection[str], powers: Collection[int]) -> str: """ Generates a polynomial clause _alpha_ * X^a * Y^b * Z^c ... """ c = [coef] vp = (['', '{}', '({}^{})'][min(p, 2)].format(v, p) for v, p in zip(variables, powers)) return '*'.join(c + [s for s in vp if s])
[docs] def compute_hadamard_product(f: str, g: str) -> str: """ Computes the Hadamard product of two univariate rational functions, i.e. the point-wise product of the coefficients in their formal power series representation. TODO: To be moved into the distribution interface. """ s_f, s_g = sympy.S(f), sympy.S(g) _, s_f_denom = s_f.as_numer_denom() _, s_g_denom = s_g.as_numer_denom() f_roots = s_f_denom.as_poly().all_roots() g_roots = s_g_denom.as_poly().all_roots() print(f"Degree f: {len(f_roots)}") print(f"Degree g: {len(g_roots)}") s_result_denom = sympy.Mul(*[1 - (fr * gr) * sympy.S("x") for fr, gr in itertools.product(f_roots, g_roots)]) print(f"Denominator: {s_result_denom}") s_compm_f = sympy.Matrix(sympy.matrices.expressions.CompanionMatrix( (sympy.S(f"x^{len(f_roots)}") * s_f_denom.subs("x", "1/x")).as_poly().monic())) s_compm_g = sympy.Matrix(sympy.matrices.expressions.CompanionMatrix( (sympy.S(f"x^{len(g_roots)}") * s_g_denom.subs("x", "1/x")).as_poly().monic())) s_result_denom_2 = sympy.det( sympy.eye(len(f_roots) * len(g_roots)) - (sympy.matrices.kronecker_product(s_compm_f, s_compm_g)) * sympy.S( "x")) print(f"Denominator: {s_result_denom_2}") print(f"Comparing {len(f_roots) * len(g_roots)} terms") print(s_f.series(n=len(f_roots) * len(g_roots))) print(s_g.series(n=len(f_roots) * len(g_roots))) f_const, f_rest = s_f.series(n=len(f_roots) * len(g_roots)).removeO().as_coeff_Add() g_const, g_rest = s_g.series(n=len(f_roots) * len(g_roots)).removeO().as_coeff_Add() f_rest_dict = f_rest.as_coefficients_dict() g_rest_dict = g_rest.as_coefficients_dict() res = {sympy.S("1"): f_const * g_const} for power in range(1, len(f_roots) * len(g_roots) + 1): s_power = sympy.S(f"x^{power}") if (s_power in g_rest_dict) and (s_power in f_rest_dict): res[s_power] = f_rest_dict[s_power] * g_rest_dict[s_power] else: res[s_power] = 0 print(res) s_num = sympy.Add(*[coef * monom for monom, coef in res.items()]) * s_result_denom_2 # truncate the polynomial for terms lower than m*n s_num = s_num.series(n=len(f_roots) * len(g_roots)).removeO() return str(s_num / s_result_denom_2)