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
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
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
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
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
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