about summary refs log tree commit diff
path: root/nixpkgs/pkgs/applications/science/math/sage/default.nix
blob: 6624dcc36528b33708bdd4b6afcd7008cd3ad7fa (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
{ pkgs
, withDoc ? false
, requireSageTests ? true
, extraPythonPackages ? ps: []
}:

# Here sage and its dependencies are put together. Some dependencies may be pinned
# as a last resort. Patching sage for compatibility with newer dependency versions
# is always preferred, see `sage-src.nix` for that.

let
  inherit (pkgs) symlinkJoin callPackage nodePackages;

  python3 = pkgs.python3 // {
    pkgs = pkgs.python3.pkgs.overrideScope (self: super: {
      # `sagelib`, i.e. all of sage except some wrappers and runtime dependencies
      sagelib = self.callPackage ./sagelib.nix {
        inherit flint3;
        inherit sage-src env-locations singular;
        inherit (maxima) lisp-compiler;
        linbox = pkgs.linbox.override { withSage = true; };
        pkg-config = pkgs.pkg-config; # not to confuse with pythonPackages.pkg-config
      };

      sage-docbuild = self.callPackage ./python-modules/sage-docbuild.nix {
        inherit sage-src;
      };

      sage-setup = self.callPackage ./python-modules/sage-setup.nix {
        inherit sage-src;
      };
    });
  };

  # matches src/sage/repl/ipython_kernel/install.py:kernel_spec
  jupyter-kernel-definition = {
    displayName = "SageMath ${sage-src.version}";
    argv = [
      "${sage-with-env}/bin/sage" # FIXME which sage
      "--python"
      "-m"
      "sage.repl.ipython_kernel"
      "-f"
      "{connection_file}"
    ];
    language = "sage";
    # just one 16x16 logo is available
    logo32 = "${sage-src}/src/doc/common/themes/sage/static/sageicon.png";
    logo64 = "${sage-src}/src/doc/common/themes/sage/static/sageicon.png";
  };

  jupyter-kernel-specs = pkgs.jupyter-kernel.create {
    definitions = pkgs.jupyter-kernel.default // {
      sagemath = jupyter-kernel-definition;
    };
  };

  three = callPackage ./threejs-sage.nix { };

  # A bash script setting various environment variables to tell sage where
  # the files its looking fore are located. Also see `sage-env`.
  env-locations = callPackage ./env-locations.nix {
    inherit pari_data;
    inherit singular maxima;
    inherit three;
    cysignals = python3.pkgs.cysignals;
    mathjax = nodePackages.mathjax;
  };

  # The shell file that gets sourced on every sage start. Will also source
  # the env-locations file.
  sage-env = callPackage ./sage-env.nix {
    sagelib = python3.pkgs.sagelib;
    sage-docbuild = python3.pkgs.sage-docbuild;
    inherit env-locations;
    inherit python3 singular palp flint3 pythonEnv maxima;
    pkg-config = pkgs.pkg-config; # not to confuse with pythonPackages.pkg-config
  };

  # The documentation for sage, building it takes a lot of ram.
  sagedoc = callPackage ./sagedoc.nix {
    inherit sage-with-env jupyter-kernel-specs;
  };

  # sagelib with added wrappers and a dependency on sage-tests to make sure thet tests were run.
  sage-with-env = callPackage ./sage-with-env.nix {
    inherit python3 pythonEnv;
    inherit sage-env;
    inherit singular maxima;
    inherit three;
    pkg-config = pkgs.pkg-config; # not to confuse with pythonPackages.pkg-config
  };

  # Doesn't actually build anything, just runs sages testsuite. This is a
  # separate derivation to make it possible to re-run the tests without
  # rebuilding sagelib (which takes ~30 minutes).
  # Running the tests should take something in the order of 1h.
  sage-tests = callPackage ./sage-tests.nix {
    inherit sage-with-env;
  };

  sage-src = callPackage ./sage-src.nix {};

  pythonRuntimeDeps = with python3.pkgs; [
    sagelib
    sage-docbuild
    cvxopt
    networkx
    service-identity
    psutil
    sympy
    fpylll
    matplotlib
    tkinter # optional, as a matplotlib backend (use with `%matplotlib tk`)
    scipy
    ipywidgets
    notebook # for "sage -n"
    rpy2
    sphinx
    pillow
  ] ++ extraPythonPackages python3.pkgs;

  pythonEnv = python3.buildEnv.override {
    extraLibs = pythonRuntimeDeps;
    ignoreCollisions = true;
  } // { extraLibs = pythonRuntimeDeps; }; # make the libs accessible

  singular = pkgs.singular.override { inherit flint3; };

  maxima = pkgs.maxima-ecl.override {
    lisp-compiler = pkgs.ecl.override {
      # "echo syntax error | ecl > /dev/full 2>&1" segfaults in
      # ECL. We apply a patch to fix it (write_error.patch), but it
      # only works if threads are disabled.  sage 9.2 tests this
      # (src/sage/interfaces/tests.py) and ships ecl like so.
      # https://gitlab.com/embeddable-common-lisp/ecl/-/merge_requests/1#note_1657275
      threadSupport = false;

      # if we don't use the system boehmgc, sending a SIGINT to ecl
      # can segfault if we it happens during memory allocation.
      # src/sage/libs/ecl.pyx would intermittently fail in this case.
      useBoehmgc = true;
    };
  };

  # With openblas (64 bit), the tests fail the same way as when sage is build with
  # openblas instead of openblasCompat. Apparently other packages somehow use flints
  # blas when it is available. Alternative would be to override flint to use
  # openblasCompat.
  flint3 = pkgs.flint3.override { withBlas = false; };

  # Multiple palp dimensions need to be available and sage expects them all to be
  # in the same folder.
  palp = symlinkJoin {
    name = "palp-${pkgs.palp.version}";
    paths = [
      (pkgs.palp.override { dimensions = 4; doSymlink = false; })
      (pkgs.palp.override { dimensions = 5; doSymlink = false; })
      (pkgs.palp.override { dimensions = 6; doSymlink = true; })
      (pkgs.palp.override { dimensions = 11; doSymlink = false; })
    ];
  };

  # Sage expects those in the same directory.
  pari_data = symlinkJoin {
    name = "pari_data";
    paths = with pkgs; [
      pari-galdata
      pari-seadata-small
    ];
  };
in
# A wrapper around sage that makes sure sage finds its docs (if they were build).
callPackage ./sage.nix {
  inherit sage-tests sage-with-env sagedoc jupyter-kernel-definition jupyter-kernel-specs;
  inherit withDoc requireSageTests;
}