示例#1
0
    def show(self, delay=20, iterations=0):
        r"""
        Show this animation.

        INPUT:

        -  ``delay`` - (default: 20) delay in hundredths of a
           second between frames

        -  ``iterations`` - integer (default: 0); number of
           iterations of animation. If 0, loop forever.

        .. note::

           Currently this is done using an animated gif, though this
           could change in the future. This requires that either
           ffmpeg or the ImageMagick suite (in particular, the
           ``convert`` command) is installed.

        See also the :meth:`ffmpeg` method.

        EXAMPLES::

            sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)],
            ...                xmin=0, xmax=2*pi, figsize=[2,1])
            sage: a.show()       # optional -- ImageMagick

        The preceding will loop the animation forever. If you want to show
        only three iterations instead::

            sage: a.show(iterations=3)    # optional -- ImageMagick

        To put a half-second delay between frames::

            sage: a.show(delay=50)        # optional -- ImageMagick

        .. note::

           If you don't have ffmpeg or ImageMagick installed, you will
           get an error message like this::

              Error: Neither ImageMagick nor ffmpeg appears to be installed. Saving an
              animation to a GIF file or displaying an animation requires one of these
              packages, so please install one of them and try again.

              See www.imagemagick.org and www.ffmpeg.org for more information.
        """
        if plot.DOCTEST_MODE:
            filename = tmp_filename(ext=".gif")
            self.gif(savefile=filename, delay=delay, iterations=iterations)
            return

        if plot.EMBEDDED_MODE:
            self.gif(delay=delay, iterations=iterations)
        else:
            filename = tmp_filename(ext=".gif")
            self.gif(delay=delay, savefile=filename, iterations=iterations)
            os.system("%s %s 2>/dev/null 1>/dev/null &" % (sage.misc.viewer.browser(), filename))
示例#2
0
文件: lrs.py 项目: sagemath/sage
    def is_functional(self):
        r"""
        Test whether ``lrs`` works on a trivial input.

        EXAMPLES::

            sage: from sage.features.lrs import Lrs
            sage: Lrs().is_functional()  # optional: lrslib
            FeatureTestResult('lrslib', True)
        """
        from sage.misc.temporary_file import tmp_filename
        tf_name = tmp_filename()
        with open(tf_name, 'wb') as tf:
            tf.write("V-representation\nbegin\n 1 1 rational\n 1 \nend\nvolume")
        devnull = open(os.devnull, 'wb')
        command = ['lrs', tf_name]
        try:
            lines = subprocess.check_output(command, stderr=devnull)
        except subprocess.CalledProcessError as e:
            return FeatureTestResult(self, False,
                reason = "Call to `{command}` failed with exit code {e.returncode}.".format(command=" ".join(command), e=e))

        expected = "Volume= 1"
        if lines.find(expected) == -1:
            return FeatureTestResult(self, False,
                reason = "Output of `{command}` did not contain the expected result `{expected}`.".format(command=" ".join(command),expected=expected))

        return FeatureTestResult(self, True)
def lrs_redund(in_str, verbose=False):
    r"""
    To remove redundant inequalities from an H-representation or
    input points that are not vertices from a V-representation
    use the command 'redund' from lrslib.

    Input: lrs format in_str; Output: lrs format out_str;

    Copy and edit from ``def _volume_lrs(self, verbose=False)``,
    http://www.sagenb.org/src/geometry/polyhedron/base.py
    """
    #if is_package_installed('lrslib') != True:
    #    print 'You must install the optional lrs package ' \
    #          'for this function to work'
    #    raise NotImplementedError

    in_filename = tmp_filename()
    in_file = open(in_filename,'w')
    in_file.write(in_str)
    in_file.close()
    if verbose: print(in_str)
    redund_procs = Popen(['redund',in_filename],stdin = PIPE, stdout=PIPE, stderr=PIPE)
    out_str, err = redund_procs.communicate()
    if verbose:
        print(out_str)
    return out_str
示例#4
0
def graphics_from_save(save_function, preferred_mime_types, 
                       allowed_mime_types=None, figsize=None, dpi=None):
    """
    Helper function to construct a graphics file.

    INPUT:
    
    - ``save_function`` -- callable that can save graphics to a file
      and accepts options like
      :meth:`sage.plot.graphics.Graphics.save``.

    - ``preferred_mime_types`` -- list of mime types. The graphics
      output mime types in order of preference (i.e. best quality to
      worst).

    - ``allowed_mime_types`` -- set of mime types (as strings). The
      graphics types that we can display. Output, if any, will be one
      of those.

    - ``figsize`` -- pair of integers (optional). The desired graphics
      size in pixels. Suggested, but need not be respected by the
      output.

    - ``dpi`` -- integer (optional). The desired resolution in dots
      per inch. Suggested, but need not be respected by the output.

    OUTPUT:

    Return an instance of
    :class:`sage.structure.graphics_file.GraphicsFile` encapsulating a
    suitable image file. Image is one of the
    ``preferred_mime_types``. If ``allowed_mime_types`` is specified,
    the resulting file format matches one of these.

    Alternatively, this function can return ``None`` to indicate that
    textual representation is preferable and/or no graphics with the
    desired mime type can be generated.
    """
    # Figure out best mime type
    mime = None
    if allowed_mime_types is None:
        mime = Mime.PNG
    else:
        # order of preference
        for m in preferred_mime_types:
            if m in allowed_mime_types:
                mime = m
                break
    if mime is None:
        return None    # don't know how to generate suitable graphics
    # Generate suitable temp file
    filename = tmp_filename(ext=os.path.extsep + Mime.extension(mime))
    # Call the save_function with the right arguments
    kwds = {}
    if figsize is not None:
        kwds['figsize'] = figsize
    if dpi is not None:
        kwds['dpi'] = dpi
    save_function(filename, **kwds)
    return GraphicsFile(filename, mime)
示例#5
0
文件: csdp.py 项目: sagemath/sage
    def is_functional(self):
        r"""
        Check whether ``theta`` works on a trivial example.

        EXAMPLES::

            sage: from sage.features.csdp import CSDP
            sage: CSDP().is_functional()  # optional: csdp
            FeatureTestResult('CSDP', True)
        """
        from sage.misc.temporary_file import tmp_filename
        tf_name = tmp_filename()
        with open(tf_name, 'wb') as tf:
            tf.write("2\n1\n1 1")
        devnull = open(os.devnull, 'wb')
        command = ['theta', tf_name]
        try:
            lines = subprocess.check_output(command, stderr=devnull)
        except subprocess.CalledProcessError as e:
            return FeatureTestResult(self, False,
                reason = "Call to `{command}` failed with exit code {e.returncode}.".format(command=" ".join(command), e=e))

        result = lines.strip().split('\n')[-1]
        match = re.match("^The Lovasz Theta Number is (.*)$", result)
        if match is None:
            return FeatureTestResult(self, False,
                reason = "Last line of the output of `{command}` did not have the expected format.".format(command=" ".join(command)))

        return FeatureTestResult(self, True)
示例#6
0
 def _launch_jmol(self):
     launch_script = tmp_filename(ext='.spt')
     with open(launch_script, 'w') as f:
         f.write('set defaultdirectory "{0}"\n'.format(self.filename()))
         f.write('script SCRIPT\n')
     from sage.env import SAGE_LOCAL
     JMOL = os.path.join(SAGE_LOCAL, 'bin', 'jmol')
     os.system('{0} {1} 2>/dev/null 1>/dev/null &'
               .format(JMOL, launch_script))
示例#7
0
    def _launch_jmol(self):
        launch_script = tmp_filename(ext=".spt")
        with open(launch_script, "w") as f:
            f.write('set defaultdirectory "{0}"\n'.format(self.filename()))
            f.write("script SCRIPT\n")
        from sage.env import SAGE_LOCAL

        JMOL = os.path.join(SAGE_LOCAL, "bin", "jmol")
        os.system("{0} {1} 2>/dev/null 1>/dev/null &".format(JMOL, launch_script))
示例#8
0
 def file_name(self, val=None):
     """
     Show or set self.settings['file_name']
     """
     if val is not None:
         self.settings['file_name'] = val
     try:
         return self.settings['file_name']
     except KeyError:
         return self.file_name(tmp_filename(ext=self.image_format()))
示例#9
0
文件: buffer.py 项目: mcognetta/sage
    def filename(self, ext=None):
        """
        Return the filename.

        INPUT:

        - ``ext`` -- string. The file extension.

        OUTPUT:

        Name of a file, most likely a temporary file. If ``ext`` is
        specified, the filename will have that extension.

        You must not modify the returned file. Its permissions are set
        to readonly to help with that.

        EXAMPLES::

            sage: from sage.repl.rich_output.buffer import OutputBuffer
            sage: buf = OutputBuffer('test')
            sage: buf.filename()           # random output
            '/home/user/.sage/temp/hostname/26085/tmp_RNSfAc'

            sage: os.path.isfile(buf.filename())
            True
            sage: buf.filename(ext='txt')  # random output
            '/home/user/.sage/temp/hostname/26085/tmp_Rjjp4V.txt'
            sage: buf.filename(ext='txt').endswith('.txt')
            True
        """
        if ext is None:
            ext = ''
        elif not ext.startswith('.'):
            ext = '.' + ext

        if self._filename is None or not self._filename.endswith(ext):
            from sage.misc.temporary_file import tmp_filename
            output = tmp_filename(ext=ext)
        else:
            output = self._filename

        if self._filename is None:
            assert self._data is not None
            with open(output, 'wb') as f:
                f.write(self._data)
            self._filename = output
        elif self._filename != output:
            try:
                os.link(self._filename, output)
            except (OSError, AttributeError):
                import shutil
                shutil.copy2(self._filename, output)

        self._chmod_readonly(output)
        return output
示例#10
0
文件: tachyon.py 项目: bukzor/sage
    def __call__(self, model, outfile='sage.png',
                 verbose=1, block=True, extra_opts=''):
        """
        This executes the tachyon program, given a scene file input.
        The default is to return the result as a PNG file called 'sage.png'.

        TESTS::

            sage: from sage.interfaces.tachyon import TachyonRT
            sage: tgen = Tachyon()
            sage: tgen.texture('t1')
            sage: tgen.sphere((0,0,0),1,'t1')
            sage: tgen.str()[30:40]
            'resolution'
            sage: t = TachyonRT()
            sage: import os
            sage: t(tgen.str(), outfile = os.devnull)
            tachyon ...
            Tachyon Parallel/Multiprocessor Ray Tracer...
        """
        modelfile = tmp_filename(ext='.dat')
        open(modelfile,'w').write(model)
        opts = ''
        ext = outfile[-4:].lower()
        if ext == '.png':
            opts += ' -format PNG '
        elif ext == '.tga':
            opts += ' -format TARGA '
        elif ext == '.bmp':
            opts += ' -format BMP '
        elif ext == '.ppm':
            opts += ' -format PPM '
        elif ext == '.rgb':
            opts += ' -format RGB '

        opts += ' -o %s '%outfile

        opts += ' ' + extra_opts + ' '

        if verbose >= 2:
            opts += ' +V '
        elif verbose == 0:
            opts += '  1>/dev/null'

        cmd = 'tachyon %s %s; rm -f "%s"'%(modelfile,opts, modelfile)

        if not block:
            cmd = '( ' + cmd + ' ) &'

        if verbose:
            print cmd
        # One should always flush before system()
        sys.stdout.flush()
        sys.stderr.flush()
        os.system(cmd)
示例#11
0
def preparse_file_named(name):
    r"""
    Preparse file named \code{name} (presumably a .sage file), outputting to a
    temporary file.  Returns name of temporary file.
    """
    from sage.misc.temporary_file import tmp_filename
    tmpfilename = tmp_filename(os.path.basename(name)) + '.py'
    out = open(tmpfilename, 'w')
    preparse_file_named_to_stream(name, out)
    out.close()
    return tmpfilename
示例#12
0
    def tex(self, filename=None, include_header=True):
        """
        Writes the latex code to a file.

        INPUT:

        - ``filename`` -- string (default:``None``), the output filename.
          If ``None``, it saves the file in a temporary directory.
        - ``include_header`` -- bool (default:``True``) whether to include
          the header latex part. If ``False``, it prints only the
          tikzpicture part to the file.

        OUTPUT:

            string, path to tex file

        EXAMPLES::

            sage: from slabbe import TikzPicture
            sage: V = [[1,0,1],[1,0,0],[1,1,0],[0,0,-1],[0,1,0],[-1,0,0],[0,1,1],[0,0,1],[0,-1,0]]
            sage: P = Polyhedron(vertices=V).polar()
            sage: s = P.projection().tikz([674,108,-731],112)
            sage: t = TikzPicture(s)
            sage: _ = t.tex()

        Write only the tikzpicture without header and begin/end document::

            sage: _ = t.tex(include_header=False)

        Write to a given filename::

            sage: from sage.misc.temporary_file import tmp_filename
            sage: filename = tmp_filename('temp','.tex')
            sage: _ = t.tex(filename)

        """
        if filename is None:
            filename = tmp_filename('tikz_','.tex')
        else:
            filename = os.path.abspath(filename)

        if include_header:
            output = str(self)
        else:
            output = self.tikz_picture_code()

        with open(filename, 'w') as f:
            f.write(output)

        return filename
示例#13
0
def runsnake(command):
    """
    Graphical profiling with ``runsnake``

    INPUT:

    - ``command`` -- the command to be run as a string.

    EXAMPLES::

        sage: runsnake("list(SymmetricGroup(3))")        # optional - runsnake

    ``command`` is first preparsed (see :func:`preparse`)::

        sage: runsnake('for x in range(1,4): print(x^2)') # optional - runsnake
        1
        4
        9

    :func:`runsnake` requires the program ``runsnake``. Due to non
    trivial dependencies (python-wxgtk, ...), installing it within the
    Sage distribution is unpractical. Hence, we recommend installing
    it with the system wide Python. On Ubuntu 10.10, this can be done
    with::

        > sudo apt-get install python-profiler python-wxgtk2.8 python-setuptools
        > sudo easy_install RunSnakeRun

    See the ``runsnake`` website for instructions for other platforms.

    :func:`runsnake` further assumes that the system wide Python is
    installed in ``/usr/bin/python``.

    .. seealso::

        - `The runsnake website <http://www.vrplumber.com/programming/runsnakerun/>`_
        - ``%prun``
        - :class:`Profiler`

    """
    import cProfile
    import os
    from sage.misc.temporary_file import tmp_filename
    from sage.misc.misc import get_main_globals
    from sage.repl.preparse import preparse
    tmpfile = tmp_filename()
    cProfile.runctx(preparse(command.lstrip().rstrip()), get_main_globals(), locals(), filename=tmpfile)
    os.system("/usr/bin/python -E `which runsnake` %s &" % tmpfile)
def lcdd_rational(in_str, verbose=False):
    r"""
    Use the command ``lcdd_gmp`` from cddlib.

    Input: cdd format in_str; Output: cdd format out_str;
    """
    in_filename = tmp_filename()
    in_file = open(in_filename,'w')
    in_file.write(in_str)
    in_file.close()
    if verbose: 
        print(in_str)
    redund_procs = Popen(['lcdd_gmp',in_filename],stdin = PIPE, stdout=PIPE, stderr=PIPE)
    out_str, err = redund_procs.communicate()
    if verbose:
        print(out_str)
    return out_str
示例#15
0
文件: test.py 项目: Babyll/sage
def test_write_to_file():
    """
    Test that libgap can write to files

    See :trac:`16502`, :trac:`15833`.

    EXAMPLES::

        sage: from sage.libs.gap.test import test_write_to_file
        sage: test_write_to_file()
    """
    fname = tmp_filename()
    message = "Ceci n'est pas une groupe"
    libgap.PrintTo(fname, message)
    with open(fname, 'r') as f:
        assert f.read() == message
    SystemFile = libgap.function_factory('StringFile')
    assert SystemFile(fname).sage() == message
def lrs_lrs(in_str, verbose=False):
    r"""
    Use the command 'lrs' from lrslib.
    Input: lrs format in_str; Output: lrs format out_str;
    """
    #if is_package_installed('lrslib') != True:
    #    print 'You must install the optional lrs package ' \
    #          'for this function to work'
    #    raise NotImplementedError
    in_filename = tmp_filename()
    in_file = open(in_filename,'w')
    in_file.write(in_str)
    in_file.close()
    if verbose: print(in_str)

    redund_procs = Popen(['lrs',in_filename],stdin = PIPE, stdout=PIPE, stderr=PIPE)
    out_str, err = redund_procs.communicate()
    if verbose:
        print(out_str)
    return out_str
示例#17
0
    def __init__(self, filename=None):
        """
        Interface to the gperftools profiler

        INPUT:

        - ``filename`` -- string or ``None`` (default). The file name
          to log to. By default, a new temporary file is created.

        EXAMPLES::

            sage: from sage.misc.gperftools import Profiler
            sage: Profiler()
            Profiler logging to ...
        """
        if filename is None:
            from sage.misc.temporary_file import tmp_filename
            self._filename = tmp_filename(ext='.perf')
        else:
            self._filename = filename
示例#18
0
def get_remote_file(filename, verbose=True):
    """
    INPUT:

    - ``filename`` -- the URL of a file on the web, e.g.,
      ``"http://modular.math.washington.edu/myfile.txt"``

    - ``verbose`` -- whether to display download status

    OUTPUT:

    creates a file in the temp directory and returns the absolute path
    to that file.

    EXAMPLES::

        sage: g = get_remote_file("http://sagemath.org/ack.html", verbose=False)   # optional - internet
        sage: len(open(g).read())   # optional - internet; random
        10198
    """
    if verbose:
        print("Attempting to load remote file: " + filename)

    from sage.misc.temporary_file import tmp_filename
    temp_name = tmp_filename() + '.' + os.path.splitext(filename)[1][1:]
    # IMPORTANT -- urllib takes a long time to load,
    # so do not import it in the module scope.

    # import compatible with py2 and py3
    from six.moves.urllib.request import urlretrieve

    global cur
    cur = 0
    if verbose:
        sys.stdout.write("Loading: [")
        sys.stdout.flush()
        urlretrieve(filename, temp_name, report_hook)
        print("]")
    else:
        urlretrieve(filename, temp_name)
    return temp_name
示例#19
0
文件: cython.py 项目: bukzor/sage
def compile_and_load(code):
    r"""
    INPUT:

    - ``code`` -- string containing code that could be in a .pyx file
      that is attached or put in a %cython block in the notebook.

    OUTPUT: a module, which results from compiling the given code and
    importing it

    EXAMPLES::

        sage: module = sage.misc.cython.compile_and_load("def f(int n):\n    return n*n")
        sage: module.f(10)
        100
    """
    from sage.misc.temporary_file import tmp_filename
    file = tmp_filename(ext=".pyx")
    open(file,'w').write(code)
    from sage.server.support import cython_import
    return cython_import(file, create_local_c_file=False)
示例#20
0
文件: external.py 项目: Babyll/sage
def has_latex():
    """
    Test if Latex is available.

    EXAMPLES::

        sage: from sage.doctest.external import has_latex
        sage: has_latex() # random
        True
    """
    from sage.misc.latex import _run_latex_, _latex_file_
    from sage.misc.temporary_file import tmp_filename
    try:
        f = tmp_filename(ext='.tex')
        O = open(f, 'w') 
        O.write(_latex_file_('2+3'))
        O.close() 
        _run_latex_(f) 
        return True
    except Exception:
        return False
示例#21
0
文件: misc.py 项目: Babyll/sage
def tmp_filename():
    """
    Return a temporary file.

    OUTPUT:

    String. The absolute filename of the temporary file.

    EXAMPLES::

        sage: from sage.dev.misc import tmp_filename
        sage: tmp_filename().startswith(str(SAGE_TMP))
        True
    """
    try:
        from sage.misc.temporary_file import tmp_filename
        return tmp_filename()
    except ImportError:
        from tempfile import NamedTemporaryFile
        f = NamedTemporaryFile(dir=get_sage_tmp())
        f.close()
        return f.name
示例#22
0
文件: __init__.py 项目: sagemath/sage
    def _is_present(self):
        r"""
        Run test code to determine whether the shared library is present.

        EXAMPLES::

            sage: from sage.features import CythonFeature
            sage: empty = CythonFeature("empty", test_code="")
            sage: empty.is_present()
            FeatureTestResult('empty', True)
        """
        from sage.misc.temporary_file import tmp_filename
        with open(tmp_filename(ext=".pyx"), 'w') as pyx:
            pyx.write(self.test_code)
        from sage.misc.cython import cython_import
        try:
            cython_import(pyx.name, verbose=-1)
        except CCompilerError:
            return FeatureTestResult(self, False, reason="Failed to compile test code.")
        except ImportError:
            return FeatureTestResult(self, False, reason="Failed to import test code.")
        except Exception:
            return FeatureTestResult(self, False, reason="Failed to run test code.")
        return FeatureTestResult(self, True, reason="Test code compiled and imported.")
示例#23
0
文件: tachyon.py 项目: wdv4758h/sage
    def __call__(self, model, outfile='sage.png', verbose=1, extra_opts=''):
        """
        This executes the tachyon program, given a scene file input.

        INPUT:

        - ``model`` -- string. The tachyon model.

        - ``outfile`` -- string, default ``'sage.png'``. The filename
          to save the model to.

        - ``verbose`` -- 0, 1, (default) or 2. The verbosity level.

        - ``extra_opts`` -- string (default: empty string). Extra
          options that will be appended to the tachyon commandline.

        EXAMPLES::

            sage: from sage.interfaces.tachyon import TachyonRT
            sage: tgen = Tachyon()
            sage: tgen.texture('t1')
            sage: tgen.sphere((0,0,0),1,'t1')
            sage: tgen.str()[30:40]
            'resolution'
            sage: t = TachyonRT()
            sage: import os
            sage: t(tgen.str(), outfile=os.devnull)
            tachyon ...
            Tachyon Parallel/Multiprocessor Ray Tracer...

        TESTS::

            sage: from sage.env import SAGE_EXTCODE
            sage: filename = os.path.join(SAGE_EXTCODE, 'doctest', 'invalid', 'syntax_error.tachyon')
            sage: syntax_error = open(filename, 'r').read()
            sage: t(syntax_error, outfile=os.devnull)
            Traceback (most recent call last):
            ...
            RuntimeError: Tachyon Parallel/Multiprocessor Ray Tracer...
            ...
            Parser failed due to an input file syntax error.
            Aborting render.
        """
        modelfile = tmp_filename(ext='.dat')
        open(modelfile, 'w').write(model)
        cmd = ['tachyon', modelfile]
        ext = outfile[-4:].lower()
        if ext == '.png':
            cmd += ['-format', 'PNG']
        elif ext == '.tga':
            cmd += ['-format', 'TARGA']
        elif ext == '.bmp':
            cmd += ['-format', 'BMP']
        elif ext == '.ppm':
            cmd += ['-format', 'PPM']
        elif ext == '.rgb':
            cmd += ['-format', 'RGB']
        cmd += ['-o', outfile]
        cmd += extra_opts.split()
        if verbose >= 2:
            cmd += ['+V']
        if verbose:
            print(' '.join(cmd))
        import subprocess
        out = subprocess.check_output(cmd)
        if verbose >= 1:
            print(out)
        if out.rstrip().endswith('Aborting render.'):
            raise RuntimeError(out)
        if outfile != os.devnull and os.stat(outfile).st_size == 0:
            raise RuntimeError(
                'tachyon did not abort but output file is empty')
示例#24
0
 def _launch_jmol(self):
     launch_script = tmp_filename(ext='.spt')
     with open(launch_script, 'w') as f:
         f.write('set defaultdirectory "{0}"\n'.format(self.filename()))
         f.write('script SCRIPT\n')
     os.system('jmol {0} 2>/dev/null 1>/dev/null &'.format(launch_script))
示例#25
0
def gen_html_code(G,
                  vertex_labels=False,
                  edge_labels=False,
                  vertex_partition=[],
                  edge_partition=[],
                  force_spring_layout=False,
                  charge=-120,
                  link_distance=30,
                  link_strength=2,
                  gravity=.04,
                  vertex_size=7,
                  edge_thickness=4):
    r"""
    Creates a .html file showing the graph using `d3.js <http://d3js.org/>`_.

    This function returns the name of the .html file. If you want to
    visualize the actual graph use
    :meth:`~sage.graphs.generic_graph.GenericGraph.show`.

    INPUT:

    - ``G`` -- the graph

    - ``vertex_labels`` (boolean) -- Whether to display vertex labels (set to
      ``False`` by default).

    - ``edge_labels`` (boolean) -- Whether to display edge labels (set to
      ``False`` by default).

    - ``vertex_partition`` -- a list of lists representing a partition of the
      vertex set. Vertices are then colored in the graph according to the
      partition. Set to ``[]`` by default.

    - ``edge_partition`` -- same as ``vertex_partition``, with edges
      instead. Set to ``[]`` by default.

    - ``force_spring_layout`` -- whether to take sage's position into account if
      there is one (see :meth:`~sage.graphs.generic_graph.GenericGraph.` and
      :meth:`~sage.graphs.generic_graph.GenericGraph.`), or to compute a spring
      layout. Set to ``False`` by default.

    - ``vertex_size`` -- The size of a vertex' circle. Set to `7` by default.

    - ``edge_thickness`` -- Thickness of an edge. Set to ``4`` by default.

    - ``charge`` -- the vertices' charge. Defines how they repulse each
      other. See `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more
      information. Set to ``-120`` by default.

    - ``link_distance`` -- See
      `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more
      information. Set to ``30`` by default.

    - ``link_strength`` -- See
      `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more
      information. Set to ``2`` by default.

    - ``gravity`` -- See
      `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more
      information. Set to ``0.04`` by default.

    EXAMPLES::

        sage: graphs.RandomTree(50).show(method="js") # optional -- internet

        sage: g = graphs.PetersenGraph()
        sage: g.show(method = "js", vertex_partition=g.coloring()) # optional -- internet

        sage: graphs.DodecahedralGraph().show(method="js", force_spring_layout=True) # optional -- internet

        sage: graphs.DodecahedralGraph().show(method="js") # optional -- internet

        sage: g = digraphs.DeBruijn(2,2)
        sage: g.allow_multiple_edges(True)
        sage: g.add_edge("10","10","a")
        sage: g.add_edge("10","10","b")
        sage: g.add_edge("10","10","c")
        sage: g.add_edge("10","10","d")
        sage: g.add_edge("01","11","1")
        sage: g.show(method="js", vertex_labels=True,edge_labels=True,
        ....:        link_distance=200,gravity=.05,charge=-500,
        ....:        edge_partition=[[("11","12","2"),("21","21","a")]],
        ....:        edge_thickness=4) # optional -- internet

    TESTS::

        sage: from sage.graphs.graph_plot_js import gen_html_code
        sage: filename = gen_html_code(graphs.PetersenGraph())
    """
    directed = G.is_directed()
    multiple_edges = G.has_multiple_edges()

    # Associated an integer to each vertex
    v_to_id = {v: i for i, v in enumerate(G.vertices())}

    # Vertex colors
    color = {i: len(vertex_partition) for i in range(G.order())}
    for i, l in enumerate(vertex_partition):
        for v in l:
            color[v_to_id[v]] = i

    # Vertex list
    nodes = []
    for v in G.vertices():
        nodes.append({"name": str(v), "group": str(color[v_to_id[v]])})

    # Edge colors.
    edge_color_default = "#aaa"
    color_list = rainbow(len(edge_partition))
    edge_color = {}
    for i, l in enumerate(edge_partition):
        for e in l:
            u, v, label = e if len(e) == 3 else e+(None,)
            edge_color[u, v, label] = color_list[i]
            if not directed:
                edge_color[v, u, label] = color_list[i]

    # Edge list
    edges = []
    seen = {}  # How many times has this edge been seen ?

    for u, v, l in G.edges():

        # Edge color
        color = edge_color.get((u, v, l), edge_color_default)

        # Computes the curve of the edge
        curve = 0

        # Loop ?
        if u == v:
            seen[u, v] = seen.get((u, v), 0)+1
            curve = seen[u, v]*10+10

        # For directed graphs, one also has to take into accounts
        # edges in the opposite direction
        elif directed:
            if G.has_edge(v, u):
                seen[u, v] = seen.get((u, v), 0)+1
                curve = seen[u, v]*15
            else:
                if multiple_edges and len(G.edge_label(u, v)) != 1:
                    # Multiple edges. The first one has curve 15, then
                    # -15, then 30, then -30, ...
                    seen[u, v] = seen.get((u, v), 0) + 1
                    curve = (1 if seen[u, v] % 2 else -1)*(seen[u, v]//2)*15

        elif not directed and multiple_edges:
            # Same formula as above for multiple edges
            if len(G.edge_label(u, v)) != 1:
                seen[u, v] = seen.get((u, v), 0) + 1
                curve = (1 if seen[u, v] % 2 else -1)*(seen[u, v]//2)*15

        # Adding the edge to the list
        edges.append({"source": v_to_id[u],
                      "target": v_to_id[v],
                      "strength": 0,
                      "color": color,
                      "curve": curve,
                      "name": str(l) if edge_labels else ""})

    loops = [e for e in edges if e["source"] == e["target"]]
    edges = [e for e in edges if e["source"] != e["target"]]

    # Defines the vertices' layout if possible
    Gpos = G.get_pos()
    pos = []
    if Gpos is not None and force_spring_layout is False:
        charge = 0
        link_strength = 0
        gravity = 0

        for v in G.vertices():
            x, y = Gpos[v]
            pos.append([x, -y])

    # Encodes the data as a JSON string
    from json import JSONEncoder
    string = JSONEncoder().encode({"nodes": nodes,
                                   "links": edges, "loops": loops, "pos": pos,
                                   "directed": G.is_directed(),
                                   "charge": int(charge),
                                   "link_distance": int(link_distance),
                                   "link_strength": int(link_strength),
                                   "gravity": float(gravity),
                                   "vertex_labels": bool(vertex_labels),
                                   "edge_labels": bool(edge_labels),
                                   "vertex_size": int(vertex_size),
                                   "edge_thickness": int(edge_thickness)})

    from sage.env import SAGE_EXTCODE
    js_code_file = open(SAGE_EXTCODE+"/graphs/graph_plot_js.html", 'r')
    js_code = js_code_file.read().replace("// HEREEEEEEEEEEE", string)
    js_code_file.close()

    # Writes the temporary .html file
    filename = tmp_filename(ext='.html')
    f = open(filename, 'w')
    f.write(js_code)
    f.close()

    return filename
示例#26
0
def lovasz_theta(graph):
    r"""
    Return the value of Lovász theta-function of graph

    For a graph `G` this function is denoted by `\theta(G)`, and it can be
    computed in polynomial time. Mathematically, its most important property is the following:

    .. MATH::

        \alpha(G)\leq\theta(G)\leq\chi(\overline{G})

    with `\alpha(G)` and `\chi(\overline{G})` being, respectively, the maximum
    size of an :meth:`independent set <sage.graphs.graph.Graph.independent_set>`
    set of `G` and the :meth:`chromatic number
    <sage.graphs.graph.Graph.chromatic_number>` of the :meth:`complement
    <sage.graphs.generic_graph.GenericGraph.complement>` `\overline{G}` of `G`.

    For more information, see the :wikipedia:`Lovász_number`.

    .. NOTE::

        - Implemented for undirected graphs only. Use to_undirected to convert a
          digraph to an undirected graph.

        - This function requires the optional package ``csdp``, which you can
          install with with ``sage -i csdp``.

    EXAMPLES::

          sage: C=graphs.PetersenGraph()
          sage: C.lovasz_theta()                             # optional csdp
          4.0
          sage: graphs.CycleGraph(5).lovasz_theta()          # optional csdp
          2.236068

    TEST::

        sage: g = Graph()
        sage: g.lovasz_theta() # indirect doctest
        0
    """
    n = graph.order()
    if n == 0:
        return 0

    from networkx import write_edgelist
    from sage.misc.temporary_file import tmp_filename
    import os, subprocess
    from sage.env import SAGE_LOCAL
    from sage.misc.package import is_package_installed, PackageNotFoundError

    if not is_package_installed('csdp'):
        raise PackageNotFoundError("csdp")

    g = graph.relabel(inplace=False, perm=range(1,n+1)).networkx_graph()
    tf_name = tmp_filename()
    tf = open(tf_name, 'wb')
    tf.write(str(n)+'\n'+str(g.number_of_edges())+'\n')
    write_edgelist(g, tf, data=False)
    tf.close()
    lines = subprocess.check_output([os.path.join(SAGE_LOCAL, 'bin', 'theta'), tf_name])
    return float(lines.split()[-1])
示例#27
0
    def graphics_from_save(self,
                           save_function,
                           save_kwds,
                           file_extension,
                           output_container,
                           figsize=None,
                           dpi=None):
        r"""
        Helper to construct graphics.

        This method can be used to simplify the implementation of a
        ``_rich_repr_`` method of a graphics object if there is
        already a function to save graphics to a file.

        INPUT:

        - ``save_function`` -- callable that can save graphics to a file
          and accepts options like
          :meth:`sage.plot.graphics.Graphics.save`.

        - ``save_kwds`` -- dictionary. Keyword arguments that are
          passed to the save function.

        - ``file_extension`` -- string starting with ``'.'``. The file
          extension of the graphics file.

        - ``output_container`` -- subclass of
          :class:`sage.repl.rich_output.output_basic.OutputBase`. The
          output container to use. Must be one of the types in
          :meth:`supported_output`.

        - ``figsize`` -- pair of integers (optional). The desired graphics
          size in pixels. Suggested, but need not be respected by the
          output.

        - ``dpi`` -- integer (optional). The desired resolution in dots
          per inch. Suggested, but need not be respected by the output.

        OUTPUT:

        Return an instance of ``output_container``.

        EXAMPLES::

            sage: from sage.repl.rich_output import get_display_manager
            sage: dm = get_display_manager()
            sage: plt = plot(sin)
            sage: out = dm.graphics_from_save(plt.save, dict(), '.png', dm.types.OutputImagePng)
            sage: out
            OutputImagePng container
            sage: out.png.get().startswith(b'\x89PNG')
            True
            sage: out.png.filename()   # random
            '/home/user/.sage/temp/localhost.localdomain/23903/tmp_pu5woK.png'
        """
        import os
        if not file_extension.startswith(os.path.extsep):
            raise ValueError('file_extension must start with a period')
        if output_container not in self.supported_output():
            raise OutputTypeException(
                'output_container is not supported by backend')
        from sage.misc.temporary_file import tmp_filename
        filename = tmp_filename(ext=file_extension)
        # Call the save_function with the right arguments
        kwds = dict(save_kwds)
        if figsize is not None:
            kwds['figsize'] = figsize
        if dpi is not None:
            kwds['dpi'] = dpi
        save_function(filename, **kwds)
        from sage.repl.rich_output.buffer import OutputBuffer
        buf = OutputBuffer.from_file(filename)
        return output_container(buf)
示例#28
0
    def ffmpeg(self, savefile=None, show_path=False, output_format=None,
               ffmpeg_options='', delay=None, iterations=0, pix_fmt='rgb24'):
        r"""
        Returns a movie showing an animation composed from rendering
        the frames in self.

        This method will only work if ffmpeg is installed.  See
        http://www.ffmpeg.org for information about ffmpeg.

        INPUT:

        -  ``savefile`` - file that the mpeg gets saved to.

        .. warning:

            This will overwrite ``savefile`` if it already exists.

        - ``show_path`` - boolean (default: False); if True, print the
          path to the saved file

        - ``output_format`` - string (default: None); format and
          suffix to use for the video.  This may be 'mpg', 'mpeg',
          'avi', 'gif', or any other format that ffmpeg can handle.
          If this is None and the user specifies ``savefile`` with a
          suffix, say ``savefile='animation.avi'``, try to determine the
          format ('avi' in this case) from that file name.  If no file
          is specified or if the suffix cannot be determined, 'mpg' is
          used.

        - ``ffmpeg_options`` - string (default: ''); this string is
          passed directly to ffmpeg.

        - ``delay`` - integer (default: None); delay in hundredths of a
          second between frames.  The framerate is 100/delay.
          This is not supported for mpeg files: for mpegs, the frame
          rate is always 25 fps.

        - ``iterations`` - integer (default: 0); number of iterations
          of animation. If 0, loop forever.  This is only supported
          for animated gif output and requires ffmpeg version 0.9 or
          later.  For older versions, set ``iterations=None``.

        - ``pix_fmt`` - string (default: 'rgb24'); used only for gif
          output.  Different values such as 'rgb8' or 'pal8' may be
          necessary depending on how ffmpeg was installed.  Set
          ``pix_fmt=None`` to disable this option.

        If ``savefile`` is not specified: in notebook mode, display
        the animation; otherwise, save it to a default file name.  Use
        :func:`sage.misc.misc.set_verbose` with ``level=1`` to see
        additional output.

        EXAMPLES::

            sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)],
            ....:                xmin=0, xmax=2*pi, figsize=[2,1])
            sage: dir = tmp_dir()
            sage: a.ffmpeg(savefile=dir + 'new.mpg')       # optional -- ffmpeg
            sage: a.ffmpeg(savefile=dir + 'new.avi')       # optional -- ffmpeg
            sage: a.ffmpeg(savefile=dir + 'new.gif')       # optional -- ffmpeg
            sage: a.ffmpeg(savefile=dir + 'new.mpg', show_path=True) # optional -- ffmpeg
            Animation saved to .../new.mpg.

        .. note::

           If ffmpeg is not installed, you will get an error message
           like this::

              Error: ffmpeg does not appear to be installed. Saving an animation to
              a movie file in any format other than GIF requires this software, so
              please install it and try again.

              See www.ffmpeg.org for more information.


        TESTS::

            sage: a.ffmpeg(output_format='gif',delay=30,iterations=5)     # optional -- ffmpeg
        """
        if not self._have_ffmpeg():
            msg = """Error: ffmpeg does not appear to be installed. Saving an animation to
a movie file in any format other than GIF requires this software, so
please install it and try again."""
            raise OSError(msg)
        else:
            if savefile is None:
                if output_format is None:
                    output_format = '.mpg'
                else:
                    if output_format[0] != '.':
                        output_format = '.'+output_format
                savefile = tmp_filename(ext=output_format)
            else:
                if output_format is None:
                    suffix = os.path.splitext(savefile)[1]
                    if len(suffix) > 0:
                        output_format = suffix
                    else:
                        output_format = '.mpg'
            if not savefile.endswith(output_format):
                savefile += output_format
            early_options = ''
            if output_format == '.gif':
                # We try to set reasonable options for gif output.
                #
                # Older versions of ffmpeg (before 0.9, summer 2011)
                # use the option -loop_output instead of -loop.
                # Setting iterations=None is a way of preventing sage
                # from adding the -loop option.  A separate
                # -loop_output option can be added with the
                # ffmpeg_options argument.
                if iterations is not None:
                    loop_cmd = '-loop {0} '.format(iterations)
                else:
                    loop_cmd = ''
                # A pix_fmt value is required for some but not all
                # ffmpeg installations.  Setting pix_fmt=None will
                # prevent sage from adding this option, and it may be
                # controlled separately through ffmpeg_options.
                if pix_fmt is not None:
                    pix_fmt_cmd = '-pix_fmt {0} '.format(pix_fmt)
                else:
                    pix_fmt_cmd = ''
                ffmpeg_options += ' {0}{1}'.format(pix_fmt_cmd,loop_cmd)
            if delay is not None and output_format != '.mpeg' and output_format != '.mpg':
                early_options += ' -r %s ' % int(100/delay)
            savefile = os.path.abspath(savefile)
            pngdir = self.png()
            pngs = os.path.join(pngdir, "%08d.png")
            # For ffmpeg, it seems that some options, like '-g ... -r
            # ...', need to come before the input file names, while
            # some options, like '-pix_fmt rgb24', need to come
            # afterwards.  Hence 'early_options' and 'ffmpeg_options'
            cmd = 'cd "%s"; sage-native-execute ffmpeg -y -f image2 %s -i %s %s %s' % (pngdir, early_options, pngs, ffmpeg_options, savefile)
            from subprocess import check_call, CalledProcessError, PIPE
            try:
                if sage.misc.misc.get_verbose() > 0:
                    set_stderr = None
                else:
                    set_stderr = PIPE
                sage.misc.misc.verbose("Executing '%s'" % cmd,level=1)
                sage.misc.misc.verbose("\n---- ffmpeg output below ----\n")
                check_call(cmd, shell=True, stderr=set_stderr)
                if show_path:
                    print "Animation saved to file %s." % savefile
            except (CalledProcessError, OSError):
                print "Error running ffmpeg."
                raise
示例#29
0
def gen_html_code(G,
                  vertex_labels=False,
                  edge_labels=False,
                  vertex_partition=[],
                  edge_partition=[],
                  force_spring_layout=False,
                  charge=-120,
                  link_distance=30,
                  link_strength=2,
                  gravity=.04,
                  vertex_size=7,
                  edge_thickness=4):
    r"""
    Creates a .html file showing the graph using `d3.js <http://d3js.org/>`_.

    This function returns the name of the .html file. If you want to
    visualize the actual graph use
    :meth:`~sage.graphs.generic_graph.GenericGraph.show`.

    INPUT:

    - ``G`` -- the graph

    - ``vertex_labels`` (boolean) -- Whether to display vertex labels (set to
      ``False`` by default).

    - ``edge_labels`` (boolean) -- Whether to display edge labels (set to
      ``False`` by default).

    - ``vertex_partition`` -- a list of lists representing a partition of the
      vertex set. Vertices are then colored in the graph according to the
      partition. Set to ``[]`` by default.

    - ``edge_partition`` -- same as ``vertex_partition``, with edges
      instead. Set to ``[]`` by default.

    - ``force_spring_layout`` -- whether to take sage's position into account if
      there is one (see :meth:`~sage.graphs.generic_graph.GenericGraph.` and
      :meth:`~sage.graphs.generic_graph.GenericGraph.`), or to compute a spring
      layout. Set to ``False`` by default.

    - ``vertex_size`` -- The size of a vertex' circle. Set to `7` by default.

    - ``edge_thickness`` -- Thickness of an edge. Set to ``4`` by default.

    - ``charge`` -- the vertices' charge. Defines how they repulse each
      other. See `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more
      information. Set to ``-120`` by default.

    - ``link_distance`` -- See
      `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more
      information. Set to ``30`` by default.

    - ``link_strength`` -- See
      `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more
      information. Set to ``2`` by default.

    - ``gravity`` -- See
      `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more
      information. Set to ``0.04`` by default.

    EXAMPLES::

        sage: graphs.RandomTree(50).show(method="js") # optional -- internet

        sage: g = graphs.PetersenGraph()
        sage: g.show(method = "js", vertex_partition=g.coloring()) # optional -- internet

        sage: graphs.DodecahedralGraph().show(method="js", force_spring_layout=True) # optional -- internet

        sage: graphs.DodecahedralGraph().show(method="js") # optional -- internet

        sage: g = digraphs.DeBruijn(2,2)
        sage: g.allow_multiple_edges(True)
        sage: g.add_edge("10","10","a")
        sage: g.add_edge("10","10","b")
        sage: g.add_edge("10","10","c")
        sage: g.add_edge("10","10","d")
        sage: g.add_edge("01","11","1")
        sage: g.show(method="js", vertex_labels=True,edge_labels=True,
        ....:        link_distance=200,gravity=.05,charge=-500,
        ....:        edge_partition=[[("11","12","2"),("21","21","a")]],
        ....:        edge_thickness=4) # optional -- internet

    TESTS::

        sage: from sage.graphs.graph_plot_js import gen_html_code
        sage: filename = gen_html_code(graphs.PetersenGraph())
    """
    directed = G.is_directed()
    multiple_edges = G.has_multiple_edges()

    # Associated an integer to each vertex
    v_to_id = {v: i for i, v in enumerate(G.vertices())}

    # Vertex colors
    color = {i: len(vertex_partition) for i in range(G.order())}
    for i, l in enumerate(vertex_partition):
        for v in l:
            color[v_to_id[v]] = i

    # Vertex list
    nodes = []
    for v in G.vertices():
        nodes.append({"name": str(v), "group": str(color[v_to_id[v]])})

    # Edge colors.
    edge_color_default = "#aaa"
    color_list = rainbow(len(edge_partition))
    edge_color = {}
    for i, l in enumerate(edge_partition):
        for e in l:
            u, v, label = e if len(e) == 3 else e + (None, )
            edge_color[u, v, label] = color_list[i]
            if not directed:
                edge_color[v, u, label] = color_list[i]

    # Edge list
    edges = []
    seen = {}  # How many times has this edge been seen ?

    for u, v, l in G.edges():

        # Edge color
        color = edge_color.get((u, v, l), edge_color_default)

        # Computes the curve of the edge
        curve = 0

        # Loop ?
        if u == v:
            seen[u, v] = seen.get((u, v), 0) + 1
            curve = seen[u, v] * 10 + 10

        # For directed graphs, one also has to take into accounts
        # edges in the opposite direction
        elif directed:
            if G.has_edge(v, u):
                seen[u, v] = seen.get((u, v), 0) + 1
                curve = seen[u, v] * 15
            else:
                if multiple_edges and len(G.edge_label(u, v)) != 1:
                    # Multiple edges. The first one has curve 15, then
                    # -15, then 30, then -30, ...
                    seen[u, v] = seen.get((u, v), 0) + 1
                    curve = (1 if seen[u, v] % 2 else -1) * (seen[u, v] //
                                                             2) * 15

        elif not directed and multiple_edges:
            # Same formula as above for multiple edges
            if len(G.edge_label(u, v)) != 1:
                seen[u, v] = seen.get((u, v), 0) + 1
                curve = (1 if seen[u, v] % 2 else -1) * (seen[u, v] // 2) * 15

        # Adding the edge to the list
        edges.append({
            "source": v_to_id[u],
            "target": v_to_id[v],
            "strength": 0,
            "color": color,
            "curve": curve,
            "name": str(l) if edge_labels else ""
        })

    loops = [e for e in edges if e["source"] == e["target"]]
    edges = [e for e in edges if e["source"] != e["target"]]

    # Defines the vertices' layout if possible
    Gpos = G.get_pos()
    pos = []
    if Gpos is not None and force_spring_layout is False:
        charge = 0
        link_strength = 0
        gravity = 0

        for v in G.vertices():
            x, y = Gpos[v]
            pos.append([x, -y])

    # Encodes the data as a JSON string
    from json import JSONEncoder
    string = JSONEncoder().encode({
        "nodes": nodes,
        "links": edges,
        "loops": loops,
        "pos": pos,
        "directed": G.is_directed(),
        "charge": int(charge),
        "link_distance": int(link_distance),
        "link_strength": int(link_strength),
        "gravity": float(gravity),
        "vertex_labels": bool(vertex_labels),
        "edge_labels": bool(edge_labels),
        "vertex_size": int(vertex_size),
        "edge_thickness": int(edge_thickness)
    })

    from sage.env import SAGE_EXTCODE
    js_code_file = open(SAGE_EXTCODE + "/graphs/graph_plot_js.html", 'r')
    js_code = js_code_file.read().replace("// HEREEEEEEEEEEE", string)
    js_code_file.close()

    # Writes the temporary .html file
    filename = tmp_filename(ext='.html')
    f = open(filename, 'w')
    f.write(js_code)
    f.close()

    return filename
示例#30
0
def lovasz_theta(graph):
    r"""
    Return the value of Lovász theta-function of graph

    For a graph `G` this function is denoted by `\theta(G)`, and it can be
    computed in polynomial time. Mathematically, its most important property is the following:

    .. MATH::

        \alpha(G)\leq\theta(G)\leq\chi(\overline{G})

    with `\alpha(G)` and `\chi(\overline{G})` being, respectively, the maximum
    size of an :meth:`independent set <sage.graphs.graph.Graph.independent_set>`
    set of `G` and the :meth:`chromatic number
    <sage.graphs.graph.Graph.chromatic_number>` of the :meth:`complement
    <sage.graphs.generic_graph.GenericGraph.complement>` `\overline{G}` of `G`.

    For more information, see the :wikipedia:`Lovász_number`.

    .. NOTE::

        - Implemented for undirected graphs only. Use to_undirected to convert a
          digraph to an undirected graph.

        - This function requires the optional package ``csdp``, which you can
          install with with ``sage -i csdp``.

    EXAMPLES::

          sage: C=graphs.PetersenGraph()
          sage: C.lovasz_theta()                             # optional csdp
          4.0
          sage: graphs.CycleGraph(5).lovasz_theta()          # optional csdp
          2.236068

    TESTS::

        sage: g = Graph()
        sage: g.lovasz_theta() # indirect doctest
        0
    """
    n = graph.order()
    if n == 0:
        return 0

    from networkx import write_edgelist
    from sage.misc.temporary_file import tmp_filename
    import os, subprocess
    from sage.env import SAGE_LOCAL
    from sage.misc.package import is_package_installed, PackageNotFoundError

    if not is_package_installed('csdp'):
        raise PackageNotFoundError("csdp")

    g = graph.relabel(inplace=False, perm=range(1, n + 1)).networkx_graph()
    tf_name = tmp_filename()
    tf = open(tf_name, 'wb')
    tf.write(str(n) + '\n' + str(g.number_of_edges()) + '\n')
    write_edgelist(g, tf, data=False)
    tf.close()
    lines = subprocess.check_output(
        [os.path.join(SAGE_LOCAL, 'bin', 'theta'), tf_name])
    return float(lines.split()[-1])
示例#31
0
文件: latte.py 项目: mcognetta/sage
def integrate(arg, polynomial=None, algorithm='triangulate', raw_output=False, verbose=False, **kwds):
    r"""
    Call to the function integrate from LattE integrale.

    INPUT:

    - ``arg`` -- a cdd or LattE description string.

    - ``polynomial`` -- multivariate polynomial or valid LattE polynomial description string.
      If given, the valuation parameter of LattE is set to integrate, and is set to volume otherwise.

    - ``algorithm`` -- (default: 'triangulate') the integration method. Use 'triangulate' for
      polytope triangulation or 'cone-decompose' for tangent cone decomposition method.

    - ``raw_output`` -- if ``True`` then return directly the output string from LattE.

    - ``verbose`` -- if ``True`` then return directly verbose output from LattE.

    - For all other options of the integrate program, consult the LattE manual.

    OUTPUT:

    Either a string (if ``raw_output`` if set to ``True``) or a rational.

    EXAMPLES::

        sage: from sage.interfaces.latte import integrate
        sage: P = 2 * polytopes.cube()
        sage: x, y, z = polygen(QQ, 'x, y, z')

    Integrating over a polynomial over a polytope in either the H or V representation::

        sage: integrate(P.cdd_Hrepresentation(), x^2*y^2*z^2, cdd=True)   # optional - latte_int
        4096/27
        sage: integrate(P.cdd_Vrepresentation(), x^2*y^2*z^2, cdd=True)   # optional - latte_int
        4096/27

    Computing the volume of a polytope in either the H or V representation::

        sage: integrate(P.cdd_Hrepresentation(), cdd=True)   # optional - latte_int
        64
        sage: integrate(P.cdd_Vrepresentation(), cdd=True)   # optional - latte_int
        64

    Polynomials given as a string in LattE description are also accepted::

        sage: integrate(P.cdd_Hrepresentation(), '[[1,[2,2,2]]]', cdd=True)   # optional - latte_int
        4096/27

    TESTS::

    Testing raw output::

        sage: from sage.interfaces.latte import integrate
        sage: P = polytopes.cuboctahedron()
        sage: cddin = P.cdd_Vrepresentation()
        sage: x, y, z = polygen(QQ, 'x, y, z')
        sage: f = 3*x^2*y^4*z^6 + 7*y^3*z^5
        sage: integrate(cddin, f, cdd=True, raw_output=True)  # optional - latte_int
        '629/47775'

    Testing the ``verbose`` option to integrate over a polytope::

        sage: ans = integrate(cddin, f, cdd=True, verbose=True, raw_output=True)  # optional - latte_int
        This is LattE integrale ...
        ...
        Invocation: integrate --valuation=integrate --triangulate --redundancy-check=none --cdd --monomials=... /dev/stdin
        ...

    Testing triangulate algorithm::

        sage: from sage.interfaces.latte import integrate
        sage: P = polytopes.cuboctahedron()
        sage: cddin = P.cdd_Vrepresentation()
        sage: integrate(cddin, algorithm='triangulate', cdd=True)  # optional - latte_int
        20/3

    Testing convex decomposition algorithm::

        sage: from sage.interfaces.latte import integrate
        sage: P = polytopes.cuboctahedron()
        sage: cddin = P.cdd_Vrepresentation()
        sage: integrate(cddin, algorithm='cone-decompose', cdd=True)  # optional - latte_int
        20/3

    Testing raw output::

        sage: from sage.interfaces.latte import integrate
        sage: P = polytopes.cuboctahedron()
        sage: cddin = P.cdd_Vrepresentation()
        sage: integrate(cddin, cdd=True, raw_output=True)  # optional - latte_int
        '20/3'

    Testing polynomial given as a string in LattE description::

        sage: from sage.interfaces.latte import integrate
        sage: P = polytopes.cuboctahedron()
        sage: integrate(P.cdd_Hrepresentation(), '[[3,[2,4,6]],[7,[0, 3, 5]]]', cdd=True)   # optional - latte_int
        629/47775

    Testing the ``verbose`` option to compute the volume of a polytope::

        sage: from sage.interfaces.latte import integrate
        sage: P = polytopes.cuboctahedron()
        sage: cddin = P.cdd_Vrepresentation()
        sage: ans = integrate(cddin, cdd=True, raw_output=True, verbose=True)  # optional - latte_int
        This is LattE integrale ...
        ...
        Invocation: integrate --valuation=volume --triangulate --redundancy-check=none --cdd /dev/stdin
        ...
    """
    from subprocess import Popen, PIPE
    from sage.misc.misc import SAGE_TMP
    from sage.rings.integer import Integer

    args = ['integrate']

    got_polynomial = True if polynomial is not None else False

    if got_polynomial:
        args.append('--valuation=integrate')
    else:
        args.append('--valuation=volume')

    if algorithm=='triangulate':
        args.append('--triangulate')
    elif algorithm=='cone-decompose':
        args.append('--cone-decompose')

    if 'redundancy_check' not in kwds:
        args.append('--redundancy-check=none')

    for key,value in kwds.items():
        if value is None or value is False:
            continue

        key = key.replace('_','-')
        if value is True:
            args.append('--{}'.format(key))
        else:
            args.append('--{}={}'.format(key, value))

    if got_polynomial:
        if not isinstance(polynomial, six.string_types):
            # transform polynomial to LattE description
            monomials_list = to_latte_polynomial(polynomial)
        else:
            monomials_list = str(polynomial)

        from sage.misc.temporary_file import tmp_filename
        filename_polynomial = tmp_filename()

        with open(filename_polynomial, 'w') as f:
            f.write(monomials_list)
            args += ['--monomials=' + filename_polynomial]

    args += ['/dev/stdin']

    try:
        # The cwd argument is needed because latte
        # always produces diagnostic output files.
        latte_proc = Popen(args,
                           stdin=PIPE, stdout=PIPE,
                           stderr=(None if verbose else PIPE),
                           cwd=str(SAGE_TMP))
    except OSError:
        from sage.misc.package import PackageNotFoundError
        raise PackageNotFoundError('latte_int')

    ans, err = latte_proc.communicate(arg)
    ret_code = latte_proc.poll()
    if ret_code:
        if err is None:
            err = ", see error message above"
        else:
            err = ":\n" + err
        raise RuntimeError("LattE integrale program failed (exit code {})".format(ret_code) + err.strip())

    ans = ans.splitlines()
    ans = ans[-5].split()
    assert(ans[0]=='Answer:')
    ans = ans[1]

    if raw_output:
        return ans
    else:
        from sage.rings.rational import Rational
        return Rational(ans)
示例#32
0
    def show(self, delay=20, iterations=0):
        r"""
        Show this animation.

        INPUT:


        -  ``delay`` - (default: 20) delay in hundredths of a
           second between frames

        -  ``iterations`` - integer (default: 0); number of
           iterations of animation. If 0, loop forever.


        .. note::

           Currently this is done using an animated gif, though this
           could change in the future. This requires that either
           ffmpeg or the ImageMagick suite (in particular, the
           ``convert`` command) is installed.

        See also the :meth:`ffmpeg` method.

        EXAMPLES::

            sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)],
            ...                xmin=0, xmax=2*pi, figsize=[2,1])
            sage: a.show()       # optional -- ImageMagick

        The preceding will loop the animation forever. If you want to show
        only three iterations instead::

            sage: a.show(iterations=3)    # optional -- ImageMagick

        To put a half-second delay between frames::

            sage: a.show(delay=50)        # optional -- ImageMagick

        .. note::

           If you don't have ffmpeg or ImageMagick installed, you will
           get an error message like this::

              Error: Neither ImageMagick nor ffmpeg appears to be installed. Saving an
              animation to a GIF file or displaying an animation requires one of these
              packages, so please install one of them and try again.

              See www.imagemagick.org and www.ffmpeg.org for more information.
        """
        if sage.doctest.DOCTEST_MODE:
            filename = tmp_filename(ext='.gif')
            self.gif(savefile=filename, delay=delay, iterations=iterations)
            return

        if plot.EMBEDDED_MODE:
            self.gif(delay=delay, iterations=iterations)
        else:
            filename = tmp_filename(ext='.gif')
            self.gif(delay=delay, savefile=filename, iterations=iterations)
            os.system('%s %s 2>/dev/null 1>/dev/null &' %
                      (sage.misc.viewer.browser(), filename))
示例#33
0
    def __call__(self, program, complex, subcomplex=None, **kwds):
        """
        Call a CHomP program to compute the homology of a chain
        complex, simplicial complex, or cubical complex.

        See :class:`CHomP` for full documentation.

        EXAMPLES::

        sage: from sage.interfaces.chomp import CHomP
        sage: T = cubical_complexes.Torus()
        sage: CHomP()('homcubes', T) # indirect doctest, optional - CHomP
        {0: 0, 1: Z x Z, 2: Z}
        """
        from sage.misc.temporary_file import tmp_filename
        from sage.homology.all import CubicalComplex, cubical_complexes
        from sage.homology.all import SimplicialComplex, Simplex
        from sage.homology.cubical_complex import Cube
        from sage.homology.chain_complex import HomologyGroup, ChainComplex
        from subprocess import Popen, PIPE
        from sage.rings.all import QQ, ZZ
        from sage.modules.all import VectorSpace, vector
        from sage.combinat.free_module import CombinatorialFreeModule

        if not have_chomp(program):
            raise OSError("Program %s not found" % program)

        verbose = kwds.get('verbose', False)
        generators = kwds.get('generators', False)
        extra_opts = kwds.get('extra_opts', '')
        base_ring = kwds.get('base_ring', ZZ)

        if extra_opts:
            extra_opts = extra_opts.split()
        else:
            extra_opts = []

        # type of complex:
        cubical = False
        simplicial = False
        chain = False
        # CHomP seems to have problems with cubical complexes if the
        # first interval in the first cube defining the complex is
        # degenerate.  So replace the complex X with [0,1] x X.
        if isinstance(complex, CubicalComplex):
            cubical = True
            edge = cubical_complexes.Cube(1)
            original_complex = complex
            complex = edge.product(complex)
            if verbose:
                print "Cubical complex"
        elif isinstance(complex, SimplicialComplex):
            simplicial = True
            if verbose:
                print "Simplicial complex"
        else:
            chain = True
            base_ring = kwds.get('base_ring', complex.base_ring())
            if verbose:
                print "Chain complex over %s" % base_ring

        if base_ring == QQ:
            raise ValueError(
                "CHomP doesn't compute over the rationals, only over Z or F_p."
            )
        if base_ring.is_prime_field():
            p = base_ring.characteristic()
            extra_opts.append('-p%s' % p)
            mod_p = True
        else:
            mod_p = False

        #
        #    complex
        #
        try:
            data = complex._chomp_repr_()
        except AttributeError:
            raise AttributeError(
                "Complex can not be converted to use with CHomP.")

        datafile = tmp_filename()
        f = open(datafile, 'w')
        f.write(data)
        f.close()

        #
        #    subcomplex
        #
        if subcomplex is None:
            if cubical:
                subcomplex = CubicalComplex([complex.n_cells(0)[0]])
            elif simplicial:
                m = re.search(r'\(([^,]*),', data)
                v = int(m.group(1))
                subcomplex = SimplicialComplex([[v]])
        else:
            # replace subcomplex with [0,1] x subcomplex.
            if cubical:
                subcomplex = edge.product(subcomplex)
        #
        #    generators
        #
        if generators:
            genfile = tmp_filename()
            extra_opts.append('-g%s' % genfile)

        #
        #    call program
        #
        if subcomplex is not None:
            try:
                sub = subcomplex._chomp_repr_()
            except AttributeError:
                raise AttributeError(
                    "Subcomplex can not be converted to use with CHomP.")
            subfile = tmp_filename()
            f = open(subfile, 'w')
            f.write(sub)
            f.close()
        else:
            subfile = ''
        if verbose:
            print "Popen called with arguments",
            print[program, datafile, subfile] + extra_opts
            print
            print "CHomP output:"
            print
        # output = Popen([program, datafile, subfile, extra_opts],
        cmd = [program, datafile]
        if subfile:
            cmd.append(subfile)
        if extra_opts:
            cmd.extend(extra_opts)
        output = Popen(cmd, stdout=PIPE).communicate()[0]
        if verbose:
            print output
            print "End of CHomP output"
            print
        if generators:
            gens = open(genfile, 'r').read()
            if verbose:
                print "Generators:"
                print gens

        #
        #    process output
        #
        # output contains substrings of one of the forms
        # "H_1 = Z", "H_1 = Z_2 + Z", "H_1 = Z_2 + Z^2",
        # "H_1 = Z + Z_2 + Z"
        if output.find('trivial') != -1:
            if mod_p:
                return {0: VectorSpace(base_ring, 0)}
            else:
                return {0: HomologyGroup(0, ZZ)}
        d = {}
        h = re.compile("^H_([0-9]*) = (.*)$", re.M)
        tors = re.compile("Z_([0-9]*)")
        #
        #    homology groups
        #
        for m in h.finditer(output):
            if verbose:
                print m.groups()
            # dim is the dimension of the homology group
            dim = int(m.group(1))
            # hom_str is the right side of the equation "H_n = Z^r + Z_k + ..."
            hom_str = m.group(2)
            # need to read off number of summands and their invariants
            if hom_str.find("0") == 0:
                if mod_p:
                    hom = VectorSpace(base_ring, 0)
                else:
                    hom = HomologyGroup(0, ZZ)
            else:
                rk = 0
                if hom_str.find("^") != -1:
                    rk_srch = re.search(r'\^([0-9]*)\s?', hom_str)
                    rk = int(rk_srch.group(1))
                rk += len(re.findall("(Z$)|(Z\s)", hom_str))
                if mod_p:
                    rk = rk if rk != 0 else 1
                    if verbose:
                        print "dimension = %s, rank of homology = %s" % (dim,
                                                                         rk)
                    hom = VectorSpace(base_ring, rk)
                else:
                    n = rk
                    invts = []
                    for t in tors.finditer(hom_str):
                        n += 1
                        invts.append(int(t.group(1)))
                    for i in range(rk):
                        invts.append(0)
                    if verbose:
                        print "dimension = %s, number of factors = %s, invariants = %s" % (
                            dim, n, invts)
                    hom = HomologyGroup(n, ZZ, invts)

            #
            #    generators
            #
            if generators:
                if cubical:
                    g = process_generators_cubical(gens, dim)
                    if verbose:
                        print "raw generators: %s" % g
                    if g:
                        module = CombinatorialFreeModule(
                            base_ring,
                            original_complex.n_cells(dim),
                            prefix="",
                            bracket=True)
                        basis = module.basis()
                        output = []
                        for x in g:
                            v = module(0)
                            for term in x:
                                v += term[0] * basis[term[1]]
                            output.append(v)
                        g = output
                elif simplicial:
                    g = process_generators_simplicial(gens, dim, complex)
                    if verbose:
                        print "raw generators: %s" % gens
                    if g:
                        module = CombinatorialFreeModule(base_ring,
                                                         complex.n_cells(dim),
                                                         prefix="",
                                                         bracket=False)
                        basis = module.basis()
                        output = []
                        for x in g:
                            v = module(0)
                            for term in x:
                                if complex._is_numeric():
                                    v += term[0] * basis[term[1]]
                                else:
                                    translate = complex._translation_from_numeric(
                                    )
                                    simplex = Simplex(
                                        [translate[a] for a in term[1]])
                                    v += term[0] * basis[simplex]
                            output.append(v)
                        g = output
                elif chain:
                    g = process_generators_chain(gens, dim, base_ring)
                    if verbose:
                        print "raw generators: %s" % gens
                if g:
                    if not mod_p:
                        # sort generators to match up with corresponding invariant
                        g = [
                            _[1]
                            for _ in sorted(zip(invts, g), key=lambda x: x[0])
                        ]
                    d[dim] = (hom, g)
                else:
                    d[dim] = hom
            else:
                d[dim] = hom

        if chain:
            new_d = {}
            diff = complex.differential()
            if len(diff) == 0:
                return {}
            bottom = min(diff)
            top = max(diff)
            for dim in d:
                if complex._degree_of_differential == -1:  # chain complex
                    new_dim = bottom + dim
                else:  # cochain complex
                    new_dim = top - dim
                if isinstance(d[dim], tuple):
                    # generators included.
                    group = d[dim][0]
                    gens = d[dim][1]
                    new_gens = []
                    dimension = complex.differential(new_dim).ncols()
                    # make sure that each vector is embedded in the
                    # correct ambient space: pad with a zero if
                    # necessary.
                    for v in gens:
                        v_dict = v.dict()
                        if dimension - 1 not in v.dict():
                            v_dict[dimension - 1] = 0
                            new_gens.append(vector(base_ring, v_dict))
                        else:
                            new_gens.append(v)
                    new_d[new_dim] = (group, new_gens)
                else:
                    new_d[new_dim] = d[dim]
            d = new_d
        return d
示例#34
0
    def export_image(
            self,
            targetfile,
            datafile,  #name (path) of data file Jmol can read or script file telling it what to read or load
            datafile_cmd='script',  #"script" or "load"
            image_type='PNG',  #PNG, JPG, GIF
            figsize=5,
            **kwds):
        r"""
        This executes JmolData.jar to make an image file.

        INPUT:

        - targetfile -- the full path to the file where the image
          should be written.

        - datafile -- full path to the data file Jmol can read or
          text of a script telling Jmol what to read or load.

        - datafile_cmd -- (default ``'script'``)  ``'load'`` or ``'script'``
          should be ``"load"`` for a data file.

        - image_type -- (default ``"PNG"``) ``'PNG'`` ``'JPG'`` or ``'GIF'``

        - figsize -- number (default 5) equal to (pixels/side)/100

        OUTPUT:

        Image file, .png, .gif or .jpg (default .png)

        .. note::

            Examples will generate an error message if a functional Java Virtual Machine (JVM)
            is not installed on the machine the Sage instance is running on.

        .. warning::

            Programmers using this module should check that the JVM is
            available before making calls to avoid the user getting
            error messages.  Check for the JVM using the function
            :meth:`is_jvm_available`, which returns True if a JVM is available.

        EXAMPLES:

        Use Jmol to load a pdb file containing some DNA from a web data
        base and make an image of the DNA. If you execute this in the
        notebook, the image will appear in the output cell::

            sage: from sage.interfaces.jmoldata import JmolData
            sage: JData = JmolData()
            sage: script = "load =1lcd;display DNA;moveto 0.0 { -473 -713 -518 59.94} 100.0 0.0 0.0 {21.17 26.72 27.295} 27.544636 {0.0 0.0 0.0} -25.287832 64.8414 0.0;"
            sage: testfile = tmp_filename(ext="DNA.png")
            sage: JData.export_image(targetfile=testfile,datafile=script,image_type="PNG")  # optional -- java internet
            sage: print os.path.exists(testfile)  # optional -- java internet
            True

        Use Jmol to save an image of a 3-D object created in Sage.
        This method is used internally by plot3d to generate static images.
        This example doesn't have correct scaling::

            sage: from sage.interfaces.jmoldata import JmolData
            sage: JData = JmolData()
            sage: D=dodecahedron()
            sage: from sage.misc.misc import SAGE_TMP
            sage: archive_name=os.path.join(SAGE_TMP, "archive.jmol.zip")
            sage: D.export_jmol(archive_name)  #not scaled properly...need some more steps.
            sage: testfile = os.path.join(SAGE_TMP, "testimage.png")
            sage: script = 'set defaultdirectory "%s"\n script SCRIPT\n'%archive_name
            sage: JData.export_image(targetfile =testfile,datafile = script, image_type="PNG") # optional -- java
            sage: print os.path.exists(testfile) # optional -- java
            True

        """
        # Set up paths, file names and scripts
        jmolpath = os.path.join(SAGE_LOCAL, "share", "jmol", "JmolData.jar")
        launchscript = ""
        if (datafile_cmd != 'script'):
            launchscript = "load "
        launchscript = launchscript + datafile
        imagescript = "write " + image_type + " " + targetfile + "\n"

        sizeStr = "%sx%s" % (figsize * 100, figsize * 100)
        # Scratch file for Jmol errors
        scratchout = tmp_filename(ext=".txt")
        with open(scratchout, 'w') as jout:
            # Now call the java application and write the file.
            env = dict(os.environ)
            env['LC_ALL'] = 'C'
            env['LANG'] = 'C'
            subprocess.call([
                "java", "-Xmx512m", "-Djava.awt.headless=true", "-jar",
                jmolpath, "-iox", "-g", sizeStr, "-J", launchscript, "-j",
                imagescript
            ],
                            stdout=jout,
                            stderr=jout,
                            env=env)
        if not os.path.isfile(targetfile):
            raise RuntimeError(
                "Jmol failed to create file %s, see %s for details" %
                (repr(targetfile), repr(scratchout)))
        os.unlink(scratchout)
示例#35
0
    def ehrhart_polynomial(self, verbose=False, dual=None,
            irrational_primal=None, irrational_all_primal=None, maxdet=None,
            no_decomposition=None, compute_vertex_cones=None, smith_form=None,
            dualization=None, triangulation=None, triangulation_max_height=None,
            **kwds):
        r"""
        Return the Ehrhart polynomial of this polyhedron.

        Let `P` be a lattice polytope in `\RR^d` and define `L(P,t) = \# (tP
        \cap \ZZ^d)`. Then E. Ehrhart proved in 1962 that `L` coincides with a
        rational polynomial of degree `d` for integer `t`. `L` is called the
        *Ehrhart polynomial* of `P`. For more information see the
        :wikipedia:`Ehrhart_polynomial`.

        INPUT:

        - ``verbose`` - (boolean, default to ``False``) if ``True``, print the
          whole output of the LattE command.

        The following options are passed to the LattE command, for details you
        should consult `the LattE documentation
        <https://www.math.ucdavis.edu/~latte/software/packages/latte_current/>`__:

        - ``dual`` - (boolean) triangulate and signed-decompose in the dual
          space

        - ``irrational_primal`` - (boolean) triangulate in the dual space,
          signed-decompose in the primal space using irrationalization.

        - ``irrational_all_primal`` - (boolean) Triangulate and signed-decompose
          in the primal space using irrationalization.

        - ``maxdet`` -- (integer) decompose down to an index (determinant) of
          ``maxdet`` instead of index 1 (unimodular cones).

        - ``no_decomposition`` -- (boolean) do not signed-decompose simplicial cones.

        - ``compute_vertex_cones`` -- (string) either 'cdd' or 'lrs' or '4ti2'

        - ``smith_form`` -- (string) either 'ilio' or 'lidia'

        - ``dualization`` -- (string) either 'cdd' or '4ti2'

        - ``triangulation`` - (string) 'cddlib', '4ti2' or 'topcom'

        - ``triangulation_max_height`` - (integer) use a uniform distribution of
          height from 1 to this number

        .. NOTE::

            Any additional argument is forwarded to LattE's executable
            ``count``. All occurrences of '_' will be replaced with a '-'.

        ALGORITHM:

        This method calls the program ``count`` from LattE integrale, a program
        for lattice point enumeration (see
        https://www.math.ucdavis.edu/~latte/).

        EXAMPLES::

            sage: P = Polyhedron(vertices=[(0,0,0),(3,3,3),(-3,2,1),(1,-1,-2)])
            sage: p = P.ehrhart_polynomial()    # optional - latte_int
            sage: p                             # optional - latte_int
            7/2*t^3 + 2*t^2 - 1/2*t + 1
            sage: p(1)                          # optional - latte_int
            6
            sage: len(P.integral_points())
            6
            sage: p(2)                          # optional - latte_int
            36
            sage: len((2*P).integral_points())
            36

        The unit hypercubes::

            sage: from itertools import product
            sage: def hypercube(d):
            ....:     return Polyhedron(vertices=list(product([0,1],repeat=d)))
            sage: hypercube(3).ehrhart_polynomial()   # optional - latte_int
            t^3 + 3*t^2 + 3*t + 1
            sage: hypercube(4).ehrhart_polynomial()   # optional - latte_int
            t^4 + 4*t^3 + 6*t^2 + 4*t + 1
            sage: hypercube(5).ehrhart_polynomial()   # optional - latte_int
            t^5 + 5*t^4 + 10*t^3 + 10*t^2 + 5*t + 1
            sage: hypercube(6).ehrhart_polynomial()   # optional - latte_int
            t^6 + 6*t^5 + 15*t^4 + 20*t^3 + 15*t^2 + 6*t + 1

        An empty polyhedron::

            sage: P = Polyhedron(ambient_dim=3, vertices=[])
            sage: P.ehrhart_polynomial()    # optional - latte_int
            0
            sage: parent(_)                 # optional - latte_int
            Univariate Polynomial Ring in t over Rational Field

        TESTS:

        Test options::

            sage: P = Polyhedron(ieqs=[[1,-1,1,0], [-1,2,-1,0], [1,1,-2,0]], eqns=[[-1,2,-1,-3]], base_ring=ZZ)

            sage: p = P.ehrhart_polynomial(maxdet=5, verbose=True)  # optional - latte_int
            This is LattE integrale ...
            ...
            Invocation: count --ehrhart-polynomial '--redundancy-check=none' '--maxdet=5' --cdd ...
            ...
            sage: p    # optional - latte_int
            1/2*t^2 + 3/2*t + 1

            sage: p = P.ehrhart_polynomial(dual=True, verbose=True)  # optional - latte_int
            This is LattE integrale ...
            ...
            Invocation: count --ehrhart-polynomial '--redundancy-check=none' --dual --cdd ...
            ...
            sage: p   # optional - latte_int
            1/2*t^2 + 3/2*t + 1

            sage: p = P.ehrhart_polynomial(irrational_primal=True, verbose=True)   # optional - latte_int
            This is LattE integrale ...
            ...
            Invocation: count --ehrhart-polynomial '--redundancy-check=none' --irrational-primal --cdd ...
            ...
            sage: p   # optional - latte_int
            1/2*t^2 + 3/2*t + 1

            sage: p = P.ehrhart_polynomial(irrational_all_primal=True, verbose=True)  # optional - latte_int
            This is LattE integrale ...
            ...
            Invocation: count --ehrhart-polynomial '--redundancy-check=none' --irrational-all-primal --cdd ...
            sage: p   # optional - latte_int
            1/2*t^2 + 3/2*t + 1

        Test bad options::

            sage: P.ehrhart_polynomial(bim_bam_boum=19)   # optional - latte_int
            Traceback (most recent call last):
            ...
            RuntimeError: Latte returned 1 when running:
            count --ehrhart-polynomial --redundancy-check=none --bim-bam-boum=19 --cdd ...
            (see output above)
        """
        if not self.is_lattice_polytope():
            raise ValueError("this must be a lattice polytope")

        from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
        R = PolynomialRing(QQ, 't')
        if self.is_empty():
            return R.zero()

        from sage.misc.temporary_file import tmp_filename
        from sage.misc.misc import SAGE_TMP
        from subprocess import Popen, PIPE

        in_str = self.cdd_Hrepresentation()
        in_filename = tmp_filename() + '.ine'
        in_file = open(in_filename, 'w')
        in_file.write(self.cdd_Hrepresentation())
        in_file.close()

        args = ['count', '--ehrhart-polynomial']
        if 'redundancy_check' not in kwds:
            args.append('--redundancy-check=none')

        # note: the options below are explicitely written in the function
        # declaration in order to keep tab completion (see #18211).
        kwds.update({
            'dual'                    : dual,
            'irrational_primal'       : irrational_primal,
            'irrational_all_primal'   : irrational_all_primal,
            'maxdet'                  : maxdet,
            'no_decomposition'        : no_decomposition,
            'compute_vertex_cones'    : compute_vertex_cones,
            'smith_form'              : smith_form,
            'dualization'             : dualization,
            'triangulation'           : triangulation,
            'triangulation_max_height': triangulation_max_height})

        for key,value in kwds.items():
            if value is None or value is False:
                continue

            key = key.replace('_','-')
            if value is True:
                args.append('--{}'.format(key))
            else:
                args.append('--{}={}'.format(key, value))
        args.append('--cdd')
        args.append(in_filename)

        try:
            latte_proc = Popen(args, stdin=PIPE, stdout=PIPE, stderr=(None if verbose else PIPE), cwd=str(SAGE_TMP))
        except OSError:
            raise ValueError("The package latte_int must be installed (type "
                    "'sage -i latte_int') in a console or "
                    "'install_package('latte_int') at a Sage prompt)!\n")

        ans, err = latte_proc.communicate()
        ret_code = latte_proc.poll()
        if ret_code:
            if not verbose:
                print err
            raise RuntimeError("Latte returned {} when running:\n{}\n(see output above)".format(ret_code, ' '.join(args)))

        p = ans.splitlines()[-2]

        return R(p)
示例#36
0
    def graphics_from_save(self, save_function, save_kwds,
                           file_extension, output_container,
                           figsize=None, dpi=None):
        r"""
        Helper to construct graphics.

        This method can be used to simplify the implementation of a
        ``_rich_repr_`` method of a graphics object if there is
        already a function to save graphics to a file.

        INPUT:

        - ``save_function`` -- callable that can save graphics to a file
          and accepts options like
          :meth:`sage.plot.graphics.Graphics.save`.

        - ``save_kwds`` -- dictionary. Keyword arguments that are
          passed to the save function.

        - ``file_extension`` -- string starting with ``'.'``. The file
          extension of the graphics file.

        - ``output_container`` -- subclass of
          :class:`sage.repl.rich_output.output_basic.OutputBase`. The
          output container to use. Must be one of the types in
          :meth:`supported_output`.

        - ``figsize`` -- pair of integers (optional). The desired graphics
          size in pixels. Suggested, but need not be respected by the
          output.

        - ``dpi`` -- integer (optional). The desired resolution in dots
          per inch. Suggested, but need not be respected by the output.

        OUTPUT:

        Return an instance of ``output_container``.

        EXAMPLES::

            sage: from sage.repl.rich_output import get_display_manager
            sage: dm = get_display_manager()
            sage: plt = plot(sin)
            sage: out = dm.graphics_from_save(plt.save, dict(), '.png', dm.types.OutputImagePng)
            sage: out
            OutputImagePng container
            sage: out.png.get().startswith('\x89PNG')
            True
            sage: out.png.filename()   # random
            '/home/user/.sage/temp/localhost.localdomain/23903/tmp_pu5woK.png'
        """
        import os
        if not file_extension.startswith(os.path.extsep):
            raise ValueError('file_extension must start with a period')
        if output_container not in self.supported_output():
            raise OutputTypeException('output_container is not supported by backend')
        from sage.misc.temporary_file import tmp_filename
        filename = tmp_filename(ext=file_extension)
        # Call the save_function with the right arguments
        kwds = dict(save_kwds)
        if figsize is not None:
            kwds['figsize'] = figsize
        if dpi is not None:
            kwds['dpi'] = dpi
        save_function(filename, **kwds)
        from sage.repl.rich_output.buffer import OutputBuffer
        buf = OutputBuffer.from_file(filename)
        return output_container(buf)
示例#37
0
def graphics_from_save(save_function,
                       preferred_mime_types,
                       allowed_mime_types=None,
                       figsize=None,
                       dpi=None):
    """
    Helper function to construct a graphics file.

    INPUT:
    
    - ``save_function`` -- callable that can save graphics to a file
      and accepts options like
      :meth:`sage.plot.graphics.Graphics.save``.

    - ``preferred_mime_types`` -- list of mime types. The graphics
      output mime types in order of preference (i.e. best quality to
      worst).

    - ``allowed_mime_types`` -- set of mime types (as strings). The
      graphics types that we can display. Output, if any, will be one
      of those.

    - ``figsize`` -- pair of integers (optional). The desired graphics
      size in pixels. Suggested, but need not be respected by the
      output.

    - ``dpi`` -- integer (optional). The desired resolution in dots
      per inch. Suggested, but need not be respected by the output.

    OUTPUT:

    Return an instance of
    :class:`sage.structure.graphics_file.GraphicsFile` encapsulating a
    suitable image file. Image is one of the
    ``preferred_mime_types``. If ``allowed_mime_types`` is specified,
    the resulting file format matches one of these.

    Alternatively, this function can return ``None`` to indicate that
    textual representation is preferable and/or no graphics with the
    desired mime type can be generated.
    """
    # Figure out best mime type
    mime = None
    if allowed_mime_types is None:
        mime = Mime.PNG
    else:
        # order of preference
        for m in preferred_mime_types:
            if m in allowed_mime_types:
                mime = m
                break
    if mime is None:
        return None  # don't know how to generate suitable graphics
    # Generate suitable temp file
    filename = tmp_filename(ext=os.path.extsep + Mime.extension(mime))
    # Call the save_function with the right arguments
    kwds = {}
    if figsize is not None:
        kwds['figsize'] = figsize
    if dpi is not None:
        kwds['dpi'] = dpi
    save_function(filename, **kwds)
    return GraphicsFile(filename, mime)
示例#38
0
    def gif(self, delay=20, savefile=None, iterations=0, show_path=False,
            use_ffmpeg=False):
        r"""
        Returns an animated gif composed from rendering the graphics
        objects in self.

        This method will only work if either (a) the ImageMagick
        software suite is installed, i.e., you have the ``convert``
        command or (b) ``ffmpeg`` is installed.  See
        [IM] for more about ImageMagick, and see
        [FF] for more about ``ffmpeg``.  By default, this
        produces the gif using ``convert`` if it is present.  If this
        can't find ``convert`` or if ``use_ffmpeg`` is True, then it
        uses ``ffmpeg`` instead.

        INPUT:

        -  ``delay`` - (default: 20) delay in hundredths of a
           second between frames

        -  ``savefile`` - file that the animated gif gets saved
           to

        -  ``iterations`` - integer (default: 0); number of
           iterations of animation. If 0, loop forever.

        -  ``show_path`` - boolean (default: False); if True,
           print the path to the saved file

        - ``use_ffmpeg`` - boolean (default: False); if True, use
          'ffmpeg' by default instead of 'convert'.

        If ``savefile`` is not specified: in notebook mode, display the
        animation; otherwise, save it to a default file name.

        EXAMPLES::

            sage: a = animate([sin(x + float(k)) for k in srange(0,2*pi,0.7)],
            ....:                xmin=0, xmax=2*pi, figsize=[2,1])
            sage: dir = tmp_dir()
            sage: a.gif()              # not tested
            sage: a.gif(savefile=dir + 'my_animation.gif', delay=35, iterations=3)  # optional -- ImageMagick
            sage: a.gif(savefile=dir + 'my_animation.gif', show_path=True) # optional -- ImageMagick
            Animation saved to .../my_animation.gif.
            sage: a.gif(savefile=dir + 'my_animation_2.gif', show_path=True, use_ffmpeg=True) # optional -- ffmpeg
            Animation saved to .../my_animation_2.gif.

        .. note::

           If neither ffmpeg nor ImageMagick is installed, you will
           get an error message like this::

              Error: Neither ImageMagick nor ffmpeg appears to be installed. Saving an
              animation to a GIF file or displaying an animation requires one of these
              packages, so please install one of them and try again.

              See www.imagemagick.org and www.ffmpeg.org for more information.
        """
        from sage.misc.sage_ostools import have_program
        have_convert = have_program('convert')
        have_ffmpeg = self._have_ffmpeg()
        if use_ffmpeg or not have_convert:
            if have_ffmpeg:
                self.ffmpeg(savefile=savefile, show_path=show_path,
                            output_format='.gif', delay=delay,
                            iterations=iterations)
            else:
                if not have_convert:
                    msg = """
Error: Neither ImageMagick nor ffmpeg appears to be installed. Saving an
animation to a GIF file or displaying an animation requires one of these
packages, so please install one of them and try again.

See www.imagemagick.org and www.ffmpeg.org for more information."""
                else:
                    msg = """
Error: ffmpeg does not appear to be installed.  Download it from
www.ffmpeg.org, or use 'convert' to produce gifs instead."""
                raise OSError(msg)
        else:
            if not savefile:
                savefile = tmp_filename(ext='.gif')
            if not savefile.endswith('.gif'):
                savefile += '.gif'
            savefile = os.path.abspath(savefile)
            d = self.png()
            cmd = ( 'cd "%s"; sage-native-execute convert -dispose Background '
                    '-delay %s -loop %s *.png "%s"' ) % ( d, int(delay),
                        int(iterations), savefile )
            from subprocess import check_call, CalledProcessError
            try:
                check_call(cmd, shell=True)
                if show_path:
                    print "Animation saved to file %s." % savefile
            except (CalledProcessError, OSError):
                msg = """
Error: Cannot generate GIF animation.  Verify that convert
(ImageMagick) or ffmpeg is installed, and that the objects passed to
the animate command can be saved in PNG image format.

See www.imagemagick.org and www.ffmpeg.org for more information."""
                raise OSError(msg)
示例#39
0
def integrate(arg,
              polynomial=None,
              algorithm='triangulate',
              raw_output=False,
              verbose=False,
              **kwds):
    r"""
    Call to the function integrate from LattE integrale.

    INPUT:

    - ``arg`` -- a cdd or LattE description string.

    - ``polynomial`` -- multivariate polynomial or valid LattE polynomial description string.
      If given, the valuation parameter of LattE is set to integrate, and is set to volume otherwise.

    - ``algorithm`` -- (default: 'triangulate') the integration method. Use 'triangulate' for
      polytope triangulation or 'cone-decompose' for tangent cone decomposition method.

    - ``raw_output`` -- if ``True`` then return directly the output string from LattE.

    - ``verbose`` -- if ``True`` then return directly verbose output from LattE.

    - For all other options of the integrate program, consult the LattE manual.

    OUTPUT:

    Either a string (if ``raw_output`` if set to ``True``) or a rational.

    EXAMPLES::

        sage: from sage.interfaces.latte import integrate   # optional - latte_int
        sage: P = 2 * polytopes.cube()
        sage: x, y, z = polygen(QQ, 'x, y, z')

    Integrating over a polynomial over a polytope in either the H or V representation::

        sage: integrate(P.cdd_Hrepresentation(), x^2*y^2*z^2, cdd=True)   # optional - latte_int
        4096/27
        sage: integrate(P.cdd_Vrepresentation(), x^2*y^2*z^2, cdd=True)   # optional - latte_int
        4096/27

    Computing the volume of a polytope in either the H or V representation::

        sage: integrate(P.cdd_Hrepresentation(), cdd=True)   # optional - latte_int
        64
        sage: integrate(P.cdd_Vrepresentation(), cdd=True)   # optional - latte_int
        64

    Polynomials given as a string in LattE description are also accepted::

        sage: integrate(P.cdd_Hrepresentation(), '[[1,[2,2,2]]]', cdd=True)   # optional - latte_int
        4096/27

    TESTS:

    Testing raw output::

        sage: from sage.interfaces.latte import integrate   # optional - latte_int
        sage: P = polytopes.cuboctahedron()
        sage: cddin = P.cdd_Vrepresentation()
        sage: x, y, z = polygen(QQ, 'x, y, z')
        sage: f = 3*x^2*y^4*z^6 + 7*y^3*z^5
        sage: integrate(cddin, f, cdd=True, raw_output=True)  # optional - latte_int
        '629/47775'

    Testing the ``verbose`` option to integrate over a polytope::

        sage: ans = integrate(cddin, f, cdd=True, verbose=True, raw_output=True)  # optional - latte_int
        This is LattE integrale ...
        ...
        Invocation: integrate --valuation=integrate --triangulate --redundancy-check=none --cdd --monomials=... /dev/stdin
        ...

    Testing triangulate algorithm::

        sage: from sage.interfaces.latte import integrate   # optional - latte_int
        sage: P = polytopes.cuboctahedron()
        sage: cddin = P.cdd_Vrepresentation()
        sage: integrate(cddin, algorithm='triangulate', cdd=True)  # optional - latte_int
        20/3

    Testing convex decomposition algorithm::

        sage: from sage.interfaces.latte import integrate   # optional - latte_int
        sage: P = polytopes.cuboctahedron()
        sage: cddin = P.cdd_Vrepresentation()
        sage: integrate(cddin, algorithm='cone-decompose', cdd=True)  # optional - latte_int
        20/3

    Testing raw output::

        sage: from sage.interfaces.latte import integrate   # optional - latte_int
        sage: P = polytopes.cuboctahedron()
        sage: cddin = P.cdd_Vrepresentation()
        sage: integrate(cddin, cdd=True, raw_output=True)  # optional - latte_int
        '20/3'

    Testing polynomial given as a string in LattE description::

        sage: from sage.interfaces.latte import integrate   # optional - latte_int
        sage: P = polytopes.cuboctahedron()
        sage: integrate(P.cdd_Hrepresentation(), '[[3,[2,4,6]],[7,[0, 3, 5]]]', cdd=True)   # optional - latte_int
        629/47775

    Testing the ``verbose`` option to compute the volume of a polytope::

        sage: from sage.interfaces.latte import integrate   # optional - latte_int
        sage: P = polytopes.cuboctahedron()
        sage: cddin = P.cdd_Vrepresentation()
        sage: ans = integrate(cddin, cdd=True, raw_output=True, verbose=True)  # optional - latte_int
        This is LattE integrale ...
        ...
        Invocation: integrate --valuation=volume --triangulate --redundancy-check=none --cdd /dev/stdin
        ...

    Testing the runtime error::

        sage: P = Polyhedron(rays=[[1,0],[0,1]])
        sage: P._volume_latte()  # optional - latte_int
        Traceback (most recent call last):
        ...
        RuntimeError: LattE integrale program failed (exit code -6):
        This is LattE integrale ...
        ...
        determinant: nonsquare matrix
    """
    # Check that LattE is present
    Latte().require()

    arg = str_to_bytes(arg)

    from sage.rings.rational import Rational

    args = ['integrate']

    got_polynomial = True if polynomial is not None else False

    if got_polynomial:
        args.append('--valuation=integrate')
    else:
        args.append('--valuation=volume')

    if algorithm == 'triangulate':
        args.append('--triangulate')
    elif algorithm == 'cone-decompose':
        args.append('--cone-decompose')

    if 'redundancy_check' not in kwds:
        args.append('--redundancy-check=none')

    for key, value in kwds.items():
        if value is None or value is False:
            continue

        key = key.replace('_', '-')
        if value is True:
            args.append('--{}'.format(key))
        else:
            args.append('--{}={}'.format(key, value))

    if got_polynomial:
        if not isinstance(polynomial, str):
            # transform polynomial to LattE description
            monomials_list = to_latte_polynomial(polynomial)
        else:
            monomials_list = str(polynomial)

        from sage.misc.temporary_file import tmp_filename
        filename_polynomial = tmp_filename()

        with open(filename_polynomial, 'w') as f:
            f.write(monomials_list)
            args += ['--monomials=' + filename_polynomial]

    args += ['/dev/stdin']

    # The cwd argument is needed because latte
    # always produces diagnostic output files.
    latte_proc = Popen(args,
                       stdin=PIPE,
                       stdout=PIPE,
                       stderr=(None if verbose else PIPE),
                       cwd=str(SAGE_TMP))

    ans, err = latte_proc.communicate(arg)
    if err:
        err = bytes_to_str(err)
    ret_code = latte_proc.poll()
    if ret_code:
        if err is None:
            err = ", see error message above"
        else:
            err = ":\n" + err
        raise RuntimeError(
            "LattE integrale program failed (exit code {})".format(ret_code) +
            err.strip())

    ans = bytes_to_str(ans)
    ans = ans.splitlines()
    ans = ans[-5].split()
    assert (ans[0] == 'Answer:')
    ans = ans[1]

    if raw_output:
        return ans
    else:
        return Rational(ans)
示例#40
0
文件: chomp.py 项目: mcognetta/sage
    def __call__(self, program, complex, subcomplex=None, **kwds):
        """
        Call a CHomP program to compute the homology of a chain
        complex, simplicial complex, or cubical complex.

        See :class:`CHomP` for full documentation.

        EXAMPLES::

            sage: from sage.interfaces.chomp import CHomP
            sage: T = cubical_complexes.Torus()
            sage: CHomP()('homcubes', T) # indirect doctest, optional - CHomP
            {0: 0, 1: Z x Z, 2: Z}
        """
        from sage.misc.temporary_file import tmp_filename
        from sage.homology.all import CubicalComplex, cubical_complexes
        from sage.homology.all import SimplicialComplex, Simplex
        from sage.homology.chain_complex import HomologyGroup
        from subprocess import Popen, PIPE
        from sage.rings.all import QQ, ZZ
        from sage.modules.all import VectorSpace, vector
        from sage.combinat.free_module import CombinatorialFreeModule

        if not have_chomp(program):
            raise OSError("Program %s not found" % program)

        verbose = kwds.get('verbose', False)
        generators = kwds.get('generators', False)
        extra_opts = kwds.get('extra_opts', '')
        base_ring = kwds.get('base_ring', ZZ)

        if extra_opts:
            extra_opts = extra_opts.split()
        else:
            extra_opts = []

        # type of complex:
        cubical = False
        simplicial = False
        chain = False
        # CHomP seems to have problems with cubical complexes if the
        # first interval in the first cube defining the complex is
        # degenerate.  So replace the complex X with [0,1] x X.
        if isinstance(complex, CubicalComplex):
            cubical = True
            edge = cubical_complexes.Cube(1)
            original_complex = complex
            complex = edge.product(complex)
            if verbose:
                print("Cubical complex")
        elif isinstance(complex, SimplicialComplex):
            simplicial = True
            if verbose:
                print("Simplicial complex")
        else:
            chain = True
            base_ring = kwds.get('base_ring', complex.base_ring())
            if verbose:
                print("Chain complex over %s" % base_ring)

        if base_ring == QQ:
            raise ValueError("CHomP doesn't compute over the rationals, only over Z or F_p.")
        if base_ring.is_prime_field():
            p = base_ring.characteristic()
            extra_opts.append('-p%s' % p)
            mod_p = True
        else:
            mod_p = False

        #
        #    complex
        #
        try:
            data = complex._chomp_repr_()
        except AttributeError:
            raise AttributeError("Complex can not be converted to use with CHomP.")

        datafile = tmp_filename()
        f = open(datafile, 'w')
        f.write(data)
        f.close()

        #
        #    subcomplex
        #
        if subcomplex is None:
            if cubical:
                subcomplex = CubicalComplex([complex.n_cells(0)[0]])
            elif simplicial:
                m = re.search(r'\(([^,]*),', data)
                v = int(m.group(1))
                subcomplex = SimplicialComplex([[v]])
        else:
            # replace subcomplex with [0,1] x subcomplex.
            if cubical:
                subcomplex = edge.product(subcomplex)
        #
        #    generators
        #
        if generators:
            genfile = tmp_filename()
            extra_opts.append('-g%s' % genfile)

        #
        #    call program
        #
        if subcomplex is not None:
            try:
                sub = subcomplex._chomp_repr_()
            except AttributeError:
                raise AttributeError("Subcomplex can not be converted to use with CHomP.")
            subfile = tmp_filename()
            f = open(subfile, 'w')
            f.write(sub)
            f.close()
        else:
            subfile = ''
        if verbose:
            print("Popen called with arguments", end="")
            print([program, datafile, subfile] + extra_opts)
            print("")
            print("CHomP output:")
            print("")
        # output = Popen([program, datafile, subfile, extra_opts],
        cmd = [program, datafile]
        if subfile:
            cmd.append(subfile)
        if extra_opts:
            cmd.extend(extra_opts)
        output = Popen(cmd, stdout=PIPE).communicate()[0]
        if verbose:
            print(output)
            print("End of CHomP output")
            print("")
        if generators:
            gens = open(genfile, 'r').read()
            if verbose:
                print("Generators:")
                print(gens)
        #
        #    process output
        #
        if output.find('ERROR') != -1:
            raise RuntimeError('error inside CHomP')
        # output contains substrings of one of the forms
        # "H_1 = Z", "H_1 = Z_2 + Z", "H_1 = Z_2 + Z^2",
        # "H_1 = Z + Z_2 + Z"
        if output.find('trivial') != -1:
            if mod_p:
                return {0: VectorSpace(base_ring, 0)}
            else:
                return {0: HomologyGroup(0, ZZ)}
        d = {}
        h = re.compile("^H_([0-9]*) = (.*)$", re.M)
        tors = re.compile("Z_([0-9]*)")
        #
        #    homology groups
        #
        for m in h.finditer(output):
            if verbose:
                print(m.groups())
            # dim is the dimension of the homology group
            dim = int(m.group(1))
            # hom_str is the right side of the equation "H_n = Z^r + Z_k + ..."
            hom_str = m.group(2)
            # need to read off number of summands and their invariants
            if hom_str.find("0") == 0:
                if mod_p:
                    hom = VectorSpace(base_ring, 0)
                else:
                    hom = HomologyGroup(0, ZZ)
            else:
                rk = 0
                if hom_str.find("^") != -1:
                    rk_srch = re.search(r'\^([0-9]*)\s?', hom_str)
                    rk = int(rk_srch.group(1))
                rk += len(re.findall("(Z$)|(Z\s)", hom_str))
                if mod_p:
                    rk = rk if rk != 0 else 1
                    if verbose:
                        print("dimension = %s, rank of homology = %s" % (dim, rk))
                    hom = VectorSpace(base_ring, rk)
                else:
                    n = rk
                    invts = []
                    for t in tors.finditer(hom_str):
                        n += 1
                        invts.append(int(t.group(1)))
                    for i in range(rk):
                        invts.append(0)
                    if verbose:
                        print("dimension = %s, number of factors = %s, invariants = %s" % (dim, n, invts))
                    hom = HomologyGroup(n, ZZ, invts)

            #
            #    generators
            #
            if generators:
                if cubical:
                    g = process_generators_cubical(gens, dim)
                    if verbose:
                        print("raw generators: %s" % g)
                    if g:
                        module = CombinatorialFreeModule(base_ring,
                                                         original_complex.n_cells(dim),
                                                         prefix="",
                                                         bracket=True)
                        basis = module.basis()
                        output = []
                        for x in g:
                            v = module(0)
                            for term in x:
                                v += term[0] * basis[term[1]]
                            output.append(v)
                        g = output
                elif simplicial:
                    g = process_generators_simplicial(gens, dim, complex)
                    if verbose:
                        print("raw generators: %s" % gens)
                    if g:
                        module = CombinatorialFreeModule(base_ring,
                                                         complex.n_cells(dim),
                                                         prefix="",
                                                         bracket=False)
                        basis = module.basis()
                        output = []
                        for x in g:
                            v = module(0)
                            for term in x:
                                if complex._is_numeric():
                                    v += term[0] * basis[term[1]]
                                else:
                                    translate = complex._translation_from_numeric()
                                    simplex = Simplex([translate[a] for a in term[1]])
                                    v += term[0] * basis[simplex]
                            output.append(v)
                        g = output
                elif chain:
                    g = process_generators_chain(gens, dim, base_ring)
                    if verbose:
                        print("raw generators: %s" % gens)
                if g:
                    if not mod_p:
                        # sort generators to match up with corresponding invariant
                        g = [_[1] for _ in sorted(zip(invts, g), key=lambda x: x[0])]
                    d[dim] = (hom, g)
                else:
                    d[dim] = hom
            else:
                d[dim] = hom

        if chain:
            new_d = {}
            diff = complex.differential()
            if len(diff) == 0:
                return {}
            bottom = min(diff)
            top = max(diff)
            for dim in d:
                if complex._degree_of_differential == -1:  # chain complex
                    new_dim = bottom + dim
                else: # cochain complex
                    new_dim = top - dim
                if isinstance(d[dim], tuple):
                    # generators included.
                    group = d[dim][0]
                    gens = d[dim][1]
                    new_gens = []
                    dimension = complex.differential(new_dim).ncols()
                    # make sure that each vector is embedded in the
                    # correct ambient space: pad with a zero if
                    # necessary.
                    for v in gens:
                        v_dict = v.dict()
                        if dimension - 1 not in v.dict():
                            v_dict[dimension - 1] = 0
                            new_gens.append(vector(base_ring, v_dict))
                        else:
                            new_gens.append(v)
                    new_d[new_dim] = (group, new_gens)
                else:
                    new_d[new_dim] = d[dim]
            d = new_d
        return d
示例#41
0
def count(arg,
          ehrhart_polynomial=False,
          multivariate_generating_function=False,
          raw_output=False,
          verbose=False,
          **kwds):
    r"""
    Call to the program count from LattE integrale

    INPUT:

    - ``arg`` -- a cdd or LattE description string

    - ``ehrhart_polynomial``, ``multivariate_generating_function``  -- to
      compute Ehrhart polynomial or multivariate generating function instead of
      just counting points

    - ``raw_output`` -- if ``True`` then return directly the output string from LattE

    - For all other options of the count program, consult the LattE manual

    OUTPUT:

    Either a string (if ``raw_output`` if set to ``True``) or an integer (when
    counting points), or a polynomial (if ``ehrhart_polynomial`` is set to
    ``True``) or a multivariate THING (if ``multivariate_generating_function``
    is set to ``True``)

    EXAMPLES::

        sage: from sage.interfaces.latte import count    # optional - latte_int
        sage: P = 2 * polytopes.cube()

    Counting integer points from either the H or V representation::

        sage: count(P.cdd_Hrepresentation(), cdd=True)   # optional - latte_int
        125
        sage: count(P.cdd_Vrepresentation(), cdd=True)   # optional - latte_int
        125

    Ehrhart polynomial::

        sage: count(P.cdd_Hrepresentation(), cdd=True, ehrhart_polynomial=True)  # optional - latte_int
        64*t^3 + 48*t^2 + 12*t + 1

    Multivariate generating function currently only work with ``raw_output=True``::

        sage: opts = {'cdd': True,
        ....:         'multivariate_generating_function': True,
        ....:         'raw_output': True}
        sage: cddin = P.cdd_Hrepresentation()
        sage: print(count(cddin, **opts))  # optional - latte_int
        x[0]^2*x[1]^(-2)*x[2]^(-2)/((1-x[1])*(1-x[2])*(1-x[0]^(-1)))
         + x[0]^(-2)*x[1]^(-2)*x[2]^(-2)/((1-x[1])*(1-x[2])*(1-x[0]))
         + x[0]^2*x[1]^(-2)*x[2]^2/((1-x[1])*(1-x[2]^(-1))*(1-x[0]^(-1)))
         + x[0]^(-2)*x[1]^(-2)*x[2]^2/((1-x[1])*(1-x[0])*(1-x[2]^(-1)))
         + x[0]^2*x[1]^2*x[2]^(-2)/((1-x[2])*(1-x[1]^(-1))*(1-x[0]^(-1)))
         + x[0]^(-2)*x[1]^2*x[2]^(-2)/((1-x[2])*(1-x[0])*(1-x[1]^(-1)))
         + x[0]^2*x[1]^2*x[2]^2/((1-x[2]^(-1))*(1-x[1]^(-1))*(1-x[0]^(-1)))
         + x[0]^(-2)*x[1]^2*x[2]^2/((1-x[0])*(1-x[2]^(-1))*(1-x[1]^(-1)))

    TESTS:

    Testing raw output::

        sage: from sage.interfaces.latte import count   # optional - latte_int
        sage: P = polytopes.cuboctahedron()
        sage: cddin = P.cdd_Vrepresentation()
        sage: count(cddin, cdd=True, raw_output=True)  # optional - latte_int
        '19'
        sage: count(cddin, cdd=True, raw_output=True, ehrhart_polynomial=True) # optional - latte_int
        ' + 1 * t^0 + 10/3 * t^1 + 8 * t^2 + 20/3 * t^3'
        sage: count(cddin, cdd=True, raw_output=True, multivariate_generating_function=True) # optional - latte_int
        'x[0]^(-1)*x[1]^(-1)/((1-x[0]*x[2])*(1-x[0]^(-1)*x[1])*...x[0]^(-1)*x[2]^(-1)))\n'

    Testing the ``verbose`` option::

        sage: n = count(cddin, cdd=True, verbose=True, raw_output=True)  # optional - latte_int
        This is LattE integrale ...
        ...
        Invocation: count '--redundancy-check=none' --cdd /dev/stdin
        ...
        Total Unimodular Cones: ...
        Maximum number of simplicial cones in memory at once: ...
        <BLANKLINE>
        ****  The number of lattice points is:   ****
        Total time: ... sec

    Trivial input for which LattE's preprocessor does all the work::

        sage: P = Polyhedron(vertices=[[0,0,0]])
        sage: cddin = P.cdd_Hrepresentation()
        sage: count(cddin, cdd=True, raw_output=False)  # optional - latte_int
        1

    Testing the runtime error::

        sage: P = Polyhedron(rays=[[0,1], [1,0]])
        sage: cddin = P.cdd_Hrepresentation()
        sage: count(cddin, cdd=True, raw_output=False)  # optional - latte_int
        Traceback (most recent call last):
        ...
        RuntimeError: LattE integrale program failed (exit code 1):
        This is LattE integrale ...
        ...
        The polyhedron is unbounded.
    """
    # Check that LattE is present
    Latte().require()

    arg = str_to_bytes(arg)

    args = ['count']
    if ehrhart_polynomial and multivariate_generating_function:
        raise ValueError
    if ehrhart_polynomial:
        args.append('--ehrhart-polynomial')
    elif multivariate_generating_function:
        args.append('--multivariate-generating-function')

    if 'redundancy_check' not in kwds:
        args.append('--redundancy-check=none')

    for key, value in kwds.items():
        if value is None or value is False:
            continue

        key = key.replace('_', '-')
        if value is True:
            args.append('--{}'.format(key))
        else:
            args.append('--{}={}'.format(key, value))

    if multivariate_generating_function:
        from sage.misc.temporary_file import tmp_filename
        filename = tmp_filename()
        with open(filename, 'w') as f:
            f.write(bytes_to_str(arg))
        args += [filename]
    else:
        args += ['/dev/stdin']

    # The cwd argument is needed because latte
    # always produces diagnostic output files.
    latte_proc = Popen(args,
                       stdin=PIPE,
                       stdout=PIPE,
                       stderr=(None if verbose else PIPE),
                       cwd=str(SAGE_TMP))

    ans, err = latte_proc.communicate(arg)
    if err:
        err = bytes_to_str(err)
    ret_code = latte_proc.poll()
    if ret_code:
        if err is None:
            err = ", see error message above"
        else:
            err = ":\n" + err
        raise RuntimeError(
            "LattE integrale program failed (exit code {})".format(ret_code) +
            err.strip())

    ans = bytes_to_str(ans)

    if ehrhart_polynomial:
        ans = ans.splitlines()[-2]
        if raw_output:
            return ans
        else:
            from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
            from sage.rings.rational_field import QQ
            R = PolynomialRing(QQ, 't')
            return R(ans)
    elif multivariate_generating_function:
        with open(filename + '.rat') as f:
            ans = f.read()
        if raw_output:
            return ans
        else:
            raise NotImplementedError(
                "there is no Sage object to handle multivariate series from LattE, use raw_output=True"
            )
    else:
        if ans:  # Sometimes (when LattE's preproc does the work), no output appears on stdout.
            ans = ans.splitlines()[-1]
        if not ans:
            # opening a file is slow (30e-6s), so we read the file
            # numOfLatticePoints only in case of a IndexError above
            with open(SAGE_TMP + '/numOfLatticePoints', 'r') as f:
                ans = f.read()

        if raw_output:
            return ans
        else:
            return Integer(ans)
示例#42
0
文件: jmoldata.py 项目: Etn40ff/sage
    def export_image(self,
        targetfile,
        datafile, #name (path) of data file Jmol can read or script file telling it what to read or load
        datafile_cmd='script', #"script" or "load"
        image_type ='PNG', #PNG, JPG, GIF
        figsize=5,
        **kwds):
        r"""
        This executes JmolData.jar to make an image file.

        INPUT:

        - targetfile -- the full path to the file where the image
          should be written.

        - datafile -- full path to the data file Jmol can read or
          text of a script telling Jmol what to read or load.

        - datafile_cmd -- (default ``'script'``)  ``'load'`` or ``'script'``
          should be ``"load"`` for a data file.

        - image_type -- (default ``"PNG"``) ``'PNG'`` ``'JPG'`` or ``'GIF'``

        - figsize -- number (default 5) equal to (pixels/side)/100

        OUTPUT:

        Image file, .png, .gif or .jpg (default .png)

        .. note::

            Examples will generate an error message if a functional Java Virtual Machine (JVM)
            is not installed on the machine the Sage instance is running on.

        .. warning::

            Programmers using this module should check that the JVM is
            available before making calls to avoid the user getting
            error messages.  Check for the JVM using the function
            :meth:`is_jvm_available`, which returns True if a JVM is available.

        EXAMPLES:

        Use Jmol to load a pdb file containing some DNA from a web data
        base and make an image of the DNA. If you execute this in the
        notebook, the image will appear in the output cell::

            sage: from sage.interfaces.jmoldata import JmolData
            sage: JData = JmolData()
            sage: script = "load =1lcd;display DNA;moveto 0.0 { -473 -713 -518 59.94} 100.0 0.0 0.0 {21.17 26.72 27.295} 27.544636 {0.0 0.0 0.0} -25.287832 64.8414 0.0;"
            sage: testfile = tmp_filename(ext="DNA.png")
            sage: JData.export_image(targetfile=testfile,datafile=script,image_type="PNG")  # optional -- java internet
            sage: print os.path.exists(testfile)  # optional -- java internet
            True

        Use Jmol to save an image of a 3-D object created in Sage.
        This method is used internally by plot3d to generate static images.
        This example doesn't have correct scaling::

            sage: from sage.interfaces.jmoldata import JmolData
            sage: JData = JmolData()
            sage: D=dodecahedron()
            sage: from sage.misc.misc import SAGE_TMP
            sage: archive_name=os.path.join(SAGE_TMP, "archive.jmol.zip")
            sage: D.export_jmol(archive_name)  #not scaled properly...need some more steps.
            sage: testfile = os.path.join(SAGE_TMP, "testimage.png")
            sage: script = 'set defaultdirectory "%s"\n script SCRIPT\n'%archive_name
            sage: JData.export_image(targetfile =testfile,datafile = script, image_type="PNG") # optional -- java
            sage: print os.path.exists(testfile) # optional -- java
            True

        """
        # Set up paths, file names and scripts
        jmolpath = os.path.join(SAGE_LOCAL, "share", "jmol", "JmolData.jar")
        launchscript = ""
        if (datafile_cmd!='script'):
            launchscript = "load "
        launchscript = launchscript + datafile
        imagescript = "write "+ image_type +" "+targetfile+"\n"

        sizeStr = "%sx%s" %(figsize*100,figsize*100)
        # Scratch file for Jmol errors
        scratchout = tmp_filename(ext=".txt")
        with open(scratchout, 'w') as jout:
            # Now call the java application and write the file.
            subprocess.call(["java", "-Xmx512m", "-Djava.awt.headless=true",
                "-jar", jmolpath, "-iox", "-g", sizeStr,
                "-J", launchscript, "-j", imagescript], stdout=jout, stderr=jout)
        if not os.path.isfile(targetfile):
            raise RuntimeError("Jmol failed to create file %s, see %s for details"%(repr(targetfile), repr(scratchout)))
        os.unlink(scratchout)
示例#43
0
def gen_html_code(G,
                  vertex_labels=True,
                  edge_labels=False,
                  vertex_partition=[],
                  vertex_colors=None,
                  edge_partition=[],
                  force_spring_layout=False,
                  charge=-120,
                  link_distance=30,
                  link_strength=2,
                  gravity=.04,
                  vertex_size=7,
                  edge_thickness=4):
    r"""
    Creates a .html file showing the graph using `d3.js <http://d3js.org/>`_.

    This function returns the name of the .html file. If you want to visualize
    the actual graph use :meth:`~sage.graphs.generic_graph.GenericGraph.show`.

    INPUT:

    - ``G`` -- the graph

    - ``vertex_labels`` -- boolean (default: ``False``); whether to display
      vertex labels

    - ``edge_labels`` -- boolean (default: ``False``); whether to display edge
      labels

    - ``vertex_partition`` -- list (default: ``[]``); a list of lists
      representing a partition of the vertex set. Vertices are then colored in
      the graph according to the partition

    - ``vertex_colors`` -- dict (default: ``None``); a dictionary representing a
      partition of the vertex set. Keys are colors (ignored) and values are
      lists of vertices. Vertices are then colored in the graph according to the
      partition

    - ``edge_partition`` -- list (default: ``[]``); same as
      ``vertex_partition``, with edges instead

    - ``force_spring_layout`` -- boolean (default: ``False``); whether to take
      previously computed position of nodes into account if there is one, or to
      compute a spring layout

    - ``vertex_size`` -- integer (default: ``7``); the size of a vertex' circle

    - ``edge_thickness`` -- integer (default: ``4``); thickness of an edge

    - ``charge`` -- integer (default: ``-120``); the vertices' charge. Defines
      how they repulse each other. See
      `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more
      information

    - ``link_distance`` -- integer (default: ``30``); see
      `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more
      information

    - ``link_strength`` -- integer (default: ``2``); see
      `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more
      information

    - ``gravity`` -- float (default: ``0.04``); see
      `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more
      information

    .. WARNING::

        Since the d3js package is not standard yet, the javascript is fetched
        from d3js.org website by the browser. If you want to avoid that (e.g.
        to protect your privacy or by lack of internet connection), you can
        install the d3js package for offline use by running ``sage -i d3js``
        from the command line.

    EXAMPLES::

        sage: graphs.RandomTree(50).show(method="js") # optional -- internet

        sage: g = graphs.PetersenGraph()
        sage: g.show(method="js", vertex_partition=g.coloring()) # optional -- internet

        sage: graphs.DodecahedralGraph().show(method="js", force_spring_layout=True) # optional -- internet

        sage: graphs.DodecahedralGraph().show(method="js") # optional -- internet

        sage: g = digraphs.DeBruijn(2, 2)
        sage: g.allow_multiple_edges(True)
        sage: g.add_edge("10", "10", "a")
        sage: g.add_edge("10", "10", "b")
        sage: g.add_edge("10", "10", "c")
        sage: g.add_edge("10", "10", "d")
        sage: g.add_edge("01", "11", "1")
        sage: g.show(method="js", vertex_labels=True,edge_labels=True,
        ....:        link_distance=200, gravity=.05, charge=-500,
        ....:        edge_partition=[[("11", "12", "2"), ("21", "21", "a")]],
        ....:        edge_thickness=4) # optional -- internet

    TESTS::

        sage: from sage.graphs.graph_plot_js import gen_html_code
        sage: filename = gen_html_code(graphs.PetersenGraph())

    :trac:`17370`::

        sage: filename = gen_html_code(graphs.CompleteBipartiteGraph(4, 5))

    In the generated html code, the source (resp. target) of a link is the index
    of the node in the list defining the names of the nodes. We check that the
    order is correct (:trac:`27460`)::

        sage: filename = gen_html_code(DiGraph({1: [10]}))
        sage: with open(filename, 'r') as f:
        ....:     data = f.read()
        sage: nodes = data.partition('"nodes":')[2]; nodes
        ...[{..."name": "10"...}, {..."name": "1"...}]...
        sage: links = data.partition('"links":')[2]
        sage: '"source": 1' in links and '"target": 0' in links
        True
    """
    directed = G.is_directed()
    multiple_edges = G.has_multiple_edges()

    # Associated an integer to each vertex
    v_to_id = {v: i for i, v in enumerate(G)}

    # Vertex colors
    if vertex_colors is not None:
        vertex_partition = list(vertex_colors.values())
    len_vertex_partition = len(vertex_partition)
    color = {i: len_vertex_partition for i in range(G.order())}
    for i, l in enumerate(vertex_partition):
        for v in l:
            color[v_to_id[v]] = i

    # Vertex list
    # Data for vertex v must be at position v_to_id[v] in list nodes
    nodes = [{"name": str(v), "group": str(color[v_to_id[v]])} for v in G]

    # Edge colors.
    edge_color_default = "#aaa"
    color_list = rainbow(len(edge_partition))
    edge_color = {}
    for i, l in enumerate(edge_partition):
        for e in l:
            u, v, label = e if len(e) == 3 else e + (None, )
            edge_color[u, v, label] = color_list[i]
            if not directed:
                edge_color[v, u, label] = color_list[i]

    # Edge list
    edges = []
    seen = {}  # How many times has this edge been seen ?

    for u, v, l in G.edge_iterator():

        # Edge color
        color = edge_color.get((u, v, l), edge_color_default)

        # Computes the curve of the edge
        curve = 0

        # Loop ?
        if u == v:
            seen[u, v] = seen.get((u, v), 0) + 1
            curve = seen[u, v] * 10 + 10

        # For directed graphs, one also has to take into accounts
        # edges in the opposite direction
        elif directed:
            if G.has_edge(v, u):
                seen[u, v] = seen.get((u, v), 0) + 1
                curve = seen[u, v] * 15
            else:
                if multiple_edges and len(G.edge_label(u, v)) != 1:
                    # Multiple edges. The first one has curve 15, then
                    # -15, then 30, then -30, ...
                    seen[u, v] = seen.get((u, v), 0) + 1
                    curve = (1 if seen[u, v] % 2 else -1) * (seen[u, v] //
                                                             2) * 15

        elif not directed and multiple_edges:
            # Same formula as above for multiple edges
            if len(G.edge_label(u, v)) != 1:
                seen[u, v] = seen.get((u, v), 0) + 1
                curve = (1 if seen[u, v] % 2 else -1) * (seen[u, v] // 2) * 15

        # Adding the edge to the list
        # The source (resp. target) is the index of u (resp. v) in list nodes
        edges.append({
            "source": v_to_id[u],
            "target": v_to_id[v],
            "strength": 0,
            "color": color,
            "curve": curve,
            "name": str(l) if edge_labels else ""
        })

    loops = [e for e in edges if e["source"] == e["target"]]
    edges = [e for e in edges if e["source"] != e["target"]]

    # Defines the vertices' layout if possible
    Gpos = G.get_pos()
    pos = []
    if Gpos is not None and force_spring_layout is False:
        charge = 0
        link_strength = 0
        gravity = 0

        for v in G:
            x, y = Gpos[v]
            pos.append([float(x), float(-y)])

    # Encodes the data as a JSON string
    from json import JSONEncoder
    string = JSONEncoder().encode({
        "nodes": nodes,
        "links": edges,
        "loops": loops,
        "pos": pos,
        "directed": G.is_directed(),
        "charge": int(charge),
        "link_distance": int(link_distance),
        "link_strength": int(link_strength),
        "gravity": float(gravity),
        "vertex_labels": bool(vertex_labels),
        "edge_labels": bool(edge_labels),
        "vertex_size": int(vertex_size),
        "edge_thickness": int(edge_thickness)
    })

    from sage.env import SAGE_EXTCODE, SAGE_SHARE
    js_code_file = open(SAGE_EXTCODE + "/graphs/graph_plot_js.html", 'r')
    js_code = js_code_file.read().replace("// GRAPH_DATA_HEREEEEEEEEEEE",
                                          string)
    js_code_file.close()

    # Add d3.js script depending on whether d3js package is installed.
    d3js_filepath = os.path.join(SAGE_SHARE, 'd3js', 'd3.min.js')
    if os.path.exists(d3js_filepath):
        with open(d3js_filepath, 'r') as d3js_code_file:
            d3js_script = '<script>' + d3js_code_file.read() + '</script>'
    else:
        d3js_script = '<script src="http://d3js.org/d3.v3.min.js"></script>'
    js_code = js_code.replace('// D3JS_SCRIPT_HEREEEEEEEEEEE', d3js_script)

    # Writes the temporary .html file
    filename = tmp_filename(ext='.html')
    f = open(filename, 'w')
    f.write(js_code)
    f.close()

    return filename