def _test_polymake_pickling(self, tester=None, other=None, **options): """ Run tests to see that our polymake pickling/unpickling works. INPUT: - ``other`` -- a pickling polytope of ``self`` to be tested against TESTS:: sage: polytopes.cross_polytope(3, backend='polymake')._test_polymake_pickling() # optional - polymake """ if tester is None: tester = self._tester(**options) if other is None: from sage.misc.persist import loads, dumps other = loads(dumps(self)) tester.assertEqual(self, other) if not hasattr(self, '_polymake_polytope'): tester.assertFalse(hasattr(other, '_polymake_polytope')) return P = self._polymake_polytope P1 = other._polymake_polytope tester.assertEqual(P.F_VECTOR, P1.F_VECTOR) tester.assertEqual(P.VERTICES, P1.VERTICES) tester.assertEqual(P.LINEALITY_SPACE, P1.LINEALITY_SPACE) tester.assertEqual(P.FACETS, P1.FACETS) tester.assertEqual(P.AFFINE_HULL, P1.AFFINE_HULL)
def load_element(self, str): """ Create element from its string representation. The default implementation uses 'loads' and is very inefficient. """ import base64 return loads(base64.b64decode(str))
def __init__(self, algebra, gens, subalgebra, unstable, bbox, facade): self._algebra = algebra self._unstable = unstable self._amil = algebra.an_element().change_basis("milnor").parent() self._subalg = subalgebra self._prime = self._algebra.characteristic() self._emask = 0 self._trunc = bbox self._rmask = [] if facade is None: print("WARNING: you should supply a reasonable facade") facade = self if subalgebra is not None: assert subalgebra._truncation_type == 0 # FIXME if not algebra.is_generic(): e, r = (), subalgebra._profile else: r, e = subalgebra._profile msk = 1 for i in e: if 2 == i: self._emask = self._emask | msk msk = msk << 1 self._rmask = r self._gens = gens if hasattr(gens, "dump_element"): self._dumpfuncs = gens.dump_element, gens.load_element else: import base64 from sage.misc.persist import dumps, loads self._dumpfuncs = lambda x: base64.b64encode(dumps( x)), lambda x: loads(base64.b64decode(x)) if self.is_finite(): cat = FiniteEnumeratedSets() if not self._algebra.is_generic(): emax = 0 else: assert self._algebra._has_nontrivial_profile() rp, ep = self._profile emax = len(k for k in ep if k == 2) self._algbox = region(tmin=0, tmax=self._algebra.top_class().degree(), emin=0, emax=emax, s=0) else: cat = InfiniteEnumeratedSets() self._algbox = region(tmin=0, emin=0, s=0) Parent.__init__(self, facade=facade, category=(cat, YacopGradedSets()))
def _test_pickling(self, **options): """ Checks that the instance in self can be pickled and unpickled properly. EXAMPLES:: sage: from sage.misc.sage_unittest import PythonObjectWithTests sage: PythonObjectWithTests(int(1))._test_pickling() .. SEEALSO:: :func:`dumps`, :func:`loads` """ tester = instance_tester(self, **options) from sage.misc.persist import loads, dumps tester.assertEqual(loads(dumps(self._instance)), self._instance)
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)