Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
mkoeppe committed Oct 7, 2021
2 parents 64528df + 654d09c commit 555bee7
Show file tree
Hide file tree
Showing 18 changed files with 257 additions and 94 deletions.
1 change: 1 addition & 0 deletions build/pkgs/4ti2/distros/arch.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
4ti2
1 change: 1 addition & 0 deletions build/pkgs/4ti2/distros/cygwin.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lib4ti2-devel
1 change: 1 addition & 0 deletions build/pkgs/4ti2/distros/debian.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
4ti2
1 change: 1 addition & 0 deletions build/pkgs/4ti2/distros/fedora.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
4ti2
1 change: 1 addition & 0 deletions build/pkgs/4ti2/distros/freebsd.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
math/4ti2
1 change: 1 addition & 0 deletions build/pkgs/4ti2/distros/gentoo.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sci-mathematics/4ti2
32 changes: 32 additions & 0 deletions build/pkgs/4ti2/spkg-configure.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
SAGE_SPKG_CONFIGURE([4ti2], [
SAGE_SPKG_DEPCHECK([gmp mpir glpk zlib], [
dnl Debian installs these programs with an executable prefix "4ti2-",
dnl OpenSUSE uses the prefix "4ti2_".
dnl Singular checks for unprefixed and prefixed with "4ti2-".
dnl Polymake does not check for prefixed binaries.
m4_foreach([prog], [hilbert,markov,graver,zsolve,qsolve,rays,ppi,circuits,groebner], [
AC_CHECK_PROGS([FOURTITWO_]m4_toupper(prog), prog [4ti2-]prog [4ti2_]prog)
AS_VAR_IF([FOURTITWO_]m4_toupper(prog), [""], [sage_spkg_install_4ti2=yes])
AC_SUBST([FOURTITWO_]m4_toupper(prog))
])
dnl Adapted from https://github.com/latte-int/latte/blob/master/m4/4ti2-check.m4
AC_MSG_CHECKING(for library 4ti2gmp)
BACKUP_CXXFLAGS=${CXXFLAGS}
BACKUP_LIBS=${LIBS}
FORTYTWO_CXXFLAGS="-D__STDC_LIMIT_MACROS -D_4ti2_GMP_"
FORTYTWO_LIBS="-l4ti2gmp -lzsolve"
CXXFLAGS="${BACKUP_CXXFLAGS} ${FORTYTWO_CXXFLAGS} ${GMP_CFLAGS}"
LIBS="${BACKUP_LIBS} ${FORTYTWO_LIBS} ${GMP_LIBS}"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include "4ti2/4ti2.h"
]], [[ _4ti2_rays_create_state(_4ti2_PREC_INT_ARB);
]])],[
AC_MSG_RESULT([yes])
],[
AC_MSG_RESULT([no])
sage_spkg_install_4ti2=yes
])
CXXFLAGS=${BACKUP_CXXFLAGS}
LIBS=${BACKUP_LIBS}
])
])
11 changes: 11 additions & 0 deletions pkgs/sage-conf/sage_conf.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ ECL_CONFIG = "@SAGE_ECL_CONFIG@".replace('${prefix}', SAGE_LOCAL)

SAGE_NAUTY_BINS_PREFIX = "@SAGE_NAUTY_BINS_PREFIX@"

# Names or paths of the 4ti2 executables
FOURTITWO_HILBERT = "@FOURTITWO_HILBERT@"
FOURTITWO_MARKOV = "@FOURTITWO_MARKOV@"
FOURTITWO_GRAVER = "@FOURTITWO_GRAVER@"
FOURTITWO_ZSOLVE = "@FOURTITWO_ZSOLVE@"
FOURTITWO_QSOLVE = "@FOURTITWO_QSOLVE@"
FOURTITWO_RAYS = "@FOURTITWO_RAYS@"
FOURTITWO_PPI = "@FOURTITWO_PPI@"
FOURTITWO_CIRCUITS = "@FOURTITWO_CIRCUITS@"
FOURTITWO_GROEBNER = "@FOURTITWO_GROEBNER@"

# Colon-separated list of pkg-config modules to search for cblas functionality.
# We hard-code it here as cblas because configure (build/pkgs/openblas/spkg-configure.m4)
# always provides cblas.pc, if necessary by creating a facade pc file for a system BLAS.
Expand Down
4 changes: 2 additions & 2 deletions src/sage/doctest/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,8 +407,8 @@ def __init__(self, options, args):
from sage.features import package_systems
options.optional.update(system.name for system in package_systems())

from sage.features.sagemath import sage_optional_tags
options.optional.update(sage_optional_tags())
from sage.features.sagemath import sage_features
options.optional.update(feature.name for feature in sage_features())

# Check that all tags are valid
for o in options.optional:
Expand Down
16 changes: 15 additions & 1 deletion src/sage/doctest/external.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,19 @@ def has_rubiks():
from sage.features.rubiks import Rubiks
return Rubiks().is_present()

def has_4ti2():
"""
Test if the 4ti2 package is available.
EXAMPLES::
sage: from sage.doctest.external import has_4ti2
sage: has_4ti2() # optional -- 4ti2
FeatureTestResult('4ti2', True)
"""
from sage.features.four_ti_2 import FourTi2
return FourTi2().is_present()

def external_software():
"""
Return the alphabetical list of external software supported by this module.
Expand Down Expand Up @@ -346,7 +359,8 @@ class AvailableSoftware(object):
sage: from sage.doctest.external import external_software, available_software
sage: external_software
['cplex',
['4ti2',
'cplex',
'ffmpeg',
'graphviz',
'gurobi',
Expand Down
2 changes: 1 addition & 1 deletion src/sage/doctest/reporting.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def have_optional_tag(self, tag):
False
"""
if tag in self.controller.options.optional:
if self.controller.options.optional is True or tag in self.controller.options.optional:
return True
if 'external' in self.controller.options.optional:
if tag in available_software.seen():
Expand Down
9 changes: 9 additions & 0 deletions src/sage/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,15 @@ def var(key: str, *fallbacks: Optional[str], force: bool = False) -> Optional[st
MAXIMA_FAS = var("MAXIMA_FAS")
KENZO_FAS = var("KENZO_FAS")
SAGE_NAUTY_BINS_PREFIX = var("SAGE_NAUTY_BINS_PREFIX", "")
FOURTITWO_HILBERT = var("FOURTITWO_HILBERT")
FOURTITWO_MARKOV = var("FOURTITWO_MARKOV")
FOURTITWO_GRAVER = var("FOURTITWO_GRAVER")
FOURTITWO_ZSOLVE = var("FOURTITWO_ZSOLVE")
FOURTITWO_QSOLVE = var("FOURTITWO_QSOLVE")
FOURTITWO_RAYS = var("FOURTITWO_RAYS")
FOURTITWO_PPI = var("FOURTITWO_PPI")
FOURTITWO_CIRCUITS = var("FOURTITWO_CIRCUITS")
FOURTITWO_GROEBNER = var("FOURTITWO_GROEBNER")
ARB_LIBRARY = var("ARB_LIBRARY", "arb")
CBLAS_PC_MODULES = var("CBLAS_PC_MODULES", "cblas:openblas:blas")
ECL_CONFIG = var("ECL_CONFIG", "ecl-config")
Expand Down
32 changes: 32 additions & 0 deletions src/sage/features/four_ti_2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from . import Executable
from .join_feature import JoinFeature


class FourTi2Executable(Executable):
r"""
Feature for the 4ti2 executables.
"""
def __init__(self, name):
from sage.env import SAGE_ENV
Executable.__init__(self,
name="4ti2-" + name,
executable=SAGE_ENV.get("FOURTITWO_" + name.upper(), None) or name,
spkg="4ti2")


class FourTi2(JoinFeature):
r"""
A :class:`sage.features.Feature` describing the presence of the ``4ti2`` executables.
EXAMPLES::
sage: from sage.features.four_ti_2 import FourTi2
sage: FourTi2().is_present() # optional - 4ti2
FeatureTestResult('4ti2', True)
"""
def __init__(self):
JoinFeature.__init__(self, '4ti2',
[FourTi2Executable(x)
# same list is tested in build/pkgs/4ti2/spkg-configure.m4
for x in ('hilbert', 'markov', 'graver', 'zsolve', 'qsolve',
'rays', 'ppi', 'circuits', 'groebner')])
82 changes: 82 additions & 0 deletions src/sage/features/join_feature.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
r"""
Join features
"""

from . import Feature, FeatureTestResult


class JoinFeature(Feature):
r"""
Join of several :class:`sage.features.Feature` instances.
EXAMPLES::
sage: from sage.features import Executable
sage: from sage.features.join_feature import JoinFeature
sage: F = JoinFeature("shell-boolean",
....: (Executable('shell-true', 'true'),
....: Executable('shell-false', 'false')))
sage: F.is_present()
FeatureTestResult('shell-boolean', True)
sage: F = JoinFeature("asdfghjkl",
....: (Executable('shell-true', 'true'),
....: Executable('xxyyyy', 'xxyyyy-does-not-exist')))
sage: F.is_present()
FeatureTestResult('xxyyyy', False)
"""
def __init__(self, name, features, spkg=None, url=None):
"""
TESTS:
The empty join feature is present::
sage: from sage.features.join_feature import JoinFeature
sage: JoinFeature("empty", ()).is_present()
FeatureTestResult('empty', True)
"""
if spkg is None:
spkgs = set(f.spkg for f in features if f.spkg)
if len(spkgs) > 1:
raise ValueError('given features have more than one spkg; provide spkg argument')
elif len(spkgs) == 1:
spkg = next(iter(spkgs))
if url is None:
urls = set(f.url for f in features if f.url)
if len(urls) > 1:
raise ValueError('given features have more than one url; provide url argument')
elif len(urls) == 1:
url = next(iter(urls))
super().__init__(name, spkg=spkg, url=url)
self._features = features

def _is_present(self):
r"""
Test for the presence of the join feature.
EXAMPLES::
sage: from sage.features.latte import Latte
sage: Latte()._is_present() # optional - latte_int
FeatureTestResult('LattE', True)
"""
for f in self._features:
test = f._is_present()
if not test:
return test
return FeatureTestResult(self, True)

def is_functional(self):
r"""
Test whether the join feature is functional.
EXAMPLES::
sage: from sage.features.latte import Latte
sage: Latte().is_functional() # optional - latte_int
FeatureTestResult('LattE', True)
"""
for f in self._features:
test = f.is_functional()
if not test:
return test
return FeatureTestResult(self, True)
42 changes: 5 additions & 37 deletions src/sage/features/latte.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
Check for LattE
"""
from . import Executable, Feature, FeatureTestResult
from .join_feature import JoinFeature


LATTE_URL = "https://www.math.ucdavis.edu/~latte/software.php"

Expand All @@ -27,7 +29,7 @@ def __init__(self):
url=LATTE_URL)


class Latte(Feature):
class Latte(JoinFeature):
r"""
A :class:`sage.features.Feature` describing the presence of the ``LattE``
binaries which comes as a part of ``latte_int``.
Expand All @@ -46,39 +48,5 @@ def __init__(self):
sage: isinstance(Latte(), Latte)
True
"""
Feature.__init__(self, "LattE")

def _is_present(self):
r"""
Test for the presence of LattE binaries.
EXAMPLES::
sage: from sage.features.latte import Latte
sage: Latte()._is_present() # optional - latte_int
FeatureTestResult('LattE', True)
"""

test = (Latte_count()._is_present() and
Latte_integrate()._is_present())
if not test:
return test

return FeatureTestResult(self, True)

def is_functional(self):
r"""
Test whether count and integrate are functionals.
EXAMPLES::
sage: from sage.features.latte import Latte
sage: Latte().is_functional() # optional - latte_int
FeatureTestResult('LattE', True)
"""
test = (Latte_count().is_functional() and
Latte_integrate().is_functional())
if not test:
return test

return FeatureTestResult(self, True)
JoinFeature.__init__(self, "LattE",
(Latte_count(), Latte_integrate()))
Loading

0 comments on commit 555bee7

Please sign in to comment.