wow it works

This commit is contained in:
Gregory Bednov 2025-12-26 06:45:35 +03:00
commit 00e2260bb3
7 changed files with 237 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

7
Cargo.lock generated Normal file
View 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
View file

@ -0,0 +1,6 @@
[package]
name = "plcc"
version = "0.1.0"
edition = "2024"
[dependencies]

9
shell.nix Normal file
View file

@ -0,0 +1,9 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = [
pkgs.rustc
pkgs.cargo
];
}

28
src/ast.rs Normal file
View 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
View 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
View 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));
}