def _minpoly_exp(ex, x): """ Returns the minimal polynomial of ``exp(ex)`` """ c, a = ex.args[0].as_coeff_Mul() if a == I * pi: if c.is_rational: q = sympify(c.q) if c.p == 1 or c.p == -1: if q == 3: return x**2 - x + 1 if q == 4: return x**4 + 1 if q == 6: return x**4 - x**2 + 1 if q == 8: return x**8 + 1 if q == 9: return x**6 - x**3 + 1 if q == 10: return x**8 - x**6 + x**4 - x**2 + 1 if q.is_prime: s = 0 for i in range(q): s += (-x)**i return s # x**(2*q) = product(factors) factors = [cyclotomic_poly(i, x) for i in divisors(2 * q)] mp = _choose_factor(factors, x, ex) return mp else: raise NotAlgebraic("%s does not seem to be an algebraic element" % ex) raise NotAlgebraic("%s does not seem to be an algebraic element" % ex)
def _minpoly_exp(ex, x): """ Returns the minimal polynomial of ``exp(ex)`` """ c, a = ex.args[0].as_coeff_Mul() p = sympify(c.p) q = sympify(c.q) if a == I*pi: if c.is_rational: if c.p == 1 or c.p == -1: if q == 3: return x**2 - x + 1 if q == 4: return x**4 + 1 if q == 6: return x**4 - x**2 + 1 if q == 8: return x**8 + 1 if q == 9: return x**6 - x**3 + 1 if q == 10: return x**8 - x**6 + x**4 - x**2 + 1 if q.is_prime: s = 0 for i in range(q): s += (-x)**i return s # x**(2*q) = product(factors) factors = [cyclotomic_poly(i, x) for i in divisors(2*q)] mp = _choose_factor(factors, x, ex) return mp else: raise NotAlgebraic("%s doesn't seem to be an algebraic element" % ex) raise NotAlgebraic("%s doesn't seem to be an algebraic element" % ex)
def torsion_points(self): """ Return torsion points of curve over Rational number. Return point objects those are finite order. According to Nagell-Lutz theorem, torsion point p(x, y) x and y are integers, either y = 0 or y**2 is divisor of discriminent. According to Mazur's theorem, there are at most 15 points in torsion collection. Examples ======== >>> from ec import EllipticCurve >>> e2 = EllipticCurve.minimal(-43, 166) >>> [i for i in e2.torsion_points()] [O, (3, 8), (3, -8), (-5, 16), (-5, -16), (11, 32), (11, -32)] """ if self.characteristic > 0: raise ValueError("No torsion point for Finite Field.") yield InfinityPoint(self) for x in solve(self._eq.subs(y, 0)): if x.is_rational: yield self(x, 0) for i in divisors(self.discriminant, generator=True): j = int(i**.5) if j**2 == i: for x in solve(self._eq.subs(y, j)): p = self(x, j) if x.is_rational and p.order() != oo: yield p yield -p
def singspec(elem, path='output.h5'): with pd.HDFStore(path) as store: N = len(store.sim) divs = divisors(N)[4:12] vals = np.zeros((len(divs), 3)) for i in range(len(divs)): print(divs[i], flush=1) vals[i] = h_svd(elem, divs[i], path=path) fig = plt.figure(figsize=(8,8)) fig.set_tight_layout(True) grid = gs.GridSpec(3, 1) first = plt.subplot(grid[0]) first.semilogx(divs, vals[:,0]) second = plt.subplot(grid[1]) second.semilogx(divs, vals[:,1]) third = plt.subplot(grid[2]) third.semilogx(divs, vals[:,2]) plt.show()
def optimize_calc_options(nodes, mpi_per_node, omp_per_mpi, use_omp, mpi_omp_ratio, fleurinpData=None, kpts=None, sacrifice_level=0.9, only_even_MPI=False): """ Makes a suggestion on parallelisation setup for a particular fleurinpData. Only the total number of k-points is analysed: the function suggests ideal k-point parallelisation + OMP parallelisation (if required). Note: the total number of used CPUs per node will not exceed mpi_per_node * omp_per_mpi. Sometimes perfect parallelisation is terms of idle CPUs is not what used wanted because it can harm MPI/OMP ratio. Thus the function first chooses first top parallelisations in terms of total CPUs used (bigger than sacrifice_level * maximal_number_CPUs_possible). Then a parallelisation which is the closest to the MPI/OMP ratio is chosen among them and returned. :param nodes: maximal number of nodes that can be used :param mpi_per_node: an input suggestion of MPI tasks per node :param omp_per_mpi: an input suggestion for OMP tasks per MPI process :param use_omp: False if OMP parallelisation is not needed :param mpi_omp_ratio: requested MPI/OMP ratio :param fleurinpData: FleurinpData to extract total number of kpts from :param kpts: the total number of kpts :param sacrifice_level: sets a level of performance sacrifice that a user can afford for better MPI/OMP ratio. :parm only_even_MPI: if set to True, the function does not set MPI to an odd number (if possible) :returns nodes, MPI_tasks, OMP_per_MPI, message: first three are parallelisation info and the last one is an exit message. """ from sympy.ntheory.factor_ import divisors import numpy as np cpus_per_node = mpi_per_node * omp_per_mpi if fleurinpData: kpts = fleurinpData.get_nkpts() elif not kpts: raise ValueError('You must specify either kpts of fleurinpData') divisors_kpts = divisors(kpts) possible_nodes = [x for x in divisors_kpts if x <= nodes] suggestions = [] for n_n in possible_nodes: advise_cpus = [x for x in divisors(kpts // n_n) if x <= cpus_per_node] for advised_cpu_per_node in advise_cpus: suggestions.append((n_n, advised_cpu_per_node)) def add_omp(suggestions, only_even_MPI_1): """ Also adds possibility of omp parallelisation """ final_suggestion = [] for suggestion in suggestions: if use_omp: omp = cpus_per_node // suggestion[1] else: omp = 1 # here we drop parallelisations having odd number of MPIs if only_even_MPI_1 and suggestion[1] % 2 == 0 or not only_even_MPI_1: final_suggestion.append([suggestion[0], suggestion[1], omp]) return final_suggestion # all possible suggestions taking into account omp suggestions_save = suggestions suggestions = np.array(add_omp(suggestions, only_even_MPI)) if not len(suggestions): # only odd MPI parallelisations possible, ignore only_even_MPI suggestions = np.array(add_omp(suggestions_save, False)) best_resources = max(np.prod(suggestions, axis=1)) top_suggestions = suggestions[np.prod(suggestions, axis=1) > sacrifice_level * best_resources] def best_criterion(suggestion): if use_omp: return -abs(suggestion[1] / suggestion[2] - mpi_omp_ratio) return (suggestion[0] * suggestion[1], -suggestion[0]) best_suggestion = max(top_suggestions, key=best_criterion) message = '' if float(best_suggestion[1] * best_suggestion[2]) / cpus_per_node < 0.6: message = ('WARNING: Changed the number of MPIs per node from {} to {} and OMP per MPI ' 'from {} to {}.' 'Changed the number of nodes from {} to {}. ' 'Computational setup, needed for a given number k-points ({})' ' provides less then 60% of node load.' ''.format(mpi_per_node, best_suggestion[1], omp_per_mpi, best_suggestion[2], nodes, best_suggestion[0], kpts)) raise ValueError(message) elif best_suggestion[1] * best_suggestion[2] == cpus_per_node: if best_suggestion[0] != nodes: message = ('WARNING: Changed the number of nodes from {} to {}' ''.format(nodes, best_suggestion[0])) else: message = ('Computational setup is perfect! Nodes: {}, MPIs per node {}, OMP per MPI ' '{}. Number of k-points is {}'.format(best_suggestion[0], best_suggestion[1], best_suggestion[2], kpts)) else: message = ('WARNING: Changed the number of MPIs per node from {} to {} and OMP from {} to {}' '. Changed the number of nodes from {} to {}. Number of k-points is {}.' ''.format(mpi_per_node, best_suggestion[1], omp_per_mpi, best_suggestion[2], nodes, best_suggestion[0], kpts)) return int(best_suggestion[0]), int(best_suggestion[1]), int(best_suggestion[2]), message
from sympy.ntheory.factor_ import divisors def is_pandigital_product(a, b, c): s = str(a) + str(b) + str(c) l = list(s) l.sort() return ''.join(l) == '123456789' panNums = set() for n in range(1234, 9876): divs = divisors(n) for d in divs[:len(divs) // 2]: if is_pandigital_product(d, n // d, n): print('{} * {} = {}'.format(d, n // d, n)) panNums.add(n) print(sum(panNums))