Beispiel #1
0
 def compute_selected_method(button):
     args = []
     for i in self.inputs.children:
         try:
             arg = i.value or i.placeholder
             evaled_arg = eval_in_main(arg)
             if not arg:
                 self.output.value = to_html("Argument '%s' is empty!" % i.description)
                 return
             args.append(evaled_arg)
         except:
             self.output.value = to_html("Could not evaluate argument '%s'" % i.description)
             return
     try:
         if AlarmInterrupt:
             alarm(TIMEOUT)
         out = self.selected_menu_value.member(obj, *args)
         if AlarmInterrupt:
             cancel_alarm()
     except AlarmInterrupt:
         self.output.value = to_html("Timeout!")
     except Exception as e:
         self.output.value = to_html(e)
         return
     self.output.value = to_html(out)
Beispiel #2
0
def report(F, title, systems=['sage', 'magma'], **kwds):
    """
    Run benchmarks with default arguments for each function in the list F.

    INPUT:

    - ``F`` - a list of callables used for benchmarking
    - ``title`` - a string describing this report
    - ``systems`` - a list of systems (supported entries are 'sage' and 'magma')
    - ``**kwds`` - keyword arguments passed to all functions in ``F``

    EXAMPLES::

        sage: import sage.matrix.benchmark as b
        sage: print("starting"); import sys; sys.stdout.flush(); b.report([b.det_ZZ], 'Test', systems=['sage'])
        starting...
        ======================================================================
                  Test
        ======================================================================
        ...
        ======================================================================
    """
    import os
    if len(systems) > 2:
        raise NotImplementedError("at most two systems ('sage' or 'magma')")
    print('=' * 70)
    print(' ' * 10 + title)
    print('=' * 70)
    os.system('uname -a')
    print('\n')
    for f in F:
        print("-" * 70)
        print(f.__doc__.strip())
        print(('%15s' * len(systems)) % tuple(systems))
        w = []
        for s in systems:
            alarm(timeout)
            try:
                t = f(system=s, **kwds)
            except AlarmInterrupt:
                t = -timeout
            cancel_alarm()
            w.append(float(t))
        if len(w) > 1:
            if w[1] == 0:
                w.append(0.0)
            else:
                w.append(w[0] / w[1])

        w = tuple(w)
        print(('%15.3f' * len(w)) % w)
    print('=' * 70)
Beispiel #3
0
def report(F, title, systems = ['sage', 'magma'], **kwds):
    """
    Run benchmarks with default arguments for each function in the list F.

    INPUT:

    - ``F`` - a list of callables used for benchmarking
    - ``title`` - a string describing this report
    - ``systems`` - a list of systems (supported entries are 'sage' and 'magma')
    - ``**kwds`` - keyword arguments passed to all functions in ``F``

    EXAMPLES::

        sage: import sage.matrix.benchmark as b
        sage: print "starting"; import sys; sys.stdout.flush(); b.report([b.det_ZZ], 'Test', systems=['sage'])
        starting...
        ======================================================================
                  Test
        ======================================================================
        ...
        ======================================================================
    """
    import os
    if len(systems) > 2:
        raise NotImplementedError("at most two systems ('sage' or 'magma')")
    print '='*70
    print ' '*10 + title
    print '='*70
    os.system('uname -a')
    print '\n'
    for f in F:
        print "-"*70
        print f.__doc__.strip()
        print ('%15s'*len(systems))%tuple(systems)
        w = []
        for s in systems:
            alarm(timeout)
            try:
                t = f(system=s, **kwds)
            except AlarmInterrupt:
                t = -timeout
            cancel_alarm()
            w.append(float(t))
        if len(w) > 1:
            if w[1] == 0:
                w.append(0.0)
            else:
                w.append(w[0]/w[1])

        w = tuple(w)
        print ('%15.3f'*len(w))%w
    print '='*70
Beispiel #4
0
def benchmark(pbound=[3, 2**10],
              nbound=[3, 2**8],
              cbound=[1, Infinity],
              obound=[1, Infinity],
              loops=10,
              tloop=Infinity,
              tmax=Infinity,
              prime=False,
              even=False,
              check=False,
              fname=None,
              write=False,
              overwrite=False,
              verbose=True,
              skip_pari=False,
              skip_magma=False,
              skip_rains=False,
              skip_kummer=False):
    if write:
        mode = 'w' if overwrite else 'a'
        f = open(fname, mode, 0)
    else:
        f = sys.stdout
    pmin, pmax = pbound
    nmin, nmax = nbound
    omin, omax = obound
    cmin, cmax = cbound
    M = Magma()
    for p in xrange(pmin, pmax):
        p = ZZ(p)
        if not p.is_prime():
            continue
        for n in xrange(nmin, nmax):
            n = ZZ(n)
            if (prime == 1 and not is_prime(n)) or (prime == 2
                                                    and not is_prime_power(n)):
                continue
            if n < 2:
                continue
            if n % p == 0:
                continue
            if (not even) and (n % 2 == 0):
                continue
            o, G = find_root_order(p, [n, n], n, verbose=False)
            m = G[0][0].parent().order()
            c = Mod(p, n).multiplicative_order()
            if verbose:
                sys.stdout.write("\r" + " " * 79)
                print("\rp = {}, n = {}, (o = {}, c = {})".format(p, n, o, c))
            if verbose:
                t = mytime()
                sys.stdout.write("Constructing fields ({})".format(
                    time.strftime("%c")))
                sys.stdout.flush()
            q = p**n
            k = GF(q, name='z')
            k_rand = GF(q, modulus='random', name='z')
            k_flint = GF_flint(p, k.modulus(), name='z')
            if verbose > 1:
                sys.stdout.write("\ntotal: {}s\n".format(mytime(t)))
                sys.stdout.flush()
            # Magma
            if verbose:
                sys.stdout.write("\r" + " " * 79)
                sys.stdout.write("\rMagma ({})".format(time.strftime("%c")))
                sys.stdout.flush()
            tloops = 0
            for l in xrange(loops):
                if skip_magma:
                    break
                if (o > omax) or (o == p):
                    break
                # let's assume that launching a new Magma instance is cheaper
                # than computing random irreducible polynomials
                try:
                    M._start()
                except OSError as err:
                    # but it can also cause fork issues...
                    # let's accept this
                    # and fail as the situation will only worsen
                    # unless it is "just" a memory issue
                    # which should be mitigated by COW but is not
                    #print(err)
                    if err.errno == errno.ENOMEM:
                        break
                    else:
                        raise
                try:
                    k_magma = M(k)
                    k_rand_magma = M(k_rand)
                    if tloop is not Infinity:
                        alarm(tloop)
                    t = mytime()
                    k_magma.Embed(k_rand_magma, nvals=0)
                    #M._eval_line("Embed(k_magma, k_rand_magma);", wait_for_prompt=False)
                    tloops += mytime(t)
                except TypeError:
                    # sage/magma interface sometimes gets confused
                    pass
                except (KeyboardInterrupt, AlarmInterrupt):
                    # sage interface eats KeyboardInterrupt
                    # and AlarmInterrupt derives from it
                    tloops = 0
                    break
                finally:
                    if tloop is not Infinity:
                        cancel_alarm()
                    M.quit()
                    # sage pexpect interface leaves zombies around
                    try:
                        while os.waitpid(-1, os.WNOHANG)[0]:
                            pass
                    # but sometimes every child is already buried
                    # and we get an ECHILD error...
                    except OSError:
                        pass
                if tloops > tmax:
                    break
            tmagma = tloops / (l + 1)
            if verbose > 1:
                sys.stdout.write("\ntotal: {}s, per loop: {}s\n".format(
                    tloops, tloops / (l + 1)))
                sys.stdout.flush()
            # Rains algorithms
            if verbose:
                sys.stdout.write("\r" + " " * 79)
                sys.stdout.write("\rCyclotomic Rains ({})".format(
                    time.strftime("%c")))
                sys.stdout.flush()
            trains = []
            tloops = 0
            for l in xrange(loops):
                if skip_rains:
                    break
                if (o > omax) or (o == p):
                    break
                try:
                    if tloop is not Infinity:
                        alarm(tloop)
                    t = mytime()
                    a, b = find_gens_cyclorains(k_flint,
                                                k_flint,
                                                use_lucas=False)
                    tloops += mytime(t)
                except (KeyboardInterrupt, AlarmInterrupt):
                    tloops = 0
                    break
                finally:
                    if tloop is not Infinity:
                        cancel_alarm()
                if check and (l == 0 or check > 1):
                    g = a.minpoly()
                    if g.degree() != n:
                        raise RuntimeError("wrong degree")
                    if g != b.minpoly():
                        raise RuntimeError("different minpolys")
                if tloops > tmax:
                    break
            trains.append(tloops / (l + 1))
            if verbose > 1:
                sys.stdout.write("\ntotal: {}s, per loop: {}s\n".format(
                    tloops, tloops / (l + 1)))
                sys.stdout.flush()
            # Conic Rains
            if verbose:
                sys.stdout.write("\r" + " " * 79)
                sys.stdout.write("\rConic Rains ({})".format(
                    time.strftime("%c")))
                sys.stdout.flush()
            tloops = 0
            for l in xrange(loops):
                if skip_rains:
                    break
                if (o != 2) or (o > omax) or (o == p):
                    break
                try:
                    if tloop is not Infinity:
                        alarm(tloop)
                    t = mytime()
                    a, b = find_gens_cyclorains(k_flint,
                                                k_flint,
                                                use_lucas=True)
                    tloops += mytime(t)
                except (KeyboardInterrupt, AlarmInterrupt):
                    tloops = 0
                    break
                finally:
                    if tloop is not Infinity:
                        cancel_alarm()
                if check and (l == 0 or check > 1):
                    g = a.minpoly()
                    if g.degree() != n:
                        raise RuntimeError("wrong degree")
                    if g != b.minpoly():
                        raise RuntimeError("different minpolys")
                if tloops > tmax:
                    break
            trains.append(tloops / (l + 1))
            if verbose > 1:
                sys.stdout.write("\ntotal: {}s, per loop: {}s\n".format(
                    tloops, tloops / (l + 1)))
                sys.stdout.flush()
            # Elliptic Rains
            if verbose:
                sys.stdout.write("\r" + " " * 79)
                sys.stdout.write("\rElliptic Rains ({})".format(
                    time.strftime("%c")))
                sys.stdout.flush()
            tloops = 0
            for l in xrange(loops):
                if skip_rains:
                    break
                try:
                    if tloop is not Infinity:
                        alarm(tloop)
                    t = mytime()
                    a, b = find_gens_ellrains(k_flint, k_flint)
                    tloops += mytime(t)
                except RuntimeError:
                    # sometimes no suitable elliptic curve exists
                    pass
                except (KeyboardInterrupt, AlarmInterrupt):
                    tloops = 0
                    break
                finally:
                    if tloop is not Infinity:
                        cancel_alarm()
                if check and (l == 0 or check > 1):
                    g = a.minpoly()
                    if g.degree() != n:
                        raise RuntimeError("wrong degree")
                    if g != b.minpoly():
                        raise RuntimeError("different minpolys")
                if tloops > tmax:
                    break
            trains.append(tloops / (l + 1))
            if verbose > 1:
                sys.stdout.write("\ntotal: {}s, per loop: {}s\n".format(
                    tloops, tloops / (l + 1)))
                sys.stdout.flush()
            # PARI/GP
            if verbose:
                sys.stdout.write("\r" + " " * 79)
                sys.stdout.write("\rPARI/GP ({})".format(time.strftime("%c")))
                sys.stdout.flush()
            tloops = 0
            for l in xrange(loops):
                if skip_pari:
                    break
                if c < cmin or c > cmax:
                    break
                try:
                    if tloop is not Infinity:
                        alarm(tloop)
                    t = mytime()
                    a, b = find_gens_pari(k, k)
                    tloops += mytime(t)
                except (KeyboardInterrupt, AlarmInterrupt):
                    tloops = 0
                    break
                finally:
                    if tloop is not Infinity:
                        cancel_alarm()
                if check and (l == 0 or check > 1):
                    g = a.minpoly()
                    if g.degree() != n:
                        raise RuntimeError("wrong degree")
                    if g != b.minpoly():
                        raise RuntimeError("different minpolys")
                if tloops > tmax:
                    break
            tpari = tloops / (l + 1)
            # Kummer algorithms
            tkummer = []
            # only linalg and modcomp implemented for c==1
            for i, algo in enumerate(kummer_algolist[2 * (c == 1):-2 *
                                                     (c == 1) - 1]):
                if verbose:
                    sys.stdout.write("\r" + " " * 79)
                    sys.stdout.write("\rKummer {} ({})".format(
                        kummer_namelist[2 * (c == 1) + i],
                        time.strftime("%c")))
                    sys.stdout.flush()
                tloops = 0
                for l in xrange(loops):
                    if skip_kummer:
                        break
                    if c < cmin or c > cmax:
                        break
                    try:
                        if tloop is not Infinity:
                            alarm(tloop)
                        t = mytime()
                        a, b = find_gens_kummer(k_flint, k_flint, n, algo)
                        tloops += mytime(t)
                    except (KeyboardInterrupt, AlarmInterrupt):
                        tloops = 0
                        break
                    finally:
                        if tloop is not Infinity:
                            cancel_alarm()
                    if check and (l == 0 or check > 1):
                        g = a.minpoly()
                        if g.degree() != n:
                            raise RuntimeError("wrong degree")
                        if g != b.minpoly():
                            raise RuntimeError("different minpolys")
                    if tloops > tmax:
                        break
                tkummer.append(tloops / (l + 1))
                if verbose > 1:
                    sys.stdout.write("\ntotal: {}s, per loop: {}s\n".format(
                        tloops, tloops / (l + 1)))
                    sys.stdout.flush()
            tkummer = 2 * (c == 1) * [0] + tkummer + 2 * (c == 1) * [0]
            if verbose:
                sys.stdout.write("\r")
                sys.stdout.flush()
            f.write(("{} {} ({}, {})" + " {}" + " {}" * len(trains) + " {}" +
                     " {}" * len(tkummer) + "\n").format(
                         p, n, o, c, *([tmagma] + trains + [tpari] + tkummer)))
    if write:
        f.close()
Beispiel #5
0
    def __call__(self, f, inputs):
        """
        Parallel iterator using ``fork()``.

        INPUT:

        - ``f`` -- a function (or more general, any callable)

        - ``inputs`` -- a list of pairs ``(args, kwds)`` to be used as
          arguments to ``f``, where ``args`` is a tuple and ``kwds`` is
          a dictionary.

        OUTPUT:

        EXAMPLES::

            sage: F = sage.parallel.use_fork.p_iter_fork(2,3)
            sage: sorted(list( F( (lambda x: x^2), [([10],{}), ([20],{})])))
            [(([10], {}), 100), (([20], {}), 400)]
            sage: sorted(list( F( (lambda x, y: x^2+y), [([10],{'y':1}), ([20],{'y':2})])))
            [(([10], {'y': 1}), 101), (([20], {'y': 2}), 402)]

        TESTS:

        The output of functions decorated with :func:`parallel` is read
        as a pickle by the parent process. We intentionally break the
        unpickling and demonstrate that this failure is handled
        gracefully (the exception is put in the list instead of the
        answer)::

            sage: Polygen = parallel(polygen)
            sage: list(Polygen([QQ]))
            [(((Rational Field,), {}), x)]
            sage: from sage.misc.persist import unpickle_override, register_unpickle_override
            sage: register_unpickle_override('sage.rings.polynomial.polynomial_rational_flint', 'Polynomial_rational_flint', Integer)
            sage: L = list(Polygen([QQ]))
            sage: L
            [(((Rational Field,), {}),
              'INVALID DATA __init__() takes at most 2 positional arguments (4 given)')]

        Fix the unpickling::

            sage: del unpickle_override[('sage.rings.polynomial.polynomial_rational_flint', 'Polynomial_rational_flint')]
            sage: list(Polygen([QQ,QQ]))
            [(((Rational Field,), {}), x), (((Rational Field,), {}), x)]
        """
        n = self.ncpus
        v = list(inputs)
        import os
        import sys
        import signal
        from sage.misc.persist import loads
        from sage.misc.temporary_file import tmp_dir
        dir = tmp_dir()
        timeout = self.timeout

        workers = {}
        try:
            while v or workers:
                # Spawn up to n subprocesses
                while v and len(workers) < n:
                    v0 = v.pop(0)  # Input value for the next subprocess
                    with ContainChildren():
                        pid = os.fork()
                        # The way fork works is that pid returns the
                        # nonzero pid of the subprocess for the master
                        # process and returns 0 for the subprocess.
                        if not pid:
                            # This is the subprocess.
                            self._subprocess(f, dir, *v0)

                    workers[pid] = WorkerData(v0)

                if len(workers) > 0:
                    # Now wait for one subprocess to finish and report the result.
                    # However, wait at most the time since the oldest process started.
                    T = walltime()
                    if timeout:
                        oldest = min(W.starttime for W in workers.values())
                        alarm(max(timeout - (T - oldest), 0.1))

                    try:
                        pid = os.wait()[0]
                        cancel_alarm()
                        W = workers.pop(pid)
                    except AlarmInterrupt:
                        # Kill workers that are too old
                        for pid, W in workers.items():
                            if T - W.starttime > timeout:
                                if self.verbose:
                                    print(
                                        "Killing subprocess %s with input %s which took too long"
                                        % (pid, W.input))
                                os.kill(pid, signal.SIGKILL)
                                W.failure = " (timed out)"
                    except KeyError:
                        # Some other process exited, not our problem...
                        pass
                    else:
                        # collect data from process that successfully terminated
                        sobj = os.path.join(dir, '%s.sobj' % pid)
                        try:
                            with open(sobj, "rb") as file:
                                data = file.read()
                        except IOError:
                            answer = "NO DATA" + W.failure
                        else:
                            os.unlink(sobj)
                            try:
                                answer = loads(data, compress=False)
                            except Exception as E:
                                answer = "INVALID DATA {}".format(E)

                        out = os.path.join(dir, '%s.out' % pid)
                        try:
                            with open(out) as file:
                                sys.stdout.write(file.read())
                            os.unlink(out)
                        except IOError:
                            pass

                        yield (W.input, answer)
        finally:
            # Send SIGKILL signal to workers that are left.
            if workers:
                if self.verbose:
                    print("Killing any remaining workers...")
                sys.stdout.flush()
                for pid in workers:
                    try:
                        os.kill(pid, signal.SIGKILL)
                    except OSError:
                        # If kill() failed, it is most likely because
                        # the process already exited.
                        pass
                    else:
                        try:
                            os.waitpid(pid, 0)
                        except OSError as msg:
                            if self.verbose:
                                print(msg)

            # Clean up all temporary files.
            rmtree(dir)
Beispiel #6
0
    def __call__(self, f, inputs):
        """
        Parallel iterator using ``fork()``.

        INPUT:

        - ``f`` -- a Python function that need not be pickleable or anything else!

        - ``inputs`` -- a list of pickleable pairs ``(args, kwds)``, where
          ``args`` is a tuple and ``kwds`` is a dictionary.

        OUTPUT:

        EXAMPLES::

            sage: F = sage.parallel.use_fork.p_iter_fork(2,3)
            sage: sorted(list( F( (lambda x: x^2), [([10],{}), ([20],{})])))
            [(([10], {}), 100), (([20], {}), 400)]
            sage: sorted(list( F( (lambda x, y: x^2+y), [([10],{'y':1}), ([20],{'y':2})])))
            [(([10], {'y': 1}), 101), (([20], {'y': 2}), 402)]

        TESTS:

        The output of functions decorated with :func:parallel is read
        as a pickle by the parent process. We intentionally break the
        unpickling and demonstrate that this failure is handled
        gracefully (an exception is displayed and an empty list is
        returned)::

            sage: Polygen = parallel(polygen)
            sage: list(Polygen([QQ]))
            [(((Rational Field,), {}), x)]
            sage: from sage.structure.sage_object import unpickle_override, register_unpickle_override
            sage: register_unpickle_override('sage.rings.polynomial.polynomial_rational_flint', 'Polynomial_rational_flint', Integer)
            sage: L = list(Polygen([QQ]))
            ('__init__() takes at most 2 positional arguments (4 given)', <type 'sage.rings.integer.Integer'>, (Univariate Polynomial Ring in x over Rational Field, [0, 1], False, True))
            sage: L
            []

        Fix the unpickling::

            sage: del unpickle_override[('sage.rings.polynomial.polynomial_rational_flint', 'Polynomial_rational_flint')]
            sage: list(Polygen([QQ,QQ]))
            [(((Rational Field,), {}), x), (((Rational Field,), {}), x)]
        """
        n = self.ncpus
        v = list(inputs)
        import os, sys, signal
        from sage.structure.sage_object import load
        from sage.misc.all import tmp_dir, walltime
        dir = tmp_dir()
        timeout = self.timeout

        workers = {}
        try:
            while len(v) > 0 or len(workers) > 0:
                # Spawn up to n subprocesses
                while len(v) > 0 and len(workers) < n:
                    # Subprocesses shouldn't inherit unflushed buffers (cf. #11778):
                    sys.stdout.flush()
                    sys.stderr.flush()

                    pid = os.fork()
                    # The way fork works is that pid returns the
                    # nonzero pid of the subprocess for the master
                    # process and returns 0 for the subprocess.
                    if pid:
                        # This is the parent master process.
                        workers[pid] = [v[0], walltime(), '']
                        del v[0]
                    else:
                        # This is the subprocess.
                        self._subprocess(f, dir, v[0])

                if len(workers) > 0:
                    # Now wait for one subprocess to finish and report the result.
                    # However, wait at most the time since the oldest process started.
                    if timeout:
                        oldest = min([X[1] for X in workers.values()])
                        alarm(max(timeout - (walltime()-oldest), 0.1))

                    try:
                        pid = os.wait()[0]
                        cancel_alarm()
                        w = workers.pop(pid)
                    except AlarmInterrupt:
                        cancel_alarm()
                        # Kill workers that are too old
                        for pid, X in workers.iteritems():
                            if walltime() - X[1] > timeout:
                                if self.verbose:
                                    print(
                                        "Killing subprocess %s with input %s which took too long"
                                         % (pid, X[0]) )
                                os.kill(pid, signal.SIGKILL)
                                X[-1] = ' (timed out)'
                    except KeyError:
                        # Some other process exited, not our problem...
                        pass
                    else:
                        # collect data from process that successfully terminated
                        sobj = os.path.join(dir, '%s.sobj'%pid)
                        if not os.path.exists(sobj):
                            X = "NO DATA" + w[-1]  # the message field
                        else:
                            X = load(sobj, compress=False)
                            os.unlink(sobj)
                        out = os.path.join(dir, '%s.out'%pid)
                        if not os.path.exists(out):
                            output = "NO OUTPUT"
                        else:
                            output = open(out).read()
                            os.unlink(out)

                        if output.strip():
                            print output,

                        yield (w[0], X)

        except Exception as msg:
            print msg

        finally:
            # Clean up all temporary files.
            try:
                for X in os.listdir(dir):
                    os.unlink(os.path.join(dir, X))
                os.rmdir(dir)
            except OSError as msg:
                if self.verbose:
                    print msg

            # Send "kill -9" signal to workers that are left.
            if len(workers) > 0:
                if self.verbose:
                    print "Killing any remaining workers..."
                sys.stdout.flush()
                for pid in workers.keys():
                    try:
                        os.kill(pid, signal.SIGKILL)
                        os.waitpid(pid, 0)
                    except OSError as msg:
                        if self.verbose:
                            print msg
Beispiel #7
0
    def __call__(self, f, inputs):
        """
        Parallel iterator using ``fork()``.

        INPUT:

        - ``f`` -- a Python function that need not be pickleable or anything else!

        - ``inputs`` -- a list of pickleable pairs ``(args, kwds)``, where
          ``args`` is a tuple and ``kwds`` is a dictionary.

        OUTPUT:

        EXAMPLES::

            sage: F = sage.parallel.use_fork.p_iter_fork(2,3)
            sage: sorted(list( F( (lambda x: x^2), [([10],{}), ([20],{})])))
            [(([10], {}), 100), (([20], {}), 400)]
            sage: sorted(list( F( (lambda x, y: x^2+y), [([10],{'y':1}), ([20],{'y':2})])))
            [(([10], {'y': 1}), 101), (([20], {'y': 2}), 402)]

        TESTS:

        The output of functions decorated with :func:parallel is read
        as a pickle by the parent process. We intentionally break the
        unpickling and demonstrate that this failure is handled
        gracefully (an exception is displayed and an empty list is
        returned)::

            sage: Polygen = parallel(polygen)
            sage: list(Polygen([QQ]))
            [(((Rational Field,), {}), x)]
            sage: from sage.structure.sage_object import unpickle_override, register_unpickle_override
            sage: register_unpickle_override('sage.rings.polynomial.polynomial_rational_flint', 'Polynomial_rational_flint', Integer)
            sage: L = list(Polygen([QQ]))
            ('__init__() takes at most 2 positional arguments (4 given)', <type 'sage.rings.integer.Integer'>, (Univariate Polynomial Ring in x over Rational Field, [0, 1], False, True))
            sage: L
            []

        Fix the unpickling::

            sage: del unpickle_override[('sage.rings.polynomial.polynomial_rational_flint', 'Polynomial_rational_flint')]
            sage: list(Polygen([QQ,QQ]))
            [(((Rational Field,), {}), x), (((Rational Field,), {}), x)]
        """
        n = self.ncpus
        v = list(inputs)
        import os, sys, signal
        from sage.structure.sage_object import load
        from sage.misc.all import tmp_dir, walltime
        dir = tmp_dir()
        timeout = self.timeout

        workers = {}
        try:
            while len(v) > 0 or len(workers) > 0:
                # Spawn up to n subprocesses
                while len(v) > 0 and len(workers) < n:
                    # Subprocesses shouldn't inherit unflushed buffers (cf. #11778):
                    sys.stdout.flush()
                    sys.stderr.flush()

                    pid = os.fork()
                    # The way fork works is that pid returns the
                    # nonzero pid of the subprocess for the master
                    # process and returns 0 for the subprocess.
                    if pid:
                        # This is the parent master process.
                        workers[pid] = [v[0], walltime(), '']
                        del v[0]
                    else:
                        # This is the subprocess.
                        self._subprocess(f, dir, v[0])

                if len(workers) > 0:
                    # Now wait for one subprocess to finish and report the result.
                    # However, wait at most the time since the oldest process started.
                    if timeout:
                        oldest = min([X[1] for X in workers.values()])
                        alarm(max(timeout - (walltime() - oldest), 0.1))

                    try:
                        pid = os.wait()[0]
                        cancel_alarm()
                        w = workers.pop(pid)
                    except AlarmInterrupt:
                        cancel_alarm()
                        # Kill workers that are too old
                        for pid, X in workers.iteritems():
                            if walltime() - X[1] > timeout:
                                if self.verbose:
                                    print(
                                        "Killing subprocess %s with input %s which took too long"
                                        % (pid, X[0]))
                                os.kill(pid, signal.SIGKILL)
                                X[-1] = ' (timed out)'
                    except KeyError:
                        # Some other process exited, not our problem...
                        pass
                    else:
                        # collect data from process that successfully terminated
                        sobj = os.path.join(dir, '%s.sobj' % pid)
                        if not os.path.exists(sobj):
                            X = "NO DATA" + w[-1]  # the message field
                        else:
                            X = load(sobj, compress=False)
                            os.unlink(sobj)
                        out = os.path.join(dir, '%s.out' % pid)
                        if not os.path.exists(out):
                            output = "NO OUTPUT"
                        else:
                            output = open(out).read()
                            os.unlink(out)

                        if output.strip():
                            print output,

                        yield (w[0], X)

        except Exception as msg:
            print msg

        finally:
            # Clean up all temporary files.
            try:
                for X in os.listdir(dir):
                    os.unlink(os.path.join(dir, X))
                os.rmdir(dir)
            except OSError as msg:
                if self.verbose:
                    print msg

            # Send "kill -9" signal to workers that are left.
            if len(workers) > 0:
                if self.verbose:
                    print "Killing any remaining workers..."
                sys.stdout.flush()
                for pid in workers.keys():
                    try:
                        os.kill(pid, signal.SIGKILL)
                        os.waitpid(pid, 0)
                    except OSError as msg:
                        if self.verbose:
                            print msg
Beispiel #8
0
    def __call__(self, f, inputs):
        """
        Parallel iterator using ``fork()``.

        INPUT:

        - ``f`` -- a function (or more general, any callable)

        - ``inputs`` -- a list of pairs ``(args, kwds)`` to be used as
          arguments to ``f``, where ``args`` is a tuple and ``kwds`` is
          a dictionary.

        OUTPUT:

        EXAMPLES::

            sage: F = sage.parallel.use_fork.p_iter_fork(2,3)
            sage: sorted(list( F( (lambda x: x^2), [([10],{}), ([20],{})])))
            [(([10], {}), 100), (([20], {}), 400)]
            sage: sorted(list( F( (lambda x, y: x^2+y), [([10],{'y':1}), ([20],{'y':2})])))
            [(([10], {'y': 1}), 101), (([20], {'y': 2}), 402)]

        TESTS:

        The output of functions decorated with :func:`parallel` is read
        as a pickle by the parent process. We intentionally break the
        unpickling and demonstrate that this failure is handled
        gracefully (the exception is put in the list instead of the
        answer)::

            sage: Polygen = parallel(polygen)
            sage: list(Polygen([QQ]))
            [(((Rational Field,), {}), x)]
            sage: from sage.structure.sage_object import unpickle_override, register_unpickle_override
            sage: register_unpickle_override('sage.rings.polynomial.polynomial_rational_flint', 'Polynomial_rational_flint', Integer)
            sage: L = list(Polygen([QQ]))
            sage: L
            [(((Rational Field,), {}),
              'INVALID DATA __init__() takes at most 2 positional arguments (4 given)')]

        Fix the unpickling::

            sage: del unpickle_override[('sage.rings.polynomial.polynomial_rational_flint', 'Polynomial_rational_flint')]
            sage: list(Polygen([QQ,QQ]))
            [(((Rational Field,), {}), x), (((Rational Field,), {}), x)]
        """
        n = self.ncpus
        v = list(inputs)
        import os, sys, signal
        from sage.structure.sage_object import loads
        from sage.misc.temporary_file import tmp_dir
        dir = tmp_dir()
        timeout = self.timeout

        workers = {}
        try:
            while len(v) > 0 or len(workers) > 0:
                # Spawn up to n subprocesses
                while len(v) > 0 and len(workers) < n:
                    v0 = v.pop(0)  # Input value for the next subprocess
                    with ContainChildren():
                        pid = os.fork()
                        # The way fork works is that pid returns the
                        # nonzero pid of the subprocess for the master
                        # process and returns 0 for the subprocess.
                        if not pid:
                            # This is the subprocess.
                            self._subprocess(f, dir, *v0)

                    workers[pid] = WorkerData(v0)

                if len(workers) > 0:
                    # Now wait for one subprocess to finish and report the result.
                    # However, wait at most the time since the oldest process started.
                    T = walltime()
                    if timeout:
                        oldest = min(W.starttime for W in workers.values())
                        alarm(max(timeout - (T - oldest), 0.1))

                    try:
                        pid = os.wait()[0]
                        cancel_alarm()
                        W = workers.pop(pid)
                    except AlarmInterrupt:
                        # Kill workers that are too old
                        for pid, W in workers.items():
                            if T - W.starttime > timeout:
                                if self.verbose:
                                    print(
                                        "Killing subprocess %s with input %s which took too long"
                                         % (pid, W.input) )
                                os.kill(pid, signal.SIGKILL)
                                W.failure = " (timed out)"
                    except KeyError:
                        # Some other process exited, not our problem...
                        pass
                    else:
                        # collect data from process that successfully terminated
                        sobj = os.path.join(dir, '%s.sobj'%pid)
                        try:
                            with open(sobj) as file:
                                data = file.read()
                        except IOError:
                            answer = "NO DATA" + W.failure
                        else:
                            os.unlink(sobj)
                            try:
                                answer = loads(data, compress=False)
                            except Exception as E:
                                answer = "INVALID DATA {}".format(E)

                        out = os.path.join(dir, '%s.out'%pid)
                        try:
                            with open(out) as file:
                                sys.stdout.write(file.read())
                            os.unlink(out)
                        except IOError:
                            pass

                        yield (W.input, answer)
        finally:
            # Send SIGKILL signal to workers that are left.
            if workers:
                if self.verbose:
                    print("Killing any remaining workers...")
                sys.stdout.flush()
                for pid in workers:
                    try:
                        os.kill(pid, signal.SIGKILL)
                    except OSError:
                        # If kill() failed, it is most likely because
                        # the process already exited.
                        pass
                    else:
                        try:
                            os.waitpid(pid, 0)
                        except OSError as msg:
                            if self.verbose:
                                print(msg)

            # Clean up all temporary files.
            rmtree(dir)
Beispiel #9
0
def benchmark(pbound = [3, 2**10], nbound = [3, 2**8], cbound = [1, Infinity], obound = [1, Infinity], loops = 10, tloop = Infinity, tmax = Infinity, prime = False, even = False, check = False, fname = None, write = False, overwrite = False, verbose = True, skip_pari = False, skip_magma = False, skip_rains = False, skip_kummer = False):
    if write:
        mode = 'w' if overwrite else 'a'
        f = open(fname, mode, 0)
    else:
        f = sys.stdout
    pmin, pmax = pbound
    nmin, nmax = nbound
    omin, omax = obound
    cmin, cmax = cbound
    M = Magma()
    for p in xrange(pmin, pmax):
        p = ZZ(p)
        if not p.is_prime():
            continue
        for n in xrange(nmin, nmax):
            n = ZZ(n)
            if (prime == 1 and not is_prime(n)) or (prime == 2 and not is_prime_power(n)):
                continue
            if n < 2:
                continue
            if n % p == 0:
                continue
            if (not even) and (n % 2 == 0):
                continue
            o, G = find_root_order(p, [n, n], n, verbose=False)
            m = G[0][0].parent().order()
            c = Mod(p,n).multiplicative_order()
            if verbose:
                sys.stdout.write("\r"+" "*79)
                print("\rp = {}, n = {}, (o = {}, c = {})".format(p, n, o, c))
            if verbose:
                t = mytime()
                sys.stdout.write("Constructing fields ({})".format(time.strftime("%c")))
                sys.stdout.flush()
            q = p**n
            k = GF(q, name='z')
            k_rand = GF(q, modulus='random', name='z')
            k_flint = GF_flint(p, k.modulus(), name='z')
            if verbose > 1:
                sys.stdout.write("\ntotal: {}s\n".format(mytime(t)))
                sys.stdout.flush()
            # Magma
            if verbose:
                sys.stdout.write("\r"+" "*79)
                sys.stdout.write("\rMagma ({})".format(time.strftime("%c")))
                sys.stdout.flush()
            tloops = 0
            for l in xrange(loops):
                if skip_magma:
                    break
                if (o > omax) or (o == p):
                    break
                # let's assume that launching a new Magma instance is cheaper
                # than computing random irreducible polynomials
                try:
                    M._start()
                except OSError as err:
                    # but it can also cause fork issues...
                    # let's accept this
                    # and fail as the situation will only worsen
                    # unless it is "just" a memory issue
                    # which should be mitigated by COW but is not
                    #print(err)
                    if err.errno == errno.ENOMEM:
                        break
                    else:
                        raise
                try:
                    k_magma = M(k)
                    k_rand_magma = M(k_rand)
                    if tloop is not Infinity:
                        alarm(tloop)
                    t = mytime()
                    k_magma.Embed(k_rand_magma, nvals=0)
                    #M._eval_line("Embed(k_magma, k_rand_magma);", wait_for_prompt=False)
                    tloops += mytime(t)
                except TypeError:
                    # sage/magma interface sometimes gets confused
                    pass
                except (KeyboardInterrupt, AlarmInterrupt):
                    # sage interface eats KeyboardInterrupt
                    # and AlarmInterrupt derives from it
                    tloops = 0
                    break
                finally:
                    if tloop is not Infinity:
                        cancel_alarm()
                    M.quit()
                    # sage pexpect interface leaves zombies around
                    try:
                        while os.waitpid(-1, os.WNOHANG)[0]:
                            pass
                    # but sometimes every child is already buried
                    # and we get an ECHILD error...
                    except OSError:
                        pass
                if tloops > tmax:
                    break
            tmagma = tloops / (l+1)
            if verbose > 1:
                sys.stdout.write("\ntotal: {}s, per loop: {}s\n".format(tloops, tloops/(l+1)))
                sys.stdout.flush()
            # Rains algorithms
            if verbose:
                sys.stdout.write("\r"+" "*79)
                sys.stdout.write("\rCyclotomic Rains ({})".format(time.strftime("%c")))
                sys.stdout.flush()
            trains = []
            tloops = 0
            for l in xrange(loops):
                if skip_rains:
                    break
                if (o > omax) or (o == p):
                    break
                try:
                    if tloop is not Infinity:
                        alarm(tloop)
                    t = mytime()
                    a, b = find_gens_cyclorains(k_flint, k_flint, use_lucas = False)
                    tloops += mytime(t)
                except (KeyboardInterrupt, AlarmInterrupt):
                    tloops = 0
                    break
                finally:
                    if tloop is not Infinity:
                        cancel_alarm()
                if check and (l == 0 or check > 1):
                    g = a.minpoly()
                    if g.degree() != n:
                        raise RuntimeError("wrong degree")
                    if g != b.minpoly():
                        raise RuntimeError("different minpolys")
                if tloops > tmax:
                    break
            trains.append(tloops / (l+1))
            if verbose > 1:
                sys.stdout.write("\ntotal: {}s, per loop: {}s\n".format(tloops, tloops/(l+1)))
                sys.stdout.flush()
            # Conic Rains
            if verbose:
                sys.stdout.write("\r"+" "*79)
                sys.stdout.write("\rConic Rains ({})".format(time.strftime("%c")))
                sys.stdout.flush()
            tloops = 0
            for l in xrange(loops):
                if skip_rains:
                    break
                if (o != 2) or (o > omax) or (o == p):
                    break
                try:
                    if tloop is not Infinity:
                        alarm(tloop)
                    t = mytime()
                    a, b = find_gens_cyclorains(k_flint, k_flint, use_lucas = True)
                    tloops += mytime(t)
                except (KeyboardInterrupt, AlarmInterrupt):
                    tloops = 0
                    break
                finally:
                    if tloop is not Infinity:
                        cancel_alarm()
                if check and (l == 0 or check > 1):
                    g = a.minpoly()
                    if g.degree() != n:
                        raise RuntimeError("wrong degree")
                    if g != b.minpoly():
                        raise RuntimeError("different minpolys")
                if tloops > tmax:
                    break
            trains.append(tloops / (l+1))
            if verbose > 1:
                sys.stdout.write("\ntotal: {}s, per loop: {}s\n".format(tloops, tloops/(l+1)))
                sys.stdout.flush()
            # Elliptic Rains
            if verbose:
                sys.stdout.write("\r"+" "*79)
                sys.stdout.write("\rElliptic Rains ({})".format(time.strftime("%c")))
                sys.stdout.flush()
            tloops = 0
            for l in xrange(loops):
                if skip_rains:
                    break
                try:
                    if tloop is not Infinity:
                        alarm(tloop)
                    t = mytime()
                    a, b = find_gens_ellrains(k_flint, k_flint)
                    tloops += mytime(t)
                except RuntimeError:
                    # sometimes no suitable elliptic curve exists
                    pass
                except (KeyboardInterrupt, AlarmInterrupt):
                    tloops = 0
                    break
                finally:
                    if tloop is not Infinity:
                        cancel_alarm()
                if check and (l == 0 or check > 1):
                    g = a.minpoly()
                    if g.degree() != n:
                        raise RuntimeError("wrong degree")
                    if g != b.minpoly():
                        raise RuntimeError("different minpolys")
                if tloops > tmax:
                    break
            trains.append(tloops / (l+1))
            if verbose > 1:
                sys.stdout.write("\ntotal: {}s, per loop: {}s\n".format(tloops, tloops/(l+1)))
                sys.stdout.flush()
            # PARI/GP
            if verbose:
                sys.stdout.write("\r"+" "*79)
                sys.stdout.write("\rPARI/GP ({})".format(time.strftime("%c")))
                sys.stdout.flush()
            tloops = 0
            for l in xrange(loops):
                if skip_pari:
                    break
                if c < cmin or c > cmax:
                    break
                try:
                    if tloop is not Infinity:
                        alarm(tloop)
                    t = mytime()
                    a, b = find_gens_pari(k, k)
                    tloops += mytime(t)
                except (KeyboardInterrupt, AlarmInterrupt):
                    tloops = 0
                    break
                finally:
                    if tloop is not Infinity:
                        cancel_alarm()
                if check and (l == 0 or check > 1):
                    g = a.minpoly()
                    if g.degree() != n:
                        raise RuntimeError("wrong degree")
                    if g != b.minpoly():
                        raise RuntimeError("different minpolys")
                if tloops > tmax:
                    break
            tpari = tloops / (l+1)
            # Kummer algorithms
            tkummer = []
            # only linalg and modcomp implemented for c==1
            for i, algo in enumerate(kummer_algolist[2*(c==1):-2*(c==1)-1]):
                if verbose:
                    sys.stdout.write("\r"+" "*79)
                    sys.stdout.write("\rKummer {} ({})".format(kummer_namelist[2*(c==1)+i], time.strftime("%c")))
                    sys.stdout.flush()
                tloops = 0
                for l in xrange(loops):
                    if skip_kummer:
                        break
                    if c < cmin or c > cmax:
                        break
                    try:
                        if tloop is not Infinity:
                            alarm(tloop)
                        t = mytime()
                        a, b = find_gens_kummer(k_flint, k_flint, n, algo)
                        tloops += mytime(t)
                    except (KeyboardInterrupt, AlarmInterrupt):
                        tloops = 0
                        break
                    finally:
                        if tloop is not Infinity:
                            cancel_alarm()
                    if check and (l == 0 or check > 1):
                        g = a.minpoly()
                        if g.degree() != n:
                            raise RuntimeError("wrong degree")
                        if g != b.minpoly():
                            raise RuntimeError("different minpolys")
                    if tloops > tmax:
                        break
                tkummer.append(tloops / (l+1))
                if verbose > 1:
                    sys.stdout.write("\ntotal: {}s, per loop: {}s\n".format(tloops, tloops/(l+1)))
                    sys.stdout.flush()
            tkummer = 2*(c == 1)*[0] + tkummer + 2*(c == 1)*[0]
            if verbose:
                sys.stdout.write("\r")
                sys.stdout.flush()
            f.write(("{} {} ({}, {})" + " {}" + " {}"*len(trains) + " {}" + " {}"*len(tkummer)+"\n").format(p, n, o, c, *([tmagma] + trains + [tpari] + tkummer)))
    if write:
        f.close()