wow it works
This commit is contained in:
commit
00e2260bb3
7 changed files with 237 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
/target
|
||||||
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plcc"
|
||||||
|
version = "0.1.0"
|
||||||
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
[package]
|
||||||
|
name = "plcc"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
9
shell.nix
Normal file
9
shell.nix
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
{ pkgs ? import <nixpkgs> {} }:
|
||||||
|
|
||||||
|
pkgs.mkShell {
|
||||||
|
buildInputs = [
|
||||||
|
pkgs.rustc
|
||||||
|
pkgs.cargo
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
28
src/ast.rs
Normal file
28
src/ast.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
use std::collections::hash_map::DefaultHasher;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum Prim {
|
||||||
|
Sin,
|
||||||
|
Cos,
|
||||||
|
Triple, // 3 * x
|
||||||
|
AddPair, // (a,b) -> a + b
|
||||||
|
Input, // переменная x
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ExprAst {
|
||||||
|
Atom(Prim),
|
||||||
|
Composition(Box<ExprAst>, Box<ExprAst>), // g ∘ f
|
||||||
|
Junction(Box<ExprAst>, Box<ExprAst>), // (f, g)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ast_input() -> ExprAst {
|
||||||
|
ExprAst::Atom(Prim::Input)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hash_ast(e: &ExprAst) -> u64 {
|
||||||
|
let mut h = DefaultHasher::new();
|
||||||
|
e.hash(&mut h);
|
||||||
|
h.finish()
|
||||||
|
}
|
||||||
69
src/dsl.rs
Normal file
69
src/dsl.rs
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
// Обобщённое выражение: I -> Out
|
||||||
|
pub trait Expr<I> {
|
||||||
|
type Out;
|
||||||
|
fn eval(&self, x: I) -> Self::Out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// атомарная функция
|
||||||
|
pub struct Function<I, O> {
|
||||||
|
pub f: fn(I) -> O,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, O> Expr<I> for Function<I, O> {
|
||||||
|
type Out = O;
|
||||||
|
fn eval(&self, x: I) -> O {
|
||||||
|
(self.f)(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// композиция g∘f
|
||||||
|
pub struct Composition<F1, F2> {
|
||||||
|
pub first: F1,
|
||||||
|
pub second: F2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, F1, F2> Expr<I> for Composition<F1, F2>
|
||||||
|
where
|
||||||
|
F1: Expr<I>,
|
||||||
|
F2: Expr<F1::Out>,
|
||||||
|
{
|
||||||
|
type Out = F2::Out;
|
||||||
|
|
||||||
|
fn eval(&self, x: I) -> Self::Out {
|
||||||
|
let mid = self.first.eval(x);
|
||||||
|
self.second.eval(mid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// junction — две ветки параллельно
|
||||||
|
pub struct Junction<F1, F2> {
|
||||||
|
pub left: Arc<F1>,
|
||||||
|
pub right: Arc<F2>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, F1, F2> Expr<I> for Junction<F1, F2>
|
||||||
|
where
|
||||||
|
I: Copy + Send + 'static,
|
||||||
|
F1: Expr<I> + Send + Sync + 'static,
|
||||||
|
F2: Expr<I> + Send + Sync + 'static,
|
||||||
|
F1::Out: Send + 'static,
|
||||||
|
F2::Out: Send + 'static,
|
||||||
|
{
|
||||||
|
type Out = (F1::Out, F2::Out);
|
||||||
|
|
||||||
|
fn eval(&self, x: I) -> (F1::Out, F2::Out) {
|
||||||
|
let l = Arc::clone(&self.left);
|
||||||
|
let r = Arc::clone(&self.right);
|
||||||
|
|
||||||
|
let x1 = x;
|
||||||
|
let x2 = x;
|
||||||
|
|
||||||
|
let h1 = thread::spawn(move || l.eval(x1));
|
||||||
|
let h2 = thread::spawn(move || r.eval(x2));
|
||||||
|
|
||||||
|
(h1.join().unwrap(), h2.join().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
117
src/main.rs
Normal file
117
src/main.rs
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
// src/main.rs
|
||||||
|
mod ast;
|
||||||
|
mod dsl;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use ast::{
|
||||||
|
ExprAst, ExprAst::Atom, ExprAst::Composition as C, ExprAst::Junction as J, Prim::AddPair,
|
||||||
|
Prim::Cos, Prim::Input, Prim::Sin, Prim::Triple, ast_input, hash_ast,
|
||||||
|
};
|
||||||
|
use dsl::{Composition, Expr, Function, Junction};
|
||||||
|
|
||||||
|
// ========= тестовые функции =========
|
||||||
|
|
||||||
|
fn sin_f(x: f64) -> f64 {
|
||||||
|
x.sin()
|
||||||
|
}
|
||||||
|
fn cos_f(x: f64) -> f64 {
|
||||||
|
x.cos()
|
||||||
|
}
|
||||||
|
fn triple(x: f64) -> f64 {
|
||||||
|
3.0 * x
|
||||||
|
}
|
||||||
|
|
||||||
|
// (a,b) -> a + b
|
||||||
|
fn add_pair(p: (f64, f64)) -> f64 {
|
||||||
|
p.0 + p.1
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========= демонстрация =========
|
||||||
|
|
||||||
|
// AST для sin(cos(x) + 3*x)
|
||||||
|
fn pupa() -> ExprAst {
|
||||||
|
// cos(x)
|
||||||
|
let cos_x = C(Box::new(ast_input()), Box::new(Atom(Cos)));
|
||||||
|
|
||||||
|
// 3 * x
|
||||||
|
let triple_x = C(Box::new(ast_input()), Box::new(Atom(Triple)));
|
||||||
|
|
||||||
|
// (cos(x), 3*x)
|
||||||
|
let j = J(Box::new(cos_x), Box::new(triple_x));
|
||||||
|
|
||||||
|
// AddPair ∘ Junction => cos(x) + 3*x
|
||||||
|
let add = C(Box::new(j), Box::new(Atom(AddPair)));
|
||||||
|
|
||||||
|
// Sin ∘ (AddPair ∘ Junction)
|
||||||
|
C(Box::new(add), Box::new(Atom(Sin)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lupa() -> ExprAst {
|
||||||
|
use ast::*;
|
||||||
|
// cos(x)
|
||||||
|
let cos_x = C(Box::new(ast::ast_input()), Box::new(Atom(Cos)));
|
||||||
|
|
||||||
|
// 3 * x
|
||||||
|
let triple_x = C(Box::new(ast_input()), Box::new(Atom(Triple)));
|
||||||
|
|
||||||
|
// (cos(x), 3*x)
|
||||||
|
let j = J(Box::new(triple_x), Box::new(cos_x));
|
||||||
|
|
||||||
|
// AddPair ∘ Junction => cos(x) + 3*x
|
||||||
|
let add = C(Box::new(j), Box::new(Atom(AddPair)));
|
||||||
|
|
||||||
|
// Sin ∘ (AddPair ∘ Junction)
|
||||||
|
C(Box::new(add), Box::new(Atom(Sin)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// --- исполняемый граф для sin(cos(x) + 3*x) ---
|
||||||
|
|
||||||
|
let cos_expr = Function { f: cos_f }; // f64 -> f64
|
||||||
|
let mul3_expr = Function { f: triple }; // f64 -> f64
|
||||||
|
|
||||||
|
// (cos(x), 3*x) параллельно
|
||||||
|
let j = Junction {
|
||||||
|
left: Arc::new(cos_expr),
|
||||||
|
right: Arc::new(mul3_expr),
|
||||||
|
}; // f64 -> (f64,f64)
|
||||||
|
|
||||||
|
// (a,b) -> a+b
|
||||||
|
let add_expr = Function { f: add_pair }; // (f64,f64) -> f64
|
||||||
|
let sin_expr = Function { f: sin_f }; // f64 -> f64
|
||||||
|
|
||||||
|
// (f64,f64) -> f64 -> f64 === sin(a+b)
|
||||||
|
let sum_then_sin = Composition {
|
||||||
|
first: add_expr,
|
||||||
|
second: sin_expr,
|
||||||
|
};
|
||||||
|
|
||||||
|
// полный конвейер: x -> (cos(x),3x) -> cos(x)+3x -> sin(...)
|
||||||
|
let full = Composition {
|
||||||
|
first: j,
|
||||||
|
second: sum_then_sin,
|
||||||
|
};
|
||||||
|
|
||||||
|
let x = 2.0;
|
||||||
|
let y = full.eval(x); // y = sin(cos(x) + 3*x)
|
||||||
|
|
||||||
|
println!("sin(cos({}) + 3*{}) = {}", x, x, y);
|
||||||
|
|
||||||
|
// --- AST + hash для того же выражения ---
|
||||||
|
|
||||||
|
let ast = pupa();
|
||||||
|
let h = hash_ast(&ast);
|
||||||
|
|
||||||
|
println!("AST: {ast:#?}");
|
||||||
|
println!("AST hash: {h:016x}\n");
|
||||||
|
|
||||||
|
println!("comparison:");
|
||||||
|
|
||||||
|
let ast1 = pupa();
|
||||||
|
let ast2 = lupa();
|
||||||
|
|
||||||
|
println!("equal? {}", ast1 == ast2);
|
||||||
|
println!("hash1 = {:016x}", hash_ast(&ast1));
|
||||||
|
println!("hash2 = {:016x}", hash_ast(&ast2));
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue