File size: 4,339 Bytes
a8baeed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use ocl::{ProQue, Result};

trait Kernel: Sized {
    fn src() -> &'static str;
    fn name() -> &'static str;
    fn local_size() -> usize;
    fn run(&self, proque: &ProQue) -> Result<Vec<f32>>;
}

struct Add;

impl Kernel for Add {
    fn src() -> &'static str {
        r#"
            __kernel void add(__global float* c) {
                c[get_global_id(0)] = get_local_id(0);
            }
        "#
    }
    fn name() -> &'static str {
        "add"
    }
    fn local_size() -> usize {
        4
    }

    fn run(&self, proque: &ProQue) -> Result<Vec<f32>> {
        let buffer = proque.create_buffer::<f32>()?;
        let kernel = proque.kernel_builder(Self::name()).arg(&buffer).build()?;
        unsafe {
            kernel.cmd().local_work_size(Self::local_size()).enq()?;
        }
        let mut result = vec![0.0f32; 128];
        buffer.cmd().read(&mut result).enq()?;
        Ok(result)
    }
}

fn format_output(data: &[f32]) -> String {
    data.iter()
        .enumerate()
        .fold(String::new(), |acc, (i, &val)| {
            if i > 0 && i % 16 == 0 {
                format!("{}\n{:>3} ", acc, val as i32)
            } else {
                format!("{}{:>3} ", acc, val as i32)
            }
        })
}

fn execute<K: Kernel>(kernel: K, proque: &ProQue) -> Result<Vec<f32>> {
    kernel.run(proque)
}

fn main() -> Result<()> {
    let proque = ProQue::builder().src(Add::src()).dims(128).build()?;

    let result = execute(Add, &proque)?;
    println!("{}", format_output(&result));

    negate_demo();
    agent_workflow_demo();

    Ok(())
}

fn negate_demo() {
    use gpu::functor::{GpuContext, Negate, UnaryOp};

    let ctx = match GpuContext::new() {
        Ok(c) => c,
        Err(e) => {
            eprintln!("negate demo: {e}");
            std::process::exit(1);
        }
    };
    let input = [true, false, true, true, false];
    let once = Negate.run_bools(&ctx, &input).expect("negate failed");
    let twice = Negate
        .then(Negate)
        .run_bools(&ctx, &input)
        .expect("negate∘negate failed");
    println!("\ndevice : {}", ctx.device_name().unwrap_or_default());
    println!("input  : {input:?}");
    println!("¬input : {once:?}");
    println!("¬¬input: {twice:?}");
    assert_eq!(twice, input);
}

fn agent_workflow_demo() {
    use gpu::functor::{Negate, ValidationAgent, VerificationAgent, Workflow};

    println!("\n=== 3-Agent Workflow Demo ===");

    let workflow = match Workflow::new() {
        Ok(w) => w,
        Err(e) => {
            eprintln!("workflow error: {e}");
            return;
        }
    };

    println!("device: {}", workflow.device_name().unwrap_or_default());

    let input = [true, false, true, true, false];
    println!("\n[ValidationAgent] validating input: {input:?}");

    if let Err(e) = ValidationAgent::validate_input(input.len()) {
        eprintln!("validation failed: {e}");
        return;
    }
    println!("[ValidationAgent] ✓ input valid (count={})", input.len());

    println!("[ExecutionAgent] running Negate kernel on device...");
    match workflow.run_unary_bools(&Negate, &input) {
        Ok(negate_result) => {
            println!("[ExecutionAgent] ✓ Negate computed: {negate_result:?}");
            let expected = [false, true, false, false, true];
            if let Ok(()) = VerificationAgent::verify_bools_equal(&negate_result, &expected) {
                println!("[VerificationAgent] ✓ Output verified against expected {expected:?}");
            } else {
                println!("[VerificationAgent] ✗ Output mismatch");
            }
        }
        Err(e) => eprintln!("[ExecutionAgent] ✗ failed: {e}"),
    }

    println!("\n[ExecutionAgent] running Negate∘Negate composition...");
    match workflow.run_composed_bools(&Negate, &Negate, &input) {
        Ok(double_negated) => {
            println!("[ExecutionAgent] ✓ Negate∘Negate computed: {double_negated:?}");
            if let Ok(()) = VerificationAgent::verify_bools_equal(&double_negated, &input) {
                println!("[VerificationAgent] ✓ Involution verified: input == ¬¬input");
            } else {
                println!("[VerificationAgent] ✗ Involution failed");
            }
        }
        Err(e) => eprintln!("[ExecutionAgent] ✗ composition failed: {e}"),
    }
}