def form_size(expr: Expr) -> typing.Tuple[Size, typing.Optional[Symbol]]: """Form a size object from a SymPy expression.""" symbs = expr.atoms(Symbol) n_symbs = len(symbs) if n_symbs == 0: symb = None coeff_exprs = [expr] elif n_symbs == 1: symb = symbs.pop() coeff_exprs = Poly(expr, symb).all_coeffs() coeff_exprs.reverse() else: raise ValueError( 'Invalid expression', expr, 'expecting single variate polynomial (or number)' ) if all(i.is_integer for i in coeff_exprs): dtype = int else: dtype = float if len(coeff_exprs) > 1: coeffs = np.array(coeff_exprs, dtype=dtype) cost = SVPoly(coeffs) elif len(coeff_exprs) == 1: cost = dtype(coeff_exprs[0]) else: assert False return cost, symb
def get_reduced_fraction(numerator_coefs, denominator_coefs, result_deg): """ Reduce polynomial division by common factors. So (1+k)/(1+2k+k**2) will be reduced to 1/(1+k) Items in the coefs list start from the lowest degree ([a, b, c] = a + b*x +c*x**2) """ k = var('k') numerator = sum([coef * k**i for i, coef in enumerate(numerator_coefs)]) denominator = sum( [coef * k**i for i, coef in enumerate(denominator_coefs)]) reduced_num, reduced_denom = (numerator / denominator).simplify().as_numer_denom() reduced_num_coefs, reduced_denom_coefs = Poly( reduced_num, k).all_coeffs(), Poly(reduced_denom, k).all_coeffs() reduced_num_coefs.reverse() reduced_denom_coefs.reverse() # If the higher degrees are missing from the expression, then the list will have a smaller size then needed. # Adding zeros as padding to the end. reduced_num_coefs += [0] * (result_deg + 1 - len(reduced_num_coefs)) reduced_denom_coefs += [0] * (result_deg + 1 - len(reduced_denom_coefs)) return reduced_num_coefs, reduced_denom_coefs