def correctZeros(poly, MSmatrix, eigvals=True, checkNumber=True):
    '''
    A helper function. Takes in a polynomial, find the zeros, and calculates how many of the zeros are correct.
    In this function it asserts that the number of zeros is equal to the product of the degrees, which is only valid if
    the polynomial is random, and that at least 95% of the zeros are correct (so it will pass even
    on bad random runs)
    '''
    zeros = solve(poly, MSmatrix=MSmatrix, eigvals=eigvals)
    if checkNumber:
        assert (len(zeros) == poly.degree)
    correct = 0
    outOfRange = 0
    for zero in zeros:
        good = True
        if not np.isclose(0, poly([zero]), atol=1.e-3):
            good = False
        if good:
            correct += 1
    assert (100 * correct / (len(zeros)) > 95)
def division(polys,
             divisor_var=0,
             max_cond_num=1.e6,
             macaulay_zero_tol=1.e-12,
             verbose=False,
             polish=False,
             return_all_roots=True):
    '''Calculates the common zeros of polynomials using a division matrix.

    Parameters
    --------
    polys: list of MultiCheb Polynomials
        The polynomials for which the common roots are found.
    divisor_var : int
        What variable is being divided by. 0 is x, 1 is y, etc. Defaults to x.
    max_cond_num : float
        The maximum condition number of the Macaulay Matrix Reduction
    macaulay_zero_tol : float
        What is considered 0 in the macaulay matrix reduction.
    verbose : bool
        If True prints information about the solve.
    polish: bool
        If True runs a newton polish on the zeros before returning.
    return_all_roots : bool
        If True returns all the roots, otherwise just the ones in the unit box.
    Returns
    -----------
    zeros : numpy array
        The common roots of the polynomials. Each row is a root.
    '''
    #This first section creates the Macaulay Matrix with the monomials that don't have
    #the divisor variable in the first columns.
    polys, transform, is_projected = polys, lambda x: x, False
    if len(polys) == 1:
        from yroots.OneDimension import solve
        return transform(solve(polys[0], MSmatrix=0))
    power = is_power(polys)
    dim = polys[0].dim

    matrix_degree = np.sum([poly.degree for poly in polys]) - len(polys) + 1

    poly_coeff_list = []
    for poly in polys:
        poly_coeff_list = add_polys(matrix_degree, poly, poly_coeff_list)

    matrix, matrix_terms, cuts = create_matrix(poly_coeff_list, matrix_degree,
                                               dim, divisor_var)

    if verbose:
        np.set_printoptions(suppress=False, linewidth=200)
        print('\nStarting Macaulay Matrix\n', matrix)
        print(
            '\nColumns in Macaulay Matrix\nFirst element in tuple is degree of x monomial, Second element is degree of y monomial \n',
            matrix_terms)
        print(
            '\nLocation of Cuts in the Macaulay Matrix into [ Mb | M1* | M2* ]\n',
            cuts)

    #If bottom left is zero only does the first QR reduction on top part of matrix (for speed). Otherwise does it on the whole thing
    if np.allclose(matrix[cuts[0]:, :cuts[0]], 0):
        matrix, matrix_terms = rrqr_reduceMacaulay(
            matrix,
            matrix_terms,
            cuts,
            max_cond_num=max_cond_num,
            macaulay_zero_tol=macaulay_zero_tol)
    else:
        matrix, matrix_terms = rrqr_reduceMacaulay(
            matrix,
            matrix_terms,
            cuts,
            max_cond_num=max_cond_num,
            macaulay_zero_tol=macaulay_zero_tol)

    if isinstance(matrix, int):
        return -1

    VB = matrix_terms[matrix.shape[0]:]

    if verbose:
        np.set_printoptions(suppress=True, linewidth=200)
        print("\nFinal Macaulay Matrix\n", matrix)
        print("\nColumns in Macaulay Matrix\n", matrix_terms)

    #------------> chebyshev
    if not power:
        #Builds the inverse matrix. The terms are the vector basis as well as y^k/x terms for all k. Reducing
        #this matrix allows the y^k/x terms to be reduced back into the vector basis.
        x_pows_over_y = matrix_terms[np.where(
            matrix_terms[:, divisor_var] == 0)[0]]
        x_pows_over_y[:, divisor_var] = -np.ones(x_pows_over_y.shape[0],
                                                 dtype='int')
        inv_matrix_terms = np.vstack((x_pows_over_y, VB))
        inv_matrix = np.zeros([len(x_pows_over_y), len(inv_matrix_terms)])

        #A bunch of different dictionaries are used below for speed purposes and to prevent repeat calculations.

        #A dictionary of term in inv_matrix_terms to their spot in inv_matrix_terms.
        inv_spot_dict = dict()
        spot = 0
        for term in inv_matrix_terms:
            inv_spot_dict[tuple(term)] = spot
            spot += 1

        #A dictionary of terms on the diagonal to their reduction in the vector basis.
        diag_reduction_dict = dict()
        for i in range(matrix.shape[0]):
            term = matrix_terms[i]
            diag_reduction_dict[tuple(term)] = matrix[i][-len(VB):]

        #A dictionary of terms to the terms in their quotient when divided by x. (symbolically)
        divisor_terms_dict = dict()
        for term in matrix_terms:
            divisor_terms_dict[tuple(term)] = get_divisor_terms(
                term, divisor_var)

        #A dictionary of terms to their quotient when divided by x. (in the vector basis)
        term_divide_dict = dict()
        for term in matrix_terms[-len(VB):]:
            term_divide_dict[tuple(term)] = divide_term(
                term, inv_matrix_terms, inv_spot_dict, diag_reduction_dict,
                len(VB), divisor_terms_dict)

        #Builds the inv_matrix by dividing the rows of matrix by x.
        for i in range(cuts[0]):
            inv_matrix[i] = divide_row(matrix[i][-len(VB):],
                                       matrix_terms[-len(VB):],
                                       term_divide_dict, len(inv_matrix_terms))
            spot = matrix_terms[i]
            spot[divisor_var] -= 1
            inv_matrix[i][inv_spot_dict[tuple(spot)]] += 1

        #Reduces the inv_matrix to solve for the y^k/x terms in the vector basis.
        Q, R = qr(inv_matrix)

        if np.linalg.cond(R[:, :R.shape[0]]) > max_cond_num:
            return -1

        inv_solutions = np.hstack((np.eye(R.shape[0]),
                                   solve_triangular(R[:, :R.shape[0]],
                                                    R[:, R.shape[0]:])))

        #A dictionary of term in the vector basis to their spot in the vector basis.
        VB_spot_dict = dict()
        spot = 0
        for row in VB:
            VB_spot_dict[tuple(row)] = spot
            spot += 1

        #A dictionary of terms of type y^k/x to their reduction in the vector basis.
        inv_reduction_dict = dict()
        for i in range(len(inv_solutions)):
            inv_reduction_dict[tuple(
                inv_matrix_terms[i])] = inv_solutions[i][len(inv_solutions):]

        #Builds the division matrix and finds the eigenvalues and eigenvectors.
        division_matrix = build_division_matrix(VB, VB_spot_dict,
                                                diag_reduction_dict,
                                                inv_reduction_dict,
                                                divisor_terms_dict)
        #<---------end Chebyshev
    else:
        #--------->Power
        basisDict = makeBasisDict(matrix, matrix_terms, VB)

        #Dictionary of terms in the vector basis their spots in the matrix.
        VBdict = {}
        spot = 0
        for row in VB:
            VBdict[tuple(row)] = spot
            spot += 1

        # Build division matrix
        division_matrix = np.zeros((len(VB), len(VB)))
        for i in range(VB.shape[0]):
            var = np.zeros(dim)
            var[divisor_var] = 1
            term = tuple(VB[i] - var)
            if term in VBdict:
                division_matrix[VBdict[term]][i] += 1
            else:
                division_matrix[:, i] -= basisDict[term]
        #<----------end Power

    vals, vecs = eig(division_matrix, left=True, right=False)
    #conjugate because scipy gives the conjugate eigenvector
    vecs = vecs.conj()

    #     if len(vals) > len(np.unique(np.round(vals, 10))):
    #         return -1

    #     eigenvalue_cond = np.linalg.cond(vecs)
    #     if eigenvalue_cond*tol > 1:
    #         return -1

    #     if verbose:
    #         print("\nDivision Matrix\n", np.round(division_matrix[::-1,::-1], 2))
    #         print("\nLeft Eigenvectors (as rows)\n", vecs.T)
    #     if not power:
    #         if np.max(np.abs(vals)) > 1.e6:
    #             return -1

    #Calculates the zeros, the x values from the eigenvalues and the y values from the eigenvectors.
    zeros = list()

    for i in range(len(vals)):
        #         if power and abs(vecs[-1][i]) < 1.e-3:
        #             #This root has magnitude greater than 1, will possibly generate a false root due to instability
        #             continue
        #         if  np.abs(vals[i]) < 1.e-5:
        #             continue
        root = np.zeros(dim, dtype=complex)
        for spot in range(0, divisor_var):
            root[spot] = vecs[-(2 + spot)][i] / vecs[-1][i]
        for spot in range(divisor_var + 1, dim):
            root[spot] = vecs[-(1 + spot)][i] / vecs[-1][i]

        root[divisor_var] = 1 / vals[i]

        #         conditions = condeigv(division_matrix.T)
        #         if np.abs(vals[i]) > 1:
        #             print(root, conditions[i])

        if polish:
            root = newton_polish(polys, root)

        #throw out bad roots in cheb
        if not power:
            if np.any([abs(poly(root)) > 1.e-1 for poly in polys]):
                continue

        zeros.append(root)

    if return_all_roots:
        return transform(np.array(zeros))
    else:
        # only return roots in the unit complex hyperbox
        zeros = transform(np.array(zeros))
        return zeros[np.all(np.abs(zeros) <= 1, axis=0)]
def multiplication(polys,
                   max_cond_num,
                   macaulay_zero_tol,
                   verbose=False,
                   MSmatrix=0,
                   return_all_roots=True):
    '''
    Finds the roots of the given list of multidimensional polynomials using a multiplication matrix.

    Parameters
    ----------
    polys : list of polynomial objects
        Polynomials to find the common roots of.
    verbose : bool
        Prints information about how the roots are computed.
    MSmatrix : int
        Controls which Moller-Stetter matrix is constructed. The options are:
            0 (default) -- The Moller-Stetter matrix of a random polynomial
            Some positive integer i < dimension -- The Moller-Stetter matrix of x_i
    return_all_roots : bool
        If True returns all the roots, otherwise just the ones in the unit box.
    max_cond_num : float
        The maximum condition number of the Macaulay Matrix Reduction
    macaulay_zero_tol : float
        What is considered 0 in the macaulay matrix reduction.
    returns
    -------
    roots : numpy array
        The common roots of the polynomials. Each row is a root.
    Raises
    ------
    ConditioningError if MSMultMatrix(...) raises a ConditioningError.
    '''
    #We don't want to use Linear Projection right now
    #    polys, transform, is_projected = polys, lambda x:x, False

    if len(polys) == 1:
        from yroots.OneDimension import solve
        return transform(solve(polys[0], MSmatrix=0))
    poly_type = is_power(polys, return_string=True)
    dim = polys[0].dim

    if MSmatrix not in list(range(dim + 1)):
        raise ValueError(
            'MSmatrix must be 0 (random polynomial), or the index of a variable'
        )

    #By Bezout's Theorem. Useful for making sure that the reduced Macaulay Matrix is as we expect
    degrees = [poly.degree for poly in polys]
    max_number_of_roots = np.prod(degrees)

    try:
        m_f, var_dict, basisDict, VB = MSMultMatrix(
            polys,
            poly_type,
            verbose=verbose,
            MSmatrix=MSmatrix,
            max_cond_num=max_cond_num,
            macaulay_zero_tol=macaulay_zero_tol)
    except ConditioningError as e:
        raise e

    if verbose:
        print("\nM_f:\n", m_f[::-1, ::-1])

    # Get list of indexes of single variables and store vars that were not
    # in the vector space basis.
    var_spots = []
    removed_var_order = []
    removed_var_spots = []
    var_mask = []
    for order, spot in enumerate(get_var_list(dim)):
        if spot in var_dict:
            var_spots.append(var_dict[tuple(spot)])
            var_mask.append(True)
        else:
            removed_var_order.append(order)
            removed_var_spots.append(spot)
            var_mask.append(False)

    # Get left eigenvectors (come in conjugate pairs)
    vals, vecs = eig(m_f, left=True, right=False)

    if verbose:
        print('\nLeft Eigenvectors (as rows)\n', vecs.T)
        print('\nEigenvals\n', vals)

    zeros_spot = var_dict[tuple(0 for i in range(dim))]

    #throw out roots that were calculated unstably
    #     vecs = vecs[:,np.abs(vecs[zeros_spot]) > 1.e-10]
    if verbose:
        print('\nVariable Spots in the Vector\n', var_spots)
        print('\nEigeinvecs at the Variable Spots:\n', vecs[var_spots])
        print('\nConstant Term Spot in the Vector\n', zeros_spot)
        print('\nEigeinvecs at the Constant Term\n', vecs[zeros_spot])

    roots = np.zeros([len(vecs), dim], dtype=complex)
    roots[:, var_mask] = (vecs[var_spots] / vecs[zeros_spot]).T
    #Compute the removed variables
    for order, spot in zip(removed_var_order, removed_var_spots):
        for coeff, pows in zip(basisDict[spot], VB):
            temp = coeff
            for place, num in enumerate(pows):
                if num > 0:
                    temp *= roots[:, place]**num
            roots[:, order] -= temp

    #Check if too many roots
    assert roots.shape[
        0] <= max_number_of_roots, "Found too many roots,{}/{}/{}:{}".format(
            roots.shape, max_number_of_roots, degrees, roots)
    if return_all_roots:
        roots = np.array(roots, dtype=complex)
        # #print(roots)

        # REMARK: We don't always have good information about the derivatives,
        # so we can't use Newton polishing on our roots.
        # for i in range(len(roots)):
        #     roots[i] = newton_polish(polys,roots[i],niter=100,tol=1e-20)

        # #print(roots)
        return roots
    else:
        # only return roots in the unit complex hyperbox
        return roots[np.all(np.abs(roots) <= 1, axis=0)]
def multiplication(polys,
                   max_cond_num,
                   verbose=False,
                   return_all_roots=True,
                   method='svd'):
    '''
    Finds the roots of the given list of multidimensional polynomials using a multiplication matrix.

    Parameters
    ----------
    polys : list of polynomial objects
        Polynomials to find the common roots of.
    max_cond_num : float
        The maximum condition number of the Macaulay Matrix Reduction
    verbose : bool
        Prints information about how the roots are computed.
    return_all_roots : bool
        If True returns all the roots, otherwise just the ones in the unit box.
    returns
    -------
    roots : numpy array
        The common roots of the polynomials. Each row is a root.
    Raises
    ------
    ConditioningError if reduce_macaulay() raises a ConditioningError.
    TooManyRoots if the macaulay matrix returns more roots than the Bezout bound.
    '''
    #We don't want to use Linear Projection right now
    #    polys, transform, is_projected = polys, lambda x:x, False

    if len(polys) == 1:
        from yroots.OneDimension import solve
        return transform(solve(polys[0], MSmatrix=0))
    poly_type = is_power(polys, return_string=True)
    dim = polys[0].dim

    #By Bezout's Theorem. Useful for making sure that the reduced Macaulay Matrix is as we expect
    degrees = [poly.degree for poly in polys]
    max_number_of_roots = np.prod(degrees)

    matrix, matrix_terms, cut = build_macaulay(polys, verbose)

    # Attempt to reduce the Macaulay matrix
    if method == 'qrt':
        try:
            E, Q, cond, cond_back = reduce_macaulay_qrt(
                matrix, cut, max_cond_num)
        except ConditioningError as e:
            raise e
    elif method == 'tvb':
        try:
            E, Q, cond, cond_back = reduce_macaulay_tvb(
                matrix, cut, max_cond_num)
        except ConditioningError as e:
            raise e
    elif method == 'svd':
        try:
            E, Q, cond, cond_back = reduce_macaulay_svd(
                matrix, cut, max_cond_num)
        except ConditioningError as e:
            raise e

    # Construct the Möller-Stetter matrices
    # M is a 3d array containing the multiplication-by-x_i matrix in M[...,i]
    if poly_type == "MultiCheb":
        if method == 'qrt' or method == 'svd':
            M = ms_matrices_cheb(E, Q, matrix_terms, dim)
        elif method == 'tvb':
            M = ms_matrices_p_cheb(E, Q, matrix_terms, dim, cut)

    else:
        if method == 'qrt' or method == 'svd':
            M = ms_matrices(E, Q, matrix_terms, dim)
        elif method == 'tvb':
            M = ms_matrices_p(E, Q, matrix_terms, dim, cut)

    # Compute the roots using eigenvalues of the Möller-Stetter matrices
    roots, cond_eig = msroots(M)

    # Check if too many roots
    if roots.shape[0] > max_number_of_roots:
        raise TooManyRoots("Found too many roots,{}/{}/{}:{}".format(
            roots.shape, max_number_of_roots, degrees, roots))
    if return_all_roots:
        return roots
    else:
        # only return roots in the unit complex hyperbox
        return roots[np.all(np.abs(roots) <= 1, axis=0)]
def multiplication(polys, max_cond_num, verbose=False, return_all_roots=True,method='svd'):
    '''
    Finds the roots of the given list of multidimensional polynomials using a multiplication matrix.

    Parameters
    ----------
    polys : list of polynomial objects
        Polynomials to find the common roots of.
    max_cond_num : float
        The maximum condition number of the Macaulay Matrix Reduction
    verbose : bool
        Prints information about how the roots are computed.
    return_all_roots : bool
        If True returns all the roots, otherwise just the ones in the unit box.
    returns
    -------
    roots : numpy array
        The common roots of the polynomials. Each row is a root.
    '''
    #We don't want to use Linear Projection right now
#    polys, transform, is_projected = polys, lambda x:x, False

    if len(polys) == 1:
        from yroots.OneDimension import solve
        return transform(solve(polys[0], MSmatrix=0))
    poly_type = is_power(polys, return_string = True)
    dim = polys[0].dim

    #By Bezout's Theorem. Useful for making sure that the reduced Macaulay Matrix is as we expect
    bezout_bound = np.prod([poly.degree for poly in polys])

    matrix, matrix_terms, cut = build_macaulay(polys, verbose)

    roots = np.array([])

    # If cut is zero, then all the polynomials are linear and we solve
    # using solve_linear.
    if cut == 0:
        roots, cond = solve_linear([p.coeff for p in polys])
        # Make sure roots is a 2D array.
        roots = np.array([roots])
    else:
        # Attempt to reduce the Macaulay matrix
        if method == 'svd':
            res = reduce_macaulay_svd(matrix,cut,bezout_bound,max_cond_num)
            if res[0] is None:
                return res
            E,Q = res
        elif method == 'qrt':
            res = reduce_macaulay_qrt(matrix,cut,bezout_bound,max_cond_num)
            if res[0] is None:
                return res
            E,Q = res
        elif method == 'tvb':
            res = reduce_macaulay_tvb(matrix,cut,bezout_bound,max_cond_num)
            if res[0] is None:
                return res
            E,Q = res
        else:
            raise ValueError("Method must be one of 'svd','qrt' or 'tvb'")

        # Construct the Möller-Stetter matrices
        # M is a 3d array containing the multiplication-by-x_i matrix in M[...,i]
        if poly_type == "MultiCheb":
            if method == 'qrt' or method == 'svd':
                M = ms_matrices_cheb(E,Q,matrix_terms,dim)
            elif method == 'tvb':
                M = ms_matrices_p_cheb(E,Q,matrix_terms,dim,cut)

        else:
            if method == 'qrt' or method == 'svd':
                M = ms_matrices(E,Q,matrix_terms,dim)
            elif method == 'tvb':
                M = ms_matrices_p(E,Q,matrix_terms,dim,cut)

        # Compute the roots using eigenvalues of the Möller-Stetter matrices
        roots = msroots(M)

    if return_all_roots:
        return roots
    else:
        # only return roots in the unit complex hyperbox
        return roots[[np.all(np.abs(root) <= 1) for root in roots]]
def divisionNew(polys,
                divisor_var=0,
                tol=1.e-12,
                verbose=False,
                polish=False,
                return_all_roots=True):
    '''Calculates the common zeros of polynomials using a division matrix.

    Parameters
    --------
    polys: list of MultiCheb Polynomials
        The polynomials for which the common roots are found.
    divisor_var : int
        What variable is being divided by. 0 is x, 1 is y, etc. Defaults to x.
    tol : float
        The tolerance parameter for the Macaulay Reduce.
    verbose : bool
        If True prints information about the solve.
    polish: bool
        If True runs a newton polish on the zeros before returning.

    Returns
    -----------
    zeros : numpy array
        The common roots of the polynomials. Each row is a root.
    '''
    #This first section creates the Macaulay Matrix with the monomials that don't have
    #the divisor variable in the first columns.
    polys, transform, is_projected = LinearProjection.remove_linear(
        polys, 1e-4, 1e-8)
    if len(polys) == 1:
        from yroots.OneDimension import solve
        return transform(solve(polys[0], MSmatrix=0))
    power = is_power(polys)
    if power:
        raise ValueError("This only works for Chebyshev polynomials")

    dim = polys[0].dim
    matrix_degree = np.sum([poly.degree for poly in polys]) - len(polys) + 1
    poly_coeff_list = []
    for poly in polys:
        poly_coeff_list = add_polys(matrix_degree, poly, poly_coeff_list)

    matrix, matrix_terms, cuts = create_matrix(poly_coeff_list, matrix_degree,\
                                                   dim, divisor_var)

    x_pows_over_y = matrix_terms[:cuts[0]].copy()
    x_pows_over_y[:, divisor_var] = -np.ones(cuts[0], dtype='int')
    inv_matrix_terms = np.vstack((x_pows_over_y, matrix_terms))

    num_rows = matrix.shape[0]
    inv_matrix = np.zeros([num_rows + matrix.shape[0], len(inv_matrix_terms)])
    cuts = tuple([cuts[0], cuts[0] + cuts[1]])

    #A dictionary of term in inv_matrix_terms to their spot in inv_matrix_terms.
    inv_spot_dict = dict()
    spot = 0
    for term in inv_matrix_terms:
        inv_spot_dict[tuple(term)] = spot
        spot += 1

    #A dictionary of terms to the terms in their quotient when divided by x. (symbolically)
    divisor_terms_dict = dict()
    for term in matrix_terms:
        divisor_terms_dict[tuple(term)] = get_divisor_terms(term, divisor_var)

    #A dictionary of terms to their quotient when divided by x. (in the vector basis)
    term_divide_dict = dict()
    for term in matrix_terms:
        term_divide_dict[tuple(term)] = divide_term(term, inv_matrix_terms,
                                                    inv_spot_dict,
                                                    divisor_terms_dict)

    #Builds the inv_matrix by dividing the rows of matrix by x.
    for i in range(num_rows):
        inv_matrix[i] = divide_row(matrix[i], matrix_terms, term_divide_dict,
                                   len(inv_matrix_terms))

    inv_matrix[num_rows:, cuts[0]:] = matrix

    matrix, matrix_terms, perm = rrqr_reduceMacaulay(inv_matrix,
                                                     inv_matrix_terms,
                                                     cuts,
                                                     accuracy=tol,
                                                     return_perm=True)
    if isinstance(matrix, int):
        return -1

    for term in term_divide_dict:
        term_divide_dict[tuple(term)] = term_divide_dict[tuple(term)][perm]

    VB = matrix_terms[matrix.shape[0]:]
    basisDict = makeBasisDict2(matrix, matrix_terms)

    #     print(len(VB))

    #Dictionary of terms in the vector basis their spots in the matrix.
    VBdict = {}
    spot = 0
    for row in VB:
        VBdict[tuple(row)] = spot
        spot += 1

    #Builds the division matrix and finds the eigenvalues and eigenvectors.
    division_matrix = build_division_matrix(VB, VBdict, basisDict,
                                            term_divide_dict, matrix_terms)

    vals, vecs = eig(division_matrix, left=True, right=False)
    #conjugate because scipy gives the conjugate eigenvector
    vecs = vecs.conj()

    if len(vals) > len(np.unique(np.round(vals, 10))):
        return -1

    vals2, vecs2 = eig(vecs)
    sorted_vals2 = np.sort(np.abs(vals2))  #Sorted smallest to biggest
    if sorted_vals2[0] < sorted_vals2[-1] * tol:
        return -1

    if verbose:
        print("\nDivision Matrix\n", np.round(division_matrix[::-1, ::-1], 2))
        print("\nLeft Eigenvectors (as rows)\n", vecs.T)

    if np.max(np.abs(vals)) > 1.e6:
        return -1

    #Calculates the zeros, the x values from the eigenvalues and the y values from the eigenvectors.
    zeros = list()

    for i in range(len(vals)):
        if np.abs(vals[i]) < 1.e-5:
            continue
        root = np.zeros(dim, dtype=complex)
        for spot in range(0, divisor_var):
            root[spot] = vecs[-(2 + spot)][i] / vecs[-1][i]
        for spot in range(divisor_var + 1, dim):
            root[spot] = vecs[-(1 + spot)][i] / vecs[-1][i]

        root[divisor_var] = 1 / vals[i]

        if polish:
            root = newton_polish(polys, root, tol=tol)

        #throw out bad roots in cheb
        if np.any([abs(poly(root)) > 1.e-1 for poly in polys]):
            continue

        zeros.append(root)

    if return_all_roots:
        return transform(np.array(zeros))
    else:
        # only return roots in the unit complex hyperbox
        zeros = transform(np.array(zeros))
        return zeros[np.all(np.abs(zeros) <= 1, axis=0)]