def pell(d): r""" :param d: a positive non-square integer :return: positive integers h, k such that :math:`h^2 - dk^2 = 1`. Uses Lagrange's method of continued fractions. """ h0, k0 = 0, 1 h1, k1 = 1, 0 h0s, k0s = 0, 1 h1s, k1s = 1, 0 modulus = prod([2, 3, 5, 7, 11, 13, 17, 19, 23, 29]) for ai in cont_frac_quad(0, 1, 1, d): h = ai * h1 + h0 k = ai * k1 + k0 hs = (ai * h1s + h0s) % modulus ks = (ai * k1s + k0s) % modulus if (hs**2 - d * ks**2) % modulus == 1: if h**2 - d * k**2 == +1: return h, k h0, k0 = h1, k1 h1, k1 = h, k h0s, k0s = h1s, k1s h1s, k1s = hs, ks
def phi(nn): r""" :param nn: a positive integer :return: the number of natural numbers 1 <= kk < nn that are relatively prime to nn. """ factors = factorize2(nn) return prod([pp**(kk - 1) * (pp - 1) for (pp, kk) in factors])
def divisor_function(kk, nn): r""" :param kk: the exponent :param nn: a positive integer :return: :math:`\sum_{d|n} d^k` """ factors = factorize2(nn) return prod([(ee + 1) if kk == 0 else (pp**(kk * (ee + 1)) - 1) // (pp**kk - 1) for (pp, ee) in factors])
def compute(self): """ Estimate (without any guarantee if upper or lower bound) by searching over ReLU signs of each layer. """ timer = utils.Timer() # Step 1: split up the network # f(x) matches r/(LR)+Lx/ # J(x) matches r/(L Lambda)+L/ # We do SVD's on each linear layer svds = [] for linear_layer in self.network.fcs: if (linear_layer == self.network.fcs[-1] and self.c_vector is not None): c_vec = torch.tensor(self.c_vector).view(1, -1) c_vec = c_vec.type(self.network.dtype) weight = c_vec @ linear_layer.weight else: weight = linear_layer.weight svds.append(torch.svd(weight)) num_relus = len(self.network.fcs) - 1 # Then set up each of the (num_relus) subproblems: subproblems = [] # [(Left, Right), ....] for relu_num in range(num_relus): left_svd = svds[relu_num + 1] right_svd = svds[relu_num] _, sigma_ip1, v_ip1 = svds[relu_num + 1] u_i, sigma_i, _ = svds[relu_num] if relu_num != num_relus - 1: sigma_ip1 = torch.sqrt(sigma_ip1) if relu_num != 0: sigma_i = torch.sqrt(sigma_i) sigma_i = torch.diag(sigma_i) sigma_ip1 = torch.diag(sigma_ip1) subproblems.append(((sigma_ip1 @ v_ip1.t()).data, (u_i @ sigma_i).data)) # And solve each of the subproblems: dual_norm = {'linf': 1, 'l2': 2, 'l1': np.inf}[self.primal_norm] lips = [sl.optim_nn_pca_greedy(*_, verbose=False, use_tqdm=False, norm_ord=2)[0] for _ in subproblems] self.value = utils.prod(lips) self.compute_time = timer.stop() return self.value
def legendre(a, p): """ Return (a/p), the Legendre symbol (p is prime) (a/p) = 0 if p|a = 1 if a is a quad residue mod p = -1 if a is a quad non-residue mod p """ a = a % p if a == 0: return 0 if a == 1: return 1 if a == -1: if p % 4 == 3: return -1 elif p % 4 == 1: return 1 else: return 0 if a == 2: p_mod_8 = p % 8 if p_mod_8 == 1 or p_mod_8 == 7: return 1 elif p_mod_8 == 3 or p_mod_8 == 5: return -1 else: return 0 if not isprime(a): return prod([legendre(q, p) for q, e in factorize2(a) if e % 2]) if p % 4 == 1 or a % 4 == 1: return legendre(p % a, a) else: return -legendre(p % a, a)
def f(facts): return prod([p**e for (p, e) in facts])