Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/lucifer1004/jlbun
Using Julia in Bun!
https://github.com/lucifer1004/jlbun
bun ffi javascript julia typescript
Last synced: 6 days ago
JSON representation
Using Julia in Bun!
- Host: GitHub
- URL: https://github.com/lucifer1004/jlbun
- Owner: lucifer1004
- License: mit
- Created: 2022-12-25T22:54:27.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2024-11-27T04:47:20.000Z (28 days ago)
- Last Synced: 2024-12-08T02:04:18.934Z (17 days ago)
- Topics: bun, ffi, javascript, julia, typescript
- Language: TypeScript
- Homepage: https://lucifer1004.github.io/jlbun
- Size: 485 KB
- Stars: 62
- Watchers: 5
- Forks: 1
- Open Issues: 12
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# jlbun - Using Julia in Bun
![Logo of jlbun](https://user-images.githubusercontent.com/13583761/210193825-4b898ddf-b4b2-4e21-a691-c05240bb81e3.png)
- [jlbun - Using Julia in Bun](#jlbun---using-julia-in-bun)
- [Installation](#installation)
- [Usage](#usage)
- [Evaluate Julia code](#evaluate-julia-code)
- [Pass a Bun array to Julia](#pass-a-bun-array-to-julia)
- [Pass a Julia Array to Bun](#pass-a-julia-array-to-bun)
- [Do some linear algebra](#do-some-linear-algebra)
- [Install and use new packages](#install-and-use-new-packages)
- [Function calls with keyword arguments](#function-calls-with-keyword-arguments)
- [Call JS functions from Julia](#call-js-functions-from-julia)
- [Run Julia with multiple threads](#run-julia-with-multiple-threads)
- [Star History](#star-history)## Installation
> - You need to have `Bun`, `CMake` and `Julia` installed to use this library.
> - `bun install` does not run the packages's `install` scripts, so `npm install` is used instead.```bash
npm install jlbun
```## Usage
### Evaluate Julia code
`jlbun` provides `Julia.eval()` and `Julia.tagEval()`. The former accepts a string, while the latter accepts a tagged template literal.
```typescript
import { Julia } from "jlbun";Julia.init();
Julia.eval('println("Hello from Julia")'); // "Hello from Julia"
const arr = [1, 2, "hello"];
Julia.tagEval`println(${arr})`; // "Any[1, 2, "hello"]"const arr2 = new Uint8Array([1, 2, 3]);
Julia.tagEval`println(${arr2})`; // "UInt8[0x01, 0x02, 0x03]"const obj = { foo: 0, bar: false, bal: [1, 2, 3] }
Julia.tagEval`println(${obj})`; // "(foo = 0, bar = false, bal = Any[1, 2, 3])"Julia.close();
```### Pass a Bun array to Julia
```typescript
import { Julia, JuliaArray } from "jlbun";// This initializes Julia and loads prelude symbols.
Julia.init();// Create a `TypedArray` at the Bun side.
const bunArray = new Float64Array([1, 2, 3, 4, 5]);// Create a `JuliaArray` from the `TypedArray`.
const juliaArray = JuliaArray.from(bunArray);// These two arrays now share the same memory.
Julia.Base.println(juliaArray); // [1.0, 2.0, 3.0, 4.0, 5.0]// We can modify the array at the Bun side (0-indexed).
bunArray[1] = 100.0;
Julia.Base.println(juliaArray); // [1.0, 100.0, 3.0, 4.0, 5.0]// Or we can modify the array at the Julia side (also 0-indexed).
juliaArray.set(0, -10.0);
Julia.Base.println(juliaArray); // [-10.0, 100.0, 3.0, 4.0, 5.0]// This cleans up Julia-related stuff.
Julia.close();
```### Pass a Julia Array to Bun
```typescript
import { Julia } from "jlbun";Julia.init();
const juliaArray = Julia.Base.rand(10, 10);
const bunArray = juliaArray.rawValue;
console.log(bunArray);Julia.close();
```### Do some linear algebra
```typescript
import { Julia } from "jlbun";Julia.init();
const juliaArray = Julia.Base.rand(2, 2);
const inv = Julia.Base.inv(juliaArray);
console.log(inv.value);const anotherJuliaArray = Julia.Base.rand(2, 2);
const product = Julia.Base["*"](juliaArray, anotherJuliaArray);
console.log(product.value);// We can also import Julia modules.
const LA = Julia.import("LinearAlgebra");
console.log(LA.norm(product).value);Julia.close();
```### Install and use new packages
```typescript
import { Julia } from "jlbun";
import { join } from "path";Julia.init();
// Install `CairoMakie`
Julia.Pkg.add("CairoMakie");// Import `CairoMakie`
const Cairo = Julia.import("CairoMakie");// Plot and save
const plt = Cairo.plot(Julia.Base.rand(10), Julia.Base.rand(10));
Cairo.save(join(process.cwd(), "plot.png"), plt);Julia.close();
```### Function calls with keyword arguments
```typescript
import { Julia, JuliaArray } from "jlbun";Julia.init();
const rawArray = new Int32Array([1, 10, 20, 30, 100]);
const arr = JuliaArray.from(rawArray);
Julia.Base["sort!"].callWithKwargs({ by: Julia.Base.string, rev: true }, arr);
console.log(rawArray); // Int32Array(5) [ 30, 20, 100, 10, 1 ]Julia.close();
```### Call JS functions from Julia
```typescript
import { Julia, JuliaArray, JuliaFunction } from "jlbun";Julia.init();
const jsFunc = (x: number) => -x;
const cb = JuliaFunction.from(jsFunc, {
returns: "i32",
args: ["i32"],
});const arr = JuliaArray.from(new Int32Array([1, 10, 20, 30, 100]));
const neg = arr.map(cb);
Julia.println(neg); // Int32[-1, -10, -20, -30, -100]
cb.close();Julia.close();
```To deal with strings requires some tricks, see the example below:
```typescript
import { Julia, JuliaArray, JuliaFunction, safeCString } from "jlbun";Julia.init();
const jsFunc = (x: number) => {
return safeCString(x.toString());
};const cb = JuliaFunction.from(jsFunc, {
returns: "cstring",
args: ["i32"],
});const arr = JuliaArray.from(new Int32Array([1, 10, 20, 30, 100]));
Julia.Base["sort!"].callWithKwargs({ by: cb, rev: true }, arr);
Julia.println(arr); // Int32[30, 20, 100, 10, 1]
cb.close();Julia.close();
```### Run Julia with multiple threads
To use multiple threads in Julia, you need to set the `JULIA_NUM_THREADS` environment variable.
With `export JULIA_NUM_THREADS=2` set, the following program should output `2` instead of `1`:
```typescript
import { Julia } from "jlbun";Julia.init();
Julia.eval("println(Threads.nthreads())");
Julia.close();
```A more advanced example:
```typescript
import { Julia, JuliaFunction, JuliaTask, JuliaValue } from "jlbun";Julia.init();
const promises: Promise[] = [];
const func = Julia.eval(`function ()
ans = 0;
for i in 1:1000
ans += i
end
ans
end
`) as JuliaFunction;for (let i = 0; i < Julia.nthreads; i++) {
promises.push(JuliaTask.from(func).schedule(i).value);
}const results = (await Promise.all(promises)).map(promise => promise.value);
console.log(results); // [ 500500n, 500500n, 500500n, 500500n, 500500n, 500500n, 500500n, 500500n ]Julia.close();
```## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=lucifer1004/jlbun&type=Date)](https://star-history.com/#lucifer1004/jlbun&Date)