0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rustのsymbolica

Posted at

概要

pythonを使用している方ならSymPyなどを扱っている人が多いと思いますが、symbolicaを使用するとpython,Rustともに扱えるので、このライブラリについて簡単にまとめた。

ライセンス

symbolicaには、未ライセンスの状態でも扱えますが制限があります。

制限としては以下の様な項目がありました。

  • デバイスごとに1インスタンス1コア

その為、いまどきのPCを扱っている方だとリソースが有り余っているはずです。
(そこまで使いこなせるかようわからんけど)

詳細は参考資料のSymbolica.ioPricingを参照してください。
image.png

今回の記事では、私的にはHobbyistに属するはずなのでこれからのやり方でライセンスを取得します。

環境

rustup showの結果を記載。

Default host: x86_64-unknown-linux-gnu
rustup home: /usr/local/lib/rust/rustup

installed toolchains

nightly-x86_64-unknown-linux-gnu (active, default)

active toolchain

name: nightly-x86_64-unknown-linux-gnu
active because: it's the default toolchain
installed targets:
x86_64-unknown-linux-gnu

環境構築

今回の環境では以下のパッケージをaptで入れています。
libxx系のパッケージは不要かもしれないです。

symbolicaでビルド時に使用する際はm4, gitっぽい?

別のパッケージで使用しているのでインストールしています。

 apt install -y
        curl \
        build-essential \
        libx11-dev \
        libxcursor-dev \
        libxcb1-dev \
        libxi-dev \
        libxkbcommon-dev \
        libxkbcommon-x11-dev \
        libxrandr2 \
        m4 \
        git \

プロジェクト作成

数式処理を行う為のプロジェクトを作成。

cargo new <project name>

ライセンスキーの取得

一度しか使用しないのでcargo runしたらコードを削除します。

use symbolica::LicenseManager;

fn main() {
    LicenseManager::request_hobbyist_license("Name", "Email").unwrap();
}

Emailに登録したアドレスへライセンスキーが来るのでコピーをします。

スクリーンショット 2025-06-28 214607.png

ライセンスキーを環境変数に登録します。(登録方法は良しなに)

export SYMBOLICA_LICENSE=xxxxxxxxxx-yyyyy-zzzzz-wwww-0000000

内容

基本的に次のsymbolicaクレートのモジュールをインポートします。

use symbolica::{atom::{AtomCore, Atom}, parse, symbol};

AtomCoreには、式を変更せずに維持する拡張やパターンマッチングなどの式のすべてのコア機能が搭載されています。(参考)

parseマクロでは、文字列からAtomを解析します。
リテラルコードから解析するにはparse_litマクロを使用し、誤りのある解析にはtry_parseを使用します。(参考)

symbolマクロでは、シンボルを作成するか、同じ名前の既存のシンボルを取得します。
名前空間が指定されていない場合は、現在の名前空間にシンボルが作成されます。(参考)

その為、基本Atom構造体を作成して
そのメソッドを利用する形になります。

以下が使用例。

導関数・微分(derivative)

変数 x に関して微分を行う例

    let exp: Atom = parse!("(1+x)^3");
    let a: Atom = exp.derivative(symbol!("x"));
    println!("{}\n {}", exp, a);

結果:

(x+1)^3
 3*(x+1)^2

式の展開(expand)

    let exp: Atom = parse!("(1+x)^3");
    let b: Atom = input.expand();
    println!("{}\n {}", exp, b);

結果:

(x+1)^3
 3*x+3*x^2+x^3+1

評価結果

数式の評価結果を得る方法

    let expr = parse!("cos(x)*3 + f1(x, 2) + f2(x)");

変数xを作成し、対応する値として 1.25 を定数として登録する。

    let x = parse!("x");
    let mut const_map = HashMap::default();
    const_map.insert(x.clone(), 1.25);

関数f1f2のシンボルを定義し、関数を格納するマップを初期化する。

use std::collections::HashMap;
...
    let f1 = symbol!("f1");
    let f2 = symbol!("f2");
    let mut function_map = HashMap::default();

各関数の処理をシンボルごとに登録

    function_map.insert(
        f1,
        EvaluationFn::new(Box::new(|args: &[f64], _, _, _| {
            args[0] + 2.0 * args[1]
        })),
    );
    function_map.insert(
        f2,
        EvaluationFn::new(Box::new(|args: &[f64], var_map, fn_map, cache| {
            println!("var map = {:?}", var_map);
            println!("cache = {:?}", cache);
            let f1_func = fn_map.get(&symbol!("f1")).unwrap().get();
            args[0] + 3.0 + f1_func(&[args[0], 3.], var_map, fn_map, cache)
        })),
    );

これまでの定数や関数情報を評価時に渡す
evaluteの第一引数の処理は何を行えばよいかがまだ分からないが、公式のサンプル通りにやったら動いたので一旦よし。

    let result: f64 = expr
    .evaluate(|r| {
        r.to_f64()
    } ,
     &const_map, 
     &function_map)
    .unwrap();

グラフ

つかれたので省略

参考資料

symbolica(docs.rs)
Symbolica.io
symbolica github

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?