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