def test_verify_degree(self):
        """
		Check the degree of the polynomio
		"""
        minimum = randint(2, 70)
        e = self.generate_Encrypter("test_files/")
        p = self.get_poly(e, "test_files/", minimum)
        polynomial = Poly(p.generate_random_poly())

        assert polynomial.degree() == minimum - 1
Ejemplo n.º 2
0
def PolyDivModOverQ(a, b: Poly):  #−> (Poly , Poly ):
    while (a.degree() > 0 and a.coef[a.degree()] == Fraction(0, 1)):
        a = Poly(a.coef[:a.degree()])
    while (b.degree() > 0 and b.coef[b.degree()] == Fraction(0, 1)):
        b = Poly(b.coef[:b.degree()])
    if (a.degree() < b.degree()):
        return Poly([Fraction(0, 1)]), a

    m = a.degree() - b.degree()
    revb = Poly(b.coef[::-1])
    rrevb = PolyInverseModOverQ(revb, m + 1)
    if (rrevb is None):
        raise ZeroDivisionError("ohohoh")
    q1 = Poly(a.coef[::-1]) * rrevb
    q1 = Poly(q1.coef[:(m + 1)])
    q = Poly(q1.coef[::-1])
    r = a - b * q
    while (r.degree() > 0 and r.coef[r.degree()] == Fraction(0, 1)):
        r = Poly(r.coef[:r.degree()])
    return q, r
Ejemplo n.º 3
0
def PolyDivModOverZn(a, b: Poly, n: int):  #−> (Poly , Poly ):
    a = a.trim()
    b = b.trim()
    if (n < 1):
        raise ValueError
    if (a.degree() < b.degree()):
        return Poly([0]), a
    m = a.degree() - b.degree()
    revb = Poly(b.coef[::-1])
    rrevb = PolyInverseModOverZn(revb, m + 1, n)
    if (rrevb is None):
        raise ZeroDivisionError("")
    reva = Poly(a.coef[::-1])
    q1 = reva * rrevb
    q1 = q1.truncate(m + 1)
    q = Poly(q1.coef[::-1])
    q = modPoly(q, n)
    bq = b * q
    bq = modPoly(bq, n)
    r = modPoly(a - b * q, n)
    r = Poly(r.coef[::-1])
    r.trim()
    r = Poly(r.coef[::-1])
    return q, r
Ejemplo n.º 4
0
def brune_extraction(num, denom):
    assert num.degree() == denom.degree()
    # Identify s at which re[z(iw)] is minimized
    re_z_w_num, re_z_w_denom = get_real_polynomial(num, denom)
    w0 = get_polynomial_minimum(re_z_w_num, re_z_w_denom)
    s0 = 1j * w0
    z0 = num(s0) / denom(s0)

    # Extract resistor and inductor, producing lossless pole
    r = z0.real
    l1 = z0.imag / w0
    num -= denom * Polynomial([r, l1])

    # Remove the resulting zero
    zero_p = Polynomial([w0**2, 0, 1])
    new_num = num / zero_p
    s_new_num = Polynomial([0, 1]) * new_num
    s_new_num_r = s_new_num % zero_p
    denom_r = denom % zero_p
    res = denom_r / s_new_num_r
    new_denom = (denom - res * s_new_num) / zero_p

    yc = res.coef[0] / w0
    c2 = yc / w0
    l2 = 1 / (yc * w0)
    l3 = -l1 * l2 / (l1 + l2)

    final_num = new_num - new_denom * Polynomial([0, l3])

    # TODO: calculate final_num in more numerically stable way
    if final_num.degree() == new_denom.degree() + 1:
        if final_num.coef[-1] / final_num.coef[-2] < 1e-10:
            final_num = Polynomial(final_num.coef[:-1])

    assert final_num.degree() == new_denom.degree()
    return (r, l1, c2, l2, l3), final_num, new_denom
Ejemplo n.º 5
0
def QuantumSignalProcessingPhases(poly,
                                  eps=1e-4,
                                  suc=1 - 1e-4,
                                  signal_operator="Wx",
                                  measurement=None,
                                  tolerance=1e-6,
                                  method="laurent",
                                  **kwargs):
    """
    Generate QSP phase angles for a given polynomial.

    Args:
        poly: polynomial object
        eps: capitilization parameter for numerical stability
        suc: scaling factor for numerical stability
        signal_operator: QSP signal-dependent operation ['Wx', 'Wz']
        measurement: measurement basis (defaults to signal operator basis)
        tolerance: error tolerance in final reconstruction
        method: method to use for computing phase angles ['laurent', 'tf']

    Returns:
        Array of QSP angles.

    Raises:
        CompletionError: Raised when polynomial cannot be completed in given
            model.
        AngleFindingError: Raised if angle finding algorithm cannot find
        sequence to specified tolerance.
        ValueError: Raised if invalid model (or method) is specified.
    """
    if isinstance(poly, np.ndarray) or isinstance(poly, list):
        poly = Polynomial(poly)
    elif isinstance(poly, TargetPolynomial):
        poly = Polynomial(poly.coef)

    if measurement is None:
        if signal_operator == "Wx":
            measurement = "x"
        elif signal_operator == "Wz":
            measurement = "z"

    if method == "tf":
        if not signal_operator == "Wx":
            raise ValueError(
                f"Must use Wx signal operator model with tf method")
        return QuantumSignalProcessingPhasesWithTensorflow(
            poly, measurement=measurement, **kwargs)
    elif not method == "laurent":
        raise ValueError(f"Invalid method {method}")

    model = (signal_operator, measurement)

    # Perform completion
    if model in {("Wx", "x"), ("Wz", "z")}:
        # Capitalization: eps/2 amount of error budget is put to the highest
        # power for sake of numerical stability.
        poly = suc * \
            (poly + Polynomial([0, ] * poly.degree() + [eps / 2, ]))

        lcoefs = poly2laurent(poly.coef)
        lalg = completion_from_root_finding(lcoefs, coef_type="F")
    elif model == ("Wx", "z"):
        lalg = completion_from_root_finding(poly.coef, coef_type="P")
    else:
        raise ValueError("Invalid model: {}".format(str(model)))

    # Decomposition phase
    phiset = angseq(lalg)

    # Verify by reconstruction
    adat = np.linspace(-1., 1., 100)
    response = ComputeQSPResponse(adat,
                                  phiset,
                                  signal_operator=signal_operator,
                                  measurement=measurement)["pdat"]
    expected = poly(adat)

    max_err = np.max(np.abs(response - expected))
    if max_err > tolerance:
        raise AngleFindingError(
            "The angle finding program failed on given instance, with an error of {}. Please relax the error budget and / or the success probability."
            .format(max_err))

    return phiset
Ejemplo n.º 6
0
class PolynomialCT:
    """  Calculate the Polynomial Chirp Transformation parameters

        ===== Attributes =======
        alpha: polynomial coefficients from highest to lowest order
        z: signal data
        fs: sampling rate
        win_size: Size of sampling window

        hidden:
        _polynomial: underlying polynomial funtion
        tfd: current estimate of the polynomial chirplet
    """

    # not
    def __init__(self,
                 data,
                 fs=2 * np.pi,
                 win_size=256,
                 overlap=None,
                 poly_order=6,
                 initial_alpha=None):
        """ Initialize class. 
        """
        if initial_alpha is None:
            alpha = np.zeros(poly_order + 1)
        else:
            alpha = initial_alpha
        self.alpha = alpha

        self.z = data
        self.fs = fs
        self.poly_order = poly_order
        self._polynomial = Polynomial(alpha)
        # transform frequency
        num_time_bins = self.z.size // win_size
        num_freq_bins = win_size // 2
        self.win_size = win_size
        if overlap is None:
            self.overlap = num_freq_bins // 2
        else:
            self.overlap = overlap
        self.tfd = np.zeros((num_freq_bins, num_time_bins), dtype='complex')

    # complete
    def _FRotationOperator(self, times):
        """ Calculate the nonlinear Frequency Rotation operator for self.z, 
            using parameters self.alpha for times <times>.

            Output: (times.size,) numpy.ndarray
        """
        sum_ = np.zeros(times.size, dtype='complex')
        for i in range(2, self._polynomial.degree() + 2):
            sum_ = sum_ + 1 / i * self.alpha[i - 1] * times**i
        return np.exp(-1j * sum_)

    # complete
    def _FShiftOperator(self, times, t0):
        """ Calculate the nonlinear Frequency Shift operator for self.z, 
            using parameters self.alpha for times <times>.

            Output: (num_time_bins, win_size) numpy.ndarray
        """
        if (t0 - self.win_size // 2) >= 0:
            time_win = times[t0 - self.win_size // 2:t0 + self.win_size // 2]
        else:
            time_win = times[:t0 + self.win_size // 2]

        sum_ = np.zeros(time_win.shape, dtype='complex')
        mid_value = times[t0]
        for k in range(2, self._polynomial.degree() + 2):
            sum_ = sum_ + self.alpha[k - 1] * time_win**(k - 1) * mid_value
        return np.exp(1j * sum_)

    def _STFT(self):
        """ Helper function for calculating the PCT. This function does all the
            heavy lifting. Output the PCT(t, k) where k is the frequency index.
            The STFT is computed with no overlap and a gaussian window. 

            Output: (num_freq_bins, num_time_bins) numpy.ndarray
        """
        num_time_bins = self.z.size // (self.win_size - self.overlap)  #+ 1
        num_freq_bins = self.win_size // 2
        num_stfts = self.win_size // (self.win_size - self.overlap)
        Zxx = np.zeros((num_freq_bins, num_time_bins), dtype='complex')

        times = np.arange(self.z.size) / self.fs  # divide by sampling rate
        freq_rot = self._FRotationOperator(times)
        # gaussian window
        window = 1/(np.sqrt(2 * np.pi) * self.win_size // 2) *\
                 get_window(('gaussian', self.win_size // 2), self.win_size)

        for m in range(num_stfts):
            for i in range(num_time_bins):
                t = i * (self.win_size - self.overlap)
                if (t + self.win_size) > self.z.size:
                    continue
                if t - self.win_size // 2 < 0:
                    x = self.z[:t + self.win_size // 2 ] *\
                            freq_rot[:t + self.win_size //2]
                    # further transform the signal with the correct shift operator
                    freq_shift = self._FShiftOperator(times, t)
                    x_transform = x * window[:x.size] * freq_shift
                else:
                    x = self.z[t - self.win_size // 2:t + self.win_size // 2 ] *\
                            freq_rot[t - self.win_size // 2:t + self.win_size //2]
                    # further transform the signal with the correct shift operator
                    freq_shift = self._FShiftOperator(times, t)
                    x_transform = x * window[:x.size] * freq_shift

                output = np.fft.fft(x_transform)[:num_freq_bins]
                factor = 1 - m * (self.win_size - self.overlap)
                assert (factor <= 1)
                Zxx[:, i] = Zxx[:, i] + factor * np.power(output, 2)
        Zxx = np.sqrt(Zxx) / (self.win_size - self.overlap)

        t = np.arange(0, num_time_bins) * (
            (self.win_size - self.overlap) / self.fs)
        f = np.arange(0, num_freq_bins) * (self.fs / self.win_size)
        # plt.pcolormesh(t,f,np.abs(Zxx), cmap=cm.get_cmap('jet'),shading='gouraud')
        # plt.ylabel('freq')
        # plt.show()
        return Zxx

    # complete
    def REN(self, pct):
        # frequency correction due to infinite integral
        integrand = np.log10(np.power(np.abs(pct), 3))
        return -1 * romb(romb(integrand, axis=1), axis=0)

    def _update_polynomial(self):
        # generate a line
        # print(self.alpha)
        num_time_bins = self.z.size // (self.win_size - self.overlap)  # + 1
        num_freq_bins = self.win_size // 2
        # scale the bins
        freq_values = np.arange(0,num_freq_bins) *\
                      (self.fs / self.win_size)
        tfd_peak = freq_values[np.argmax(np.abs(self.tfd), axis=0)]
        time_values = np.linspace(0,num_time_bins,tfd_peak.size) *\
                      ((self.win_size - self.overlap) / self.fs)
        fitted_polynomial = self._polynomial.fit(time_values[1:-1],
                                                 tfd_peak[1:-1],
                                                 self.poly_order)
        self._polynomial = fitted_polynomial.convert().copy()
        self.alpha = self._polynomial.coef
        # plt.plot(time_values[1:], tfd_peak[1:], 'r.')
        # plt.plot(time_values[1:], polyval(time_values[1:], self.alpha, 'k'))
        # plt.show()

    def PCT(self, initial_state=False):
        """ Calculate the polynomial chirp transformation using the parameters 
            <alpha> for  a analytic signal z[n] <z>.

            This function updates the following attributes: polynomial, ,
            tfd, and alpha
            === params ===
            initial_state: If True the polynomial parameters wont be estimated. 
        """
        # update polynomial
        # print("PCT running...")
        # recalculate the params of the instantaneous frequency
        if not initial_state:
            self._update_polynomial()

        # transform signal and compute the STFT
        self.tfd = self._STFT()
        # print("PCT end.")

    # complete
    def Run(self, err, max_iter=100, iter_count=False):
        """ Run the system.

            === params ===
            err: stopping condition form 0 < err < 1
            max_iter: maximum number of runs
            iter_count: if True return the number of iterations required to
                        reach termination criteria
        """
        change_in_ren = inf  # Current change in Renyi entropy
        self.PCT(True)
        count = 0
        while (change_in_ren > err) and (max_iter > count):
            prev_pct = self.tfd.copy()
            self.PCT()
            curr_pct = self.tfd
            #REN_prev = self.REN(prev_pct)
            #REN_curr = self.REN(curr_pct)
            #change_in_ren = np.abs((REN_curr - REN_prev) / REN_curr)
            count += 1