This repo is basically deprecated. However, work is continuing at https://github.com/sagemathinc/cowasm/tree/main/sagemath
"Something like the Python-based SageMath, but for the Javascript world."
You should have Node version 16.x installed. All the compiled code is WebAssembly, so it should work on any computer with Node 16.x installed and install very quickly; in particular, nothing needs to be compiled when installing.
> npm install @jsage/jpython
> npx jsage # or npx jpython for no preparser
Welcome to JSage. Using Node.js v16.13.0.
Type dir(jsage) for available functions.
jsage: list([2 .. 2^3])
[2, 3, 4, 5, 6, 7, 8]
jsage: 2/3 + 4/5
22/15
jsage: dir(jsage)
['ComplexNumber', 'dims', 'P1List', 'ManinSymbols', 'EllipticCurve', 'factor', 'arith', 'Integer', 'ZZ', 'Rational', 'QQ', 'pari', 'misc', 'Number', 'init']
jsage: dims.dimensionCuspForms(389)
32
jsage: E = EllipticCurve('389a'); E
EllipticCurve([0, 1, 1, -2, 0])
jsage: E.analyticRank()
2
jsage: E.conductor()
389
jsage: E.anlist(20)
[0, 1, -2, -2, 2, -3, 4, -5, 0, 1, 6, -4, -4, -3, 10, 6, -4, -6, -2, 5, -6]
jsage: %time v = E.anlist(10^5);
Wall time: 170ms
jsage: M = ManinSymbols(389); P = M.presentation(1009); t = P.heckeOperator(2);
jsage: t.fcp()
[x + 2 2]
[x + 439 2]
...
[x^4 + 298*x^3 + 873*x^2 + 507*x + 325 2]
[x^9 + 347*x^8 + 408*x^7 + 343*x^6 + 673*x^5 + 219*x^4 + 736*x^3 + 475*x^2 + 326*x + 697 2]
jsage: for i in range(4): print(i, 10+i) # jsage is similar to Python...
...
0 10
1 11
2 12
3 13
As explained below, it's also pretty easy to build JSage from source. We fully support building and developing natively using x86_64 and aarch64 Linux, and Intel and M1 MacOS. There's also a Docker build recipe.
The name "JSage" is meant to suggest a small combination of ideas from Javascript and Sage.
In 2004, I started https://www.sagemath.org/, which has gone on to be very successful in supporting pure mathematics research and teaching. Similar to Ryan Dahl who started node.js, I haven't been deeply involved in the weeds of Sage development for a long time, and also similar to Ryan, I've been thinking what I would do differently if I were to start Sage today in 2021. This is one possible result of mulling over that question lately.
!! Right now I don't claim this is useful for anything at all. It's a "Proof of Concept" !!
Some potential longterm goals are listed below.
SageMath is a very large Python/Cython library that also includes a large number of other mathematical software systems such as PARI and Gap and Singular. Thus part of the goal is to build each of PARI, GAP, etc. using Zig. This could be distributed as a small native Electron app along with a few hundred megabytes of cross-platform WebAssembly and data files. When there's a new release of Sage, the WebAssembly files need to get rebuilt and tested once, and the resulting binary will then support all versions of Linux, Windows, MacOS, and iOS. For iOS we would use a-shell (or simple contribute a free package to a-shell).
- There's probably no way to build R with Zig, so we'll toss it; the Python community has not ended up building stats around rpy2 so this is fine.
- It might be very difficult to build Maxima via ECL (embedded common lisp) for WASM, in which case we will have to change Sage to not depend on Maxima for symbolic computation. We'll see. This is a very challenging project!
Javascript is the most widely deployed language, but there is essentially nothing similar to any part of Sage, Pari, Gap or Singular available natively in their ecosystem. Web applications, Node.js programs, and sandboxed code running via WebAssembly could all benefit from such software.
Modern Javascript runtimes -- in particular, Chrome V8 and Firefox SpiderMonkey -- have good just-in-time (JIT) compilers that optimize a wide range of Javascript code. It could be valuable to combine math research software with the power of Javascript JIT. The Python ecosystem's JIT story is very different than what's available in Javascript. There's Pypy, but it's more "fringe", and it has real performance issues with C extensions. There's also numba, which is amazing for what it is amazing at, but only works for very specific types of code. There's also the new Pyston spinoff from Dropbox.
Compared to Julia, the Javascript JIT's are also impressive due to how quickly and seamlessly it does JIT'ing, since that's a critical requirement for web pages. Sometimes Julia's JIT experience can involve waiting a long time for the JIT to happen before your code runs.
In any case, there may be situations where a program is fairly easy to write using a combination of Javascript and some of the WebAssembly libraries that come out of this project, and Javascript's JIT might also result in a very pleasant experience overall, as compared to other options.
Another experimental project you will find here is jpython
, which is a very lightweight Python-to-Javascript compiler. It makes it possible to write Python code, but benefit from a Javascript JIT and all the functionality we build for WASM above. JPython runs natively in Javascript, so there is no dependence on Python itself (unlike Transcrypt). JPython is a fork of RapydScript, but with very different goals and constraints, e.g., much better conformance with the Python language, support for operator overloading, support for numerical computation, a mode to parse the "Sage preparser" language, and with a lot of what RapydScript does removed (e.g., everything related to frontend UI programming). This barely exists today though!
Making libraries like Pari, NTL, eclib, etc. available to Javascript is just a first step. This project also includes building new tools using modern low-level high-performance languages like Zig.
Unlike Julia or Oscar, this project does not attempt to directly compete with SageMath. Indeed, one of the goals is to provide a distribution of SageMath that is easier to use, and another goal is to make the components of Sage and ultimately much of the core Sage library efficiently usable in more situations (e.g., node.js, web browsers, etc.). This project is thus about enriching the mathematical software ecosystem and expanding it beyond Python.
- Node.js at least version 16.x: the
node
in your path must be this recent version of node.js, which is very easy to install on most computers. - Standard build tools: e.g., git, make, curl, m4, etc. For Linux see the Dockerfile remark below, and for macOS, just make sure to install XCode which includes all this.
- This Dockerfile automates building JSage from source on Ubuntu Linux 20.04. It fully works on both x86_64 and aarch64 Linux, and looking at it might answer any questions about build dependencies. Also, if you're having trouble building JSage and have Docker installed, you could instead do
make docker
and build this Docker image locally.
- This Dockerfile automates building JSage from source on Ubuntu Linux 20.04. It fully works on both x86_64 and aarch64 Linux, and looking at it might answer any questions about build dependencies. Also, if you're having trouble building JSage and have Docker installed, you could instead do
- Tested Platforms: I've tested building on the following platforms:
- x86_64 and aarch64 Linux -- via the Dockerfile above
- macOS 12.x with Apple Silicon, and XCode installed (to provide make, git, etc.)
- x86_64 Linux as in any CoCalc project with network access.
- Microsoft Windows via WSL -- works fine, at least using Ubuntu (the default) after
apt install
the packages in the Dockerfile.
The build takes on the order of one hour or so.
Just type "make"
...$ make
This runs a single top level makefile to build all the packages. The build process for all individual packages is also accomplished using a Makefile. We don't use shell scripts or Python code to orchestrate building anything, since make
is much cleaner and easier to read, maintain and debug.
In most subdirectories foo
of packages, this will create some subdirectories:
packages/foo/dist/[native|wasm]
-- a native or WebAssembly build of the package; this has binaries, headers, and libs. These get used by other packages.packages/build/[native|wasm]
- build artifacts for the native or WebAssembly build; can be safely deleted
I have put a lot of work into getting various things to build, e.g., NTL, FLINT, Python, which are currently not needed as a dependency for the core library I find myself building. Thus they are now NOT being built by default, since they aren't needed. Really all we need so far to build what we want to build is JPython (a Python language->Javascript compiler), GMP and Pari. It's amazing how much functionality Pari has built in, which overall is much broader (but less deep in some ways) than what's available in the C/C++ ecosystem of NTL/FLINT, etc. For our purposes though (of something very cross platform and easy to maintain!), Pari is really ideal.
That said, I put a lot of work into these other packages, and maybe they will be important at some point. But don't expect them to just work.
Unlike SageMath, where everything is built into a single local
directory, here we build everything in its own self-contained package. When a package like pari
depends on another package like gmp
, our Makefile for pari
explicitly references the dist
directory in the packages/dist/gmp
. This makes it possible to uninstall packages, update them, etc., whereas using a common directory for everything can be a mess with possibly conflicting versions of files.
The build creates directories dist/native and dist/wasm. The dist/native
artifacts are only of value on the computer where you ran the build, since they are architecture dependent and can easily depend on libraries on your system. In contrast, the dist/wasm
artifacts are platform independent. They can be used nearly everywhere: on servers via WASM, on ARM computers (e.g., aarch64 linux, Apple Silicon, etc.), and in any modern web browser (though many details remain, obviously).
Email [email protected] if you find this interesting and want to help out. This is all as open source as possible, given what each dependency allows. This is right now entirely a "project for fun and exploration" with no real constraints.