Skip to content

Commit

Permalink
Docs: review Readme, improvements, restructuring (#128)
Browse files Browse the repository at this point in the history
* Docs: review docs, improvements, restructuring

* Review and improve the readme
* Add folder `advanced` for packages, move Customizing Wolframite there
* Customizing Wolframite: switch from `**` which is now in default aliases to st. that is not, fix code, prove it works
* Add Clojure primer to the menu
* Fix `:start!ed?`
* Readme: improve examples, cleanup redundant sections, etc.

* Fix readme links to work outside of the book.

* Fix help!, improve Wolf 4 clj, bikes util fns

* Quickstart: require w with :refer :all and :excludes

Issue: More convenient Wolframite w/o all the `w/`, but w/o overriding Clojure/Java core stuff.

* Review Quick start & other improvements

* Cust. wolframite - subheading, todo
* Clj primer - REPL intro

* Fix: Re-introduce custom, error-detecting `evaluate`

Somehow it got lost, likely in a botched merged.

* Review, improve Understanding Wolframite

* Add `wl/ns-exclusions` so we can use it in multiple places of the docs; include "assert" mode so that docs will fail if we need to update the exclusions there
* Understanding Wolframite: Make the Eval. form first, add crossrefs, ...

* Review gotchas - fix name, mention `**`

* Review faq

* review wolfram-for-clojurians

* Review for-scientists.index

* Comment on symbols.

* Cavities: simplify code, fix typos

* Readme: Leverage referred wolf syms, drop w/

* fixes
  • Loading branch information
holyjak authored Oct 4, 2024
1 parent 67769fc commit a212939
Show file tree
Hide file tree
Showing 24 changed files with 652 additions and 585 deletions.
104 changes: 48 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

[![Clojars download](https://img.shields.io/clojars/v/org.scicloj/wolframite.svg)](https://clojars.org/org.scicloj/wolframite) [Wolframite sources](https://github.com/scicloj/wolframite/)

An interface between Clojure and the Wolfram Language (Supports [Mathematica](https://www.wolfram.com/mathematica/) and [Wolfram Engine](https://www.wolfram.com/engine/) ).
An interface between Clojure and the Wolfram Language (Supports [Mathematica](https://www.wolfram.com/mathematica/) and [Wolfram Engine](https://www.wolfram.com/engine/)).

## Status

**Wolframite is currently (Q3/2024) under active development again. You can [keep track of what is happening in this discussion](https://github.com/scicloj/wolframite/discussions/17).**
**We are working on wrapping up version 1.0, focusing on documentation. You can [keep track of what is happening in this discussion](https://github.com/scicloj/wolframite/discussions/17).**

## What is Wolframite? ##

Expand All @@ -21,10 +21,19 @@ By linking the two:
* Wolframite provides the **seamless and transparent translation of native data structures** between Clojure and Wolfram. This includes high-precision numbers, matricies, N-dimensional arrays, and evaluated and unevaluated Mathematica expressions and formulae.
* Wolframite lets you **write Wolfram as if it was Clojure** by providing Clojure functions and vars for all Wolfram symbols, including docstrings and autocompletion in your favorite IDE
* [Tentative] Wolframite facilitates **the "Clojurization" of Wolfram's existing parallel-computing capabilities.** Wolfram is not designed for threads or concurrency. It has excellent support for parallel computation, but parallel evaluations are initiated from a single-threaded master kernel which blocks until all parallel evaluations return. By contrast, Wolframite includes a concurrency framework that lets multiple Clojure threads execute Wolfram expressions without blocking others. Now it is easy to run a simulation in Clojure with 1,000 independent threads asynchronously evaluating processor-intensive expressions in Wolfram. The computations will be farmed out adaptively and transparently to however many Wolfram kernels are available on any number of processor cores, either locally or across a cluster, grid, or network.
* Notice that you cannot run more Wolfram kernels than your license allows (see `wolframite/kernel-info!`)
* Notice that you cannot run more Wolfram kernels than your license allows (see the function `(wolframite.core/kernel-info!)`)

Wolframite is open-source and targeted at applications in scientific computing, computational economics, finance, and other fields that rely on the combination of parallelized simulation and high-performance number-crunching. Wolframite gives the programmer access to Clojure's most cutting-edge features--easy concurrency and multithreading, immutable persistent data structures, and software transactional memory---alongside Wolfram's easy-to-use algorithms for numerics, symbolic mathematics, optimization, statistics, visualization, and image-processing.

Wolfram / Mathematica itself is a commercial product and requires a license. Though Wolfram Engine is [free to use in development](https://www.wolfram.com/engine/free-license/).

## Documentation

No matter what is your level of experience with either Clojure or Wolfram, we have you covered!

While this page provides a brief overview of Wolframite assuming some level of knowledge of each of the systems, we have also tutorials targeted at [scientists new to Clojure](https://scicloj.github.io/wolframite/for_scientists.index.html)
and at [Clojure developers new to Wolfram](https://scicloj.github.io/wolframite/for_developers.index.html). However, you should try to read through this page, the [Quickstart](https://scicloj.github.io/wolframite/quickstart.html), and browse through [Understanding Wolframite](https://scicloj.github.io/wolframite/understanding_wolframite.html) before diving into the tutorials. If you have never seen Clojure before, you may want to start with a quick look at our [Clojure Primer](https://scicloj.github.io/wolframite/clojure_primer.index.html) to understand better the rest of the documentation. Remember: you don't need to learn or remember all at once.

## Usage

### Prerequisites:
Expand All @@ -33,9 +42,9 @@ Wolframite is open-source and targeted at applications in scientific computing,

First, if you haven't already, install the [Clojure CLI toolchain](https://clojure.org/guides/getting_started) (homebrew is a great way to do this if you're on Mac or Linux, but you can just as easily use the installation scripts if you prefer).

#### Wolfram (Mathematica) or Wolfram Engine
#### Wolfram Mathematica or Wolfram Engine

Next, obviously, you'll need to ensure that you have Wolfram Engine or the Wolfram desktop app (formerly called Mathematica) installed and your license (free for W. E.) registered - make sure you can run these tools on their own _before_ trying Wolframite.
Next, obviously, you'll need to ensure that you have Wolfram Engine or the Wolfram desktop application (formerly called Mathematica) installed and your license registered. Make sure you can run these tools on their own _before_ trying Wolframite.

First of all, you need to initialize a connection to a Wolfram/Mathematica kernel, like this:

Expand All @@ -46,7 +55,7 @@ This should also find and load the JLink JAR included with your installation. Wa

> === Adding path to classpath: /Applications/Wolfram Engine.app/Contents/Resources/Wolfram Player.app/Contents/SystemFiles/Links/JLink/JLink.jar ===
However, sometimes Wolframite may fail to find the correct path automatically and needs your help. You can set the `WOLFRAM_INSTALL_PATH` environment variable or Java system property (the latter takes priority) to point to the correct location. Example:
However, sometimes Wolframite may fail to find the correct path automatically and needs your help. You can set the `WOLFRAM_INSTALL_PATH` environment variable or Java system property (the latter takes priority) to point to the correct location. Examples:

```shell
export WOLFRAM_INSTALL_PATH=/opt/mathematica/13.1
Expand All @@ -55,87 +64,69 @@ export WOLFRAM_INSTALL_PATH="/Applications/Wolfram Engine.app/Contents/Resources

### Getting started

Start a REPL with Wolframite on the classpath, then initialize it:
Start a [Clojure REPL](https://clojure.org/guides/repl/introduction) with Wolframite on the classpath:

```shell
clj -Sdeps '{:deps {org.scicloj/wolframite {:mvn/version "1.0.0-SNAPSHOT"}}}'
```

and try it out:

```clojure
(require '[wolframite.core :as wl]
'[wolframite.wolfram :as w]) ; Wolfram symbols as Clojure vars / fns
'[wolframite.wolfram :as w :refer :all ; Wolfram symbols as Clojure vars / fns
:exclude [* + - -> / < <= = == > >= fn
Byte Character Integer Number Short String Thread]])
;; Initialize
(wl/start!) ; => nil
(wl/start!) ; => {:status :ok, :wolfram-version 14.1, :started? true}
;; Use it:
(wl/eval (w/Dot [1 2 3] [4 5 6]))
;=> 32
(wl/eval (Dot [2 2 4] [4 5 6]))
;=> 42
```

More examples
More examples:

```clojure
(wl/eval (w/D (w/Power 'x 2) 'x))
(wl/eval (D (Power 'x 2) 'x)) ; derivative
;=> (* 2 x)
(wl/eval (w/ChemicalData "Ethanol" "MolarMass"))
(wl/eval (ChemicalData "Ethanol" "MolarMass"))
;=> (Quantity 46.069M (* "Grams" (Power "Moles" -1)))

;; Accessing WlframAlpha
(wl/eval (w/WolframAlpha "How many licks does it take to get to the center of a Tootsie Pop?")) ; BEWARE: must be online
;=> [(-> [["Input" 1] "Plaintext"] "How many licks does it take to get to the Tootsie Roll center of a Tootsie Pop?") (-> [["Result" 1] "Plaintext"] "3481\n(according to student researchers at the University of Cambridge)")]
;; Accessing WolframAlpha (BEWARE: must be online)
(wl/eval (WolframAlpha "How many licks does it take to get to the center of a Tootsie Pop?"))
;=> [(-> [["Input" 1] "Plaintext"] "How many licks does it take to get to the Tootsie Roll
; center of a Tootsie Pop?") (-> [["Result" 1] "Plaintext"] "3481\n(according to student
; researchers at the University of Cambridge)")]

(wl/eval (w/N w/Pi 20))
(wl/eval (N Pi 20)) ; numerical value with 20 digit precision
;=> 3.141592653589793238462643383279502884197169399375105820285M

(wl/eval (w/Map (w/fn [x] (w/Sqrt x)) [4 16]))
(wl/eval (Map (w/fn [x] (Sqrt x)) [4 16]))
;=> [2 4]
```

TIP: Cursive - teach it to resolve `w/fn` as `clojure.core/fn`.

NOTE: The `wolframite.wolfram` (`w`) ns has vars for all Wolfram symbols at the time of the last release. Check `w/*wolfram-kernel-name*` for kernel type/version and run `(wolframite.impl.wolfram-syms.write-ns/write-ns!)`
NOTE: The `wolframite.wolfram` (`w`) namespace has vars for all Wolfram symbols at the time of the last release of Wolframite. Check `w/*wolfram-kernel-name*` for kernel type/version and run `(wolframite.impl.wolfram-syms.write-ns/write-ns!)`
to generate your own wolfram ns with whatever additional symbols your Wolfram/Mathematice has, and/or with custom "aliases".

#### Learning Wolframite

[Visit our documentation site](https://scicloj.github.io/wolframite/) to learn all you might want to know about using Wolframite.

#### Customizing Wolframite

A big advantage of Wolframite (as opposed to its earlier incarnations) is that we can now individually tailor the user experience at the level of initialization,
```clojure
(wl/start! {:aliases '{** Power}})
(wl/eval '(** 2 5)) ; => 32
```
,
and function call,
```clojure
(wl/start!)
(wl/eval '(** 2 5) {:aliases '{** Power}}) ; => 32
```
. Use it how you want to!

TIP: You can also get convenience vars for your aliases in `wolframite.wolfram` by running
something like
`(wolframite.impl.wolfram-syms.write-ns/write-ns! <path> {:aliases '{** Power}})`. After you load
the file, you'll be able to use `(wl/eval (w/** 2 5) {:aliases '{** Power}})`.

### Clerk Integration

We primarily use [Clay](https://scicloj.github.io/clay/) as our notebook tool, but there is also experimental support for [Clerk](https://github.com/nextjournal/clerk).

Example usage: (watching for changes in a folder)

```
user> (require '[clojuratica.tools.clerk-helper :as ch])
user> (require '[wolframite.tools.clerk-helper :as ch])
user> (ch/clerk-watch! ["dev/notebook"])
```

* Open dev/notebook/quickstart.clj, make a change and save.
* Open `dev/notebook/quickstart.clj`, make a change and save.
* Open `localhost:7777` in the browser

### How does it work?

You compose Wolfram expressions using the convenience functions and vars from `wolframite.wolfram`. These are then turned first into a symbolic representation of themselves and later into a tree of JLink `Expr` objects and sent to a Wolfram kernel subprocess (started by `wl/start`) for evaluation. The result is translated back from jlink.Expr into a Clojure form. This translation allows for some additional convenience logic, such as supporting `w/*` instead of `Times`.

## Dependencies

Wolframite requires Wolfram's Java integration library JLink, which is currently only available with a Wolfram Engine or Mathematica installation. It will also need to know where the `WolframKernel` / `MathKernel` executable is, in order to be able to start the external evaluation kernel process. Normally, `wl/start` should be able to find these automatically, if you installed either into a standard location on Mac, Linux or Windows. However, if necessary, you can specify either with env variables / sys properties - see Prerequisites above.
You compose Wolfram expressions using the convenience functions and vars from `wolframite.wolfram`. These are then turned first into a symbolic representation of themselves and later into a tree of JLink `Expr` objects and sent to a Wolfram kernel subprocess (started by `wl/start!`) for evaluation. The result is translated back from jlink.Expr into a Clojure form. This translation allows for some additional convenience logic, such as supporting `w/*` instead of `Times`.

## Development

Expand All @@ -151,7 +142,7 @@ clojure -X:run-tests
### Deployment

Build the jar with `clojure -T:build jar` then deploy with
`env CLOJARS_USERNAME=<tbd> CLOJARS_PASSWORD=<clojars-token> clojure -T:build deploy`
`env CLOJARS_USERNAME=<tbd> CLOJARS_PASSWORD=<clojars-token> clojure -T:build deploy`.

Note: You need to log in to Clojars and generate a deployment token. You also need to be added to
the SciCloj group there by an admin.
Expand All @@ -160,21 +151,22 @@ Consider studying Wolfram's guide [Writing Java Programs That Use the Wolfram La
[WSTP and External Program Communication](https://reference.wolfram.com/language/tutorial/WSTPAndExternalProgramCommunicationOverview.html)
when you want to dig into the JVM ↔ Wolfram communication.

#### Documentation
#### Writing documentation

Documentation is written as literal programming sources in the `notebooks` directory and turned into HTML
under `docs` using [Clay](https://scicloj.github.io/clay/)
and [Quarto](https://quarto.org/).

To render a single namespace/page, require Clay and run `(clay/make! {:source-path "<path to the file>""})`. Tip: You can also do this without quarto - just add `:run-quarto false` to the options.

To build the whole site, run `clojure -T:build build-site` (remembering to ensure that you have a ./symlink-jlink.jar symlink).
To build the whole site, run `clojure -T:build build-site` (remembering to ensure that you have the `./symlink-jlink.jar` symlink).

## Authors

The original Clojuratica, Wolframite's predecessor, was created by Garth Sheldon-Coulson, a graduate student at the Massachusetts Institute of Technology and Harvard Law School.

Ongoing maintenance and development over the years have been thanks to

* [Steve Chan](https://github.com/chanshunli),
* [Dan Farmer](https://github.com/dfarmer),
* [Norman Richards](https://github.com/orb)
Expand All @@ -198,11 +190,11 @@ version = {1.0.0-SNAPSHOT},
year = {2024}
```
## Support
## Sponsorship
We are grateful for the financial support of [Clojurists Together](https://www.clojuriststogether.org/), who supported this work for a quarter in 2024.

## Contact
If you would like to contact the maintainers or otherwise seek help from the community then please drop a message into our [zulip channel](https://clojurians.zulipchat.com/#narrow/stream/313853-wolfram-clojure-bridge) or contact the team at [SciCloj](https://github.com/scicloj).
If you would like to contact the maintainers or otherwise seek help from the community then please drop a message into our [zulip channel](https://clojurians.zulipchat.com/#narrow/stream/313853-wolfram-clojure-bridge), the `#wolframite` channel in [Clojurians Slack](https://clojurians.net), or contact the team at [SciCloj](https://github.com/scicloj).

## License

Expand Down
2 changes: 1 addition & 1 deletion deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
;; `env CLOJARS_USERNAME=<tbd> CLOJARS_PASSWORD=<clojars-token> clojure -T:build deploy`
{:deps {io.github.clojure/tools.build {:git/tag "v0.10.4" :git/sha "31388ff"}
slipset/deps-deploy {:mvn/version "0.2.2"}
org.scicloj/clay {:mvn/version "2-beta15"}
org.scicloj/clay {:mvn/version "2-beta17"}
;; We need wolframite + JLink to render Wolf code in the docs
org.scicloj/wolframite {:local/root "."}
wolfram/jlink {:local/root "./symlink-jlink.jar"}} ; FYI jlink only needed for build-site
Expand Down
29 changes: 29 additions & 0 deletions notebooks/advanced/customizing_wolframite.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
(ns advanced.customizing-wolframite
(:require [scicloj.kindly.v4.kind :as k]
[wolframite.core :as wl]))

(k/md "## Customizing Wolframite
There are several ways to customize Wolframite to your liking.
")

(k/md "### Custom aliases {#sec-custom-aliases}
We've discussed Wolframite's built-in aliases in @sec-aliases-table.
However, Wolframite allows you to individually tailor the user experience at the level of initialization:
")

#_"**TODO**: Move the more detailed discussion of customizing aliases from for-scientists.index to here"

(wl/restart! {:aliases '{🔋 Power}})
(wl/eval '(🔋 2 5))

;; , and function call,
(wl/restart!)
(wl/eval '(🔋🔋 2 5) {:aliases '{🔋🔋 Power}})

;; Use it how you want to!

(k/md "
TIP: You can also get convenience vars for your aliases in `wolframite.wolfram` by running something like `(wolframite.impl.wolfram-syms.write-ns/write-ns! <path> {:aliases '{🔋 Power}})`. After you load the file, you'll be able to use `(wl/eval (w/🔋 2 5) {:aliases '{🔋 Power}})`.
")
4 changes: 4 additions & 0 deletions notebooks/advanced/index.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(ns advanced.index
(:require [scicloj.kindly.v4.kind :as k]))

(k/md "See the other pages in this section.")
2 changes: 1 addition & 1 deletion notebooks/packages.clj → notebooks/advanced/packages.clj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(ns packages
(ns advanced.packages
"A notebook demonstrating how to import and use Wolfram packages in Wolframite."
(:require
[scicloj.kindly.v4.kind :as k]
Expand Down
7 changes: 5 additions & 2 deletions notebooks/build_config.clj
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@
:source-path ["index.clj"
"quickstart.clj"
"understanding_wolframite.clj"
"gotcha.clj"
"gotchas.clj"
{:part "Tutorials for scientists"
:chapters ["for_scientists/index.clj"
"for_scientists/cavity_physics.clj"]}
{:part "Tutorials for developers"
:chapters ["for_developers/index.clj"
"for_developers/wolfram_for_clojurians.clj"
"for_developers/demo_analysis_cycling.clj"]}
{:part "Clojure primer"
:chapters ["clojure_primer/index.clj"]}
{:part "Advanced topics"
:chapters ["packages.clj"]}
:chapters ["advanced/customizing_wolframite.clj"
"advanced/packages.clj"]}
"faq.clj"]
:base-target-path "docs"
:book {:title "Wolframite Documentation"}
Expand Down
Loading

0 comments on commit a212939

Please sign in to comment.