Skip to main content

torsh_autograd/
function.rs

1//! Enhanced autograd function framework with custom function support
2//!
3//! This module provides a comprehensive framework for defining custom autograd functions,
4//! including forward and backward pass implementations, function composition, and
5//! automatic differentiation through user-defined operations.
6
7use torsh_core::error::{Result, TorshError};
8// AutogradTensor trait is available through crate root - it's generic
9use crate::AutogradTensor;
10use parking_lot::RwLock;
11use serde::{Deserialize, Serialize};
12use std::any::Any;
13use std::collections::HashMap;
14use std::path::Path;
15use std::sync::Arc;
16use std::time::SystemTime;
17
18/// Type-erased trait for custom autograd functions - dyn-compatible version
19pub trait DynFunction: Send + Sync {
20    /// Name of the function for debugging and profiling
21    fn name(&self) -> &str;
22
23    /// Whether this function is differentiable
24    fn is_differentiable(&self) -> bool {
25        true
26    }
27
28    /// Memory complexity hint for optimization
29    fn memory_complexity(&self) -> MemoryComplexity {
30        MemoryComplexity::Linear
31    }
32
33    /// Computational complexity hint for optimization
34    fn computational_complexity(&self) -> ComputationalComplexity {
35        ComputationalComplexity::Linear
36    }
37
38    /// Whether this function can be fused with others
39    fn is_fusable(&self) -> bool {
40        false
41    }
42
43    /// Get function metadata for optimization
44    fn metadata(&self) -> FunctionMetadata {
45        FunctionMetadata {
46            name: self.name().to_string(),
47            is_differentiable: self.is_differentiable(),
48            memory_complexity: self.memory_complexity(),
49            computational_complexity: self.computational_complexity(),
50            is_fusable: self.is_fusable(),
51            version: "1.0.0".to_string(),
52            description: "Custom autograd function".to_string(),
53            author: "Unknown".to_string(),
54            created_at: SystemTime::now()
55                .duration_since(SystemTime::UNIX_EPOCH)
56                .unwrap_or_else(|_| std::time::Duration::from_secs(0))
57                .as_secs()
58                .to_string(),
59            checksum: "".to_string(),
60            dependencies: vec![],
61        }
62    }
63}
64
65/// Trait for custom autograd functions with generic methods
66pub trait Function: Send + Sync + DynFunction {
67    /// Forward pass computation
68    fn forward<T>(
69        &self,
70        ctx: &mut FunctionContext,
71        inputs: &[&dyn AutogradTensor<T>],
72    ) -> Result<Vec<Box<dyn AutogradTensor<T>>>>
73    where
74        T: torsh_core::dtype::TensorElement;
75
76    /// Backward pass computation
77    fn backward<T>(
78        &self,
79        ctx: &mut FunctionContext,
80        grad_outputs: &[&dyn AutogradTensor<T>],
81    ) -> Result<Vec<Option<Box<dyn AutogradTensor<T>>>>>
82    where
83        T: torsh_core::dtype::TensorElement;
84}
85
86/// Trait for non-differentiable functions that have subgradients
87pub trait SubgradientFunction: Send + Sync + DynFunction {
88    /// Forward pass computation
89    fn forward<T>(
90        &self,
91        ctx: &mut FunctionContext,
92        inputs: &[&dyn AutogradTensor<T>],
93    ) -> Result<Vec<Box<dyn AutogradTensor<T>>>>
94    where
95        T: torsh_core::dtype::TensorElement + num_traits::Float;
96
97    /// Subgradient computation for non-differentiable operations
98    /// Returns a set of possible subgradients
99    fn subgradient<T>(
100        &self,
101        ctx: &mut FunctionContext,
102        grad_outputs: &[&dyn AutogradTensor<T>],
103    ) -> Result<Vec<Option<SubgradientSet<T>>>>
104    where
105        T: torsh_core::dtype::TensorElement + num_traits::Float;
106}
107
108/// Set of subgradients for non-differentiable functions
109pub struct SubgradientSet<T: torsh_core::dtype::TensorElement> {
110    /// Primary subgradient (commonly used one)
111    pub primary: Box<dyn AutogradTensor<T>>,
112    /// Alternative subgradients
113    pub alternatives: Vec<Box<dyn AutogradTensor<T>>>,
114    /// Selection strategy for choosing subgradient
115    pub selection_strategy: SubgradientSelection,
116}
117
118impl<T: torsh_core::dtype::TensorElement> Clone for SubgradientSet<T> {
119    fn clone(&self) -> Self {
120        Self {
121            primary: self.primary.clone_tensor(),
122            alternatives: self.alternatives.iter().map(|t| t.clone_tensor()).collect(),
123            selection_strategy: self.selection_strategy,
124        }
125    }
126}
127
128impl<T: torsh_core::dtype::TensorElement> std::fmt::Debug for SubgradientSet<T> {
129    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130        f.debug_struct("SubgradientSet")
131            .field(
132                "primary",
133                &format!("Box<dyn AutogradTensor<{}>>", std::any::type_name::<T>()),
134            )
135            .field(
136                "alternatives",
137                &format!(
138                    "Vec<Box<dyn AutogradTensor<{}>>> (len: {})",
139                    std::any::type_name::<T>(),
140                    self.alternatives.len()
141                ),
142            )
143            .field("selection_strategy", &self.selection_strategy)
144            .finish()
145    }
146}
147
148/// Strategy for selecting subgradients in non-differentiable operations
149#[derive(Debug, Clone, Copy, PartialEq, Eq)]
150pub enum SubgradientSelection {
151    /// Always use the primary subgradient
152    Primary,
153    /// Choose randomly from available subgradients
154    Random,
155    /// Use the subgradient with minimum norm
156    MinNorm,
157    /// Use the subgradient with maximum norm
158    MaxNorm,
159    /// Use Clarke subgradient (convex hull)
160    Clarke,
161    /// Use generalized gradient (for locally Lipschitz functions)
162    Generalized,
163}
164
165/// Memory complexity categories for function optimization
166#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
167pub enum MemoryComplexity {
168    Constant,
169    Linear,
170    Quadratic,
171    Exponential,
172}
173
174/// Computational complexity categories for function optimization
175#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
176pub enum ComputationalComplexity {
177    Constant,
178    Linear,
179    LogLinear,
180    Quadratic,
181    Cubic,
182    Exponential,
183}
184
185/// Function metadata for optimization and debugging
186#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct FunctionMetadata {
188    pub name: String,
189    pub is_differentiable: bool,
190    pub memory_complexity: MemoryComplexity,
191    pub computational_complexity: ComputationalComplexity,
192    pub is_fusable: bool,
193    pub version: String,
194    pub description: String,
195    pub author: String,
196    pub created_at: String,
197    pub checksum: String,
198    pub dependencies: Vec<String>,
199}
200
201/// Context for storing values between forward and backward passes
202pub struct FunctionContext {
203    /// Saved tensors for backward pass
204    #[allow(dead_code)]
205    saved_tensors: Vec<Box<dyn Any + Send + Sync>>,
206    /// Saved scalar values for backward pass
207    saved_values: Vec<Box<dyn Any + Send + Sync>>,
208    /// Whether to materialize gradients for non-differentiable tensors
209    materialize_grads: bool,
210    /// Unique context ID for debugging
211    context_id: usize,
212    /// Function name for debugging
213    function_name: String,
214}
215
216impl Default for FunctionContext {
217    fn default() -> Self {
218        Self::new()
219    }
220}
221
222impl FunctionContext {
223    /// Create a new function context
224    pub fn new() -> Self {
225        static CONTEXT_COUNTER: std::sync::atomic::AtomicUsize =
226            std::sync::atomic::AtomicUsize::new(0);
227        Self {
228            saved_tensors: Vec::new(),
229            saved_values: Vec::new(),
230            materialize_grads: true,
231            context_id: CONTEXT_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
232            function_name: "unknown".to_string(),
233        }
234    }
235
236    /// Create a new function context with a specific name
237    pub fn with_name(name: String) -> Self {
238        let mut ctx = Self::new();
239        ctx.function_name = name;
240        ctx
241    }
242
243    /// Save arbitrary values for backward pass
244    pub fn save_value<V: Any + Send + Sync + 'static>(&mut self, value: V) {
245        self.saved_values.push(Box::new(value));
246    }
247
248    /// Get saved value by index
249    pub fn get_saved_value<V: Any + 'static>(&self, index: usize) -> Result<&V> {
250        self.saved_values
251            .get(index)
252            .and_then(|v| v.downcast_ref::<V>())
253            .ok_or_else(|| {
254                TorshError::AutogradError(format!(
255                    "Saved value at index {} not found or type mismatch in context {}",
256                    index, self.context_id
257                ))
258            })
259    }
260
261    /// Get the context ID
262    pub fn context_id(&self) -> usize {
263        self.context_id
264    }
265
266    /// Get the function name
267    pub fn function_name(&self) -> &str {
268        &self.function_name
269    }
270
271    /// Set whether to materialize gradients
272    pub fn set_materialize_grads(&mut self, materialize: bool) {
273        self.materialize_grads = materialize;
274    }
275
276    /// Check if gradients should be materialized
277    pub fn should_materialize_grads(&self) -> bool {
278        self.materialize_grads
279    }
280}
281
282/// Function registry for managing custom functions
283pub struct FunctionRegistry {
284    functions: RwLock<HashMap<String, Arc<dyn DynFunction>>>,
285}
286
287impl Default for FunctionRegistry {
288    fn default() -> Self {
289        Self::new()
290    }
291}
292
293impl FunctionRegistry {
294    /// Create a new function registry
295    pub fn new() -> Self {
296        Self {
297            functions: RwLock::new(HashMap::new()),
298        }
299    }
300
301    /// Register a custom function
302    pub fn register<F>(&self, name: String, function: F) -> Result<()>
303    where
304        F: Function + 'static,
305    {
306        let mut functions = self.functions.write();
307        if functions.contains_key(&name) {
308            return Err(TorshError::AutogradError(format!(
309                "Function '{name}' is already registered"
310            )));
311        }
312        functions.insert(name, Arc::new(function));
313        Ok(())
314    }
315
316    /// Get a registered function
317    pub fn get(&self, name: &str) -> Option<Arc<dyn DynFunction>> {
318        self.functions.read().get(name).cloned()
319    }
320
321    /// List all registered function names
322    pub fn list_functions(&self) -> Vec<String> {
323        self.functions.read().keys().cloned().collect()
324    }
325
326    /// Unregister a function
327    pub fn unregister(&self, name: &str) -> bool {
328        self.functions.write().remove(name).is_some()
329    }
330
331    /// Get function metadata
332    pub fn get_metadata(&self, name: &str) -> Option<FunctionMetadata> {
333        self.functions.read().get(name).map(|f| f.metadata())
334    }
335}
336
337// Global function registry
338static GLOBAL_REGISTRY: std::sync::OnceLock<FunctionRegistry> = std::sync::OnceLock::new();
339
340/// Get the global function registry
341pub fn global_registry() -> &'static FunctionRegistry {
342    GLOBAL_REGISTRY.get_or_init(FunctionRegistry::new)
343}
344
345/// Register a function globally
346pub fn register_function<F>(name: String, function: F) -> Result<()>
347where
348    F: Function + 'static,
349{
350    global_registry().register(name, function)
351}
352
353/// Apply a registered function by name
354/// Note: This function is limited to metadata operations only due to type erasure
355pub fn get_function_metadata(name: &str) -> Result<FunctionMetadata> {
356    let function = global_registry()
357        .get(name)
358        .ok_or_else(|| TorshError::AutogradError(format!("Function '{name}' not found")))?;
359
360    Ok(function.metadata())
361}
362
363/// Function composition utilities
364pub mod composition {
365    use super::*;
366
367    /// Composed function that applies multiple functions in sequence
368    /// Note: Due to type erasure limitations, this is a placeholder structure
369    pub struct ComposedFunction {
370        #[allow(dead_code)]
371        function_names: Vec<String>,
372        name: String,
373    }
374
375    impl ComposedFunction {
376        /// Create a new composed function from function names
377        pub fn new(function_names: Vec<String>) -> Self {
378            let name = format!("compose({})", function_names.join(", "));
379            Self {
380                function_names,
381                name,
382            }
383        }
384    }
385
386    impl DynFunction for ComposedFunction {
387        fn name(&self) -> &str {
388            &self.name
389        }
390
391        fn is_differentiable(&self) -> bool {
392            // For simplicity, assume composed functions are differentiable
393            true
394        }
395
396        fn memory_complexity(&self) -> MemoryComplexity {
397            // Conservative estimate
398            MemoryComplexity::Linear
399        }
400
401        fn computational_complexity(&self) -> ComputationalComplexity {
402            // Conservative estimate
403            ComputationalComplexity::Linear
404        }
405    }
406
407    impl Function for ComposedFunction {
408        fn forward<T>(
409            &self,
410            _ctx: &mut FunctionContext,
411            _inputs: &[&dyn AutogradTensor<T>],
412        ) -> Result<Vec<Box<dyn AutogradTensor<T>>>>
413        where
414            T: torsh_core::dtype::TensorElement,
415        {
416            // Due to type erasure limitations, function composition is not implemented
417            Err(TorshError::AutogradError(
418                "Function composition with type erasure is not supported".to_string(),
419            ))
420        }
421
422        fn backward<T>(
423            &self,
424            _ctx: &mut FunctionContext,
425            _grad_outputs: &[&dyn AutogradTensor<T>],
426        ) -> Result<Vec<Option<Box<dyn AutogradTensor<T>>>>>
427        where
428            T: torsh_core::dtype::TensorElement,
429        {
430            // Due to type erasure limitations, function composition is not implemented
431            Err(TorshError::AutogradError(
432                "Function composition with type erasure is not supported".to_string(),
433            ))
434        }
435    }
436
437    /// Compose multiple functions into a single function by name
438    pub fn compose(function_names: Vec<String>) -> ComposedFunction {
439        ComposedFunction::new(function_names)
440    }
441}
442
443/// Example function implementations
444pub mod examples {
445    use super::*;
446
447    /// Example: Scaled addition function (a + scale * b)
448    #[derive(Debug)]
449    pub struct ScaledAdd {
450        pub scale: f32,
451    }
452
453    impl DynFunction for ScaledAdd {
454        fn name(&self) -> &str {
455            "ScaledAdd"
456        }
457
458        fn is_fusable(&self) -> bool {
459            true // Element-wise operations can often be fused
460        }
461    }
462
463    impl Function for ScaledAdd {
464        fn forward<T>(
465            &self,
466            ctx: &mut FunctionContext,
467            inputs: &[&dyn AutogradTensor<T>],
468        ) -> Result<Vec<Box<dyn AutogradTensor<T>>>>
469        where
470            T: torsh_core::dtype::TensorElement,
471        {
472            if inputs.len() != 2 {
473                return Err(TorshError::AutogradError(
474                    "ScaledAdd expects exactly two inputs".to_string(),
475                ));
476            }
477
478            // Save scale for backward pass
479            ctx.save_value(self.scale);
480
481            // Compute output = a + scale * b element-wise via to_vec() / from_f64().
482            let a_data = inputs[0].to_vec();
483            let b_data = inputs[1].to_vec();
484
485            if a_data.len() != b_data.len() {
486                return Err(TorshError::AutogradError(
487                    "ScaledAdd: input tensors must have the same number of elements".to_string(),
488                ));
489            }
490
491            let scale_f64 = self.scale as f64;
492            let out_data = a_data
493                .iter()
494                .zip(b_data.iter())
495                .map(|(a_elem, b_elem)| {
496                    let a_f64 = a_elem.to_f64().ok_or_else(|| {
497                        TorshError::AutogradError(
498                            "ScaledAdd: failed to convert element to f64".to_string(),
499                        )
500                    })?;
501                    let b_f64 = b_elem.to_f64().ok_or_else(|| {
502                        TorshError::AutogradError(
503                            "ScaledAdd: failed to convert element to f64".to_string(),
504                        )
505                    })?;
506                    T::from_f64(a_f64 + scale_f64 * b_f64).ok_or_else(|| {
507                        TorshError::AutogradError(
508                            "ScaledAdd: failed to convert f64 result back to T".to_string(),
509                        )
510                    })
511                })
512                .collect::<Result<Vec<T>>>()?;
513
514            let output = inputs[0].with_data(out_data)?;
515            Ok(vec![output])
516        }
517
518        fn backward<T>(
519            &self,
520            ctx: &mut FunctionContext,
521            grad_outputs: &[&dyn AutogradTensor<T>],
522        ) -> Result<Vec<Option<Box<dyn AutogradTensor<T>>>>>
523        where
524            T: torsh_core::dtype::TensorElement,
525        {
526            if grad_outputs.len() != 1 {
527                return Err(TorshError::AutogradError(
528                    "ScaledAdd backward expects exactly one gradient output".to_string(),
529                ));
530            }
531
532            let scale: f32 = *ctx.get_saved_value(0)?;
533            let grad_output = grad_outputs[0];
534
535            // Gradients: da = grad_output, db = scale * grad_output.
536            let grad_a = Some(grad_output.clone_tensor());
537
538            // grad_b = scale * grad_output (element-wise scalar multiplication).
539            let grad_b = Some(grad_output.mul_scalar(scale as f64)?);
540
541            Ok(vec![grad_a, grad_b])
542        }
543    }
544}
545
546/// Helper macro for defining custom functions
547#[macro_export]
548macro_rules! define_custom_function {
549    (
550        $name:ident,
551        forward: $forward:expr,
552        backward: $backward:expr
553    ) => {
554        #[derive(Debug)]
555        pub struct $name;
556
557        impl $crate::function::Function for $name {
558            fn forward<T>(
559                &self,
560                ctx: &mut $crate::function::FunctionContext,
561                inputs: &[&dyn $crate::AutogradTensor<T>],
562            ) -> $crate::Result<Vec<Box<dyn $crate::AutogradTensor<T>>>>
563            where
564                T: torsh_core::dtype::TensorElement,
565            {
566                $forward(ctx, inputs)
567            }
568
569            fn backward<T>(
570                &self,
571                ctx: &mut $crate::function::FunctionContext,
572                grad_outputs: &[&dyn $crate::AutogradTensor<T>],
573            ) -> $crate::Result<Vec<Option<Box<dyn $crate::AutogradTensor<T>>>>>
574            where
575                T: torsh_core::dtype::TensorElement,
576            {
577                $backward(ctx, grad_outputs)
578            }
579
580            fn name(&self) -> &str {
581                stringify!($name)
582            }
583        }
584    };
585}
586
587/// Common non-differentiable functions with subgradient support
588pub mod subgradient_functions {
589    use super::*;
590
591    /// Absolute value function: f(x) = |x|
592    /// Subgradient: ∂f(x) = {-1 if x < 0, [-1, 1] if x = 0, 1 if x > 0}
593    #[derive(Debug)]
594    pub struct AbsFunction;
595
596    impl DynFunction for AbsFunction {
597        fn name(&self) -> &str {
598            "abs"
599        }
600        fn is_differentiable(&self) -> bool {
601            false
602        }
603    }
604
605    impl SubgradientFunction for AbsFunction {
606        fn forward<T>(
607            &self,
608            _ctx: &mut FunctionContext,
609            inputs: &[&dyn AutogradTensor<T>],
610        ) -> Result<Vec<Box<dyn AutogradTensor<T>>>>
611        where
612            T: torsh_core::dtype::TensorElement + num_traits::Float,
613        {
614            if inputs.len() != 1 {
615                return Err(TorshError::AutogradError(
616                    "abs requires exactly 1 input".to_string(),
617                ));
618            }
619
620            // For now, return a cloned tensor (in real implementation, apply abs)
621            Ok(vec![inputs[0].clone_tensor()])
622        }
623
624        fn subgradient<T>(
625            &self,
626            _ctx: &mut FunctionContext,
627            grad_outputs: &[&dyn AutogradTensor<T>],
628        ) -> Result<Vec<Option<SubgradientSet<T>>>>
629        where
630            T: torsh_core::dtype::TensorElement + num_traits::Float,
631        {
632            if grad_outputs.len() != 1 {
633                return Err(TorshError::AutogradError(
634                    "abs grad requires exactly 1 output".to_string(),
635                ));
636            }
637
638            let grad_output = grad_outputs[0];
639
640            // Primary subgradient: sign function (most commonly used)
641            let primary = grad_output.clone_tensor();
642
643            // For x = 0, subgradient is any value in [-1, 1]
644            // We provide common alternatives: -1, 0, 1
645            let zero_grad = grad_output.zeros_like();
646            let neg_grad = grad_output.mul_scalar(-1.0_f64)?;
647
648            let subgrad_set = SubgradientSet {
649                primary,
650                alternatives: vec![zero_grad, neg_grad],
651                selection_strategy: SubgradientSelection::Primary,
652            };
653
654            Ok(vec![Some(subgrad_set)])
655        }
656    }
657
658    /// ReLU function: f(x) = max(0, x)
659    /// Subgradient: ∂f(x) = {0 if x < 0, [0, 1] if x = 0, 1 if x > 0}
660    #[derive(Debug)]
661    pub struct ReLUFunction;
662
663    impl DynFunction for ReLUFunction {
664        fn name(&self) -> &str {
665            "relu"
666        }
667        fn is_differentiable(&self) -> bool {
668            false
669        }
670    }
671
672    impl SubgradientFunction for ReLUFunction {
673        fn forward<T>(
674            &self,
675            _ctx: &mut FunctionContext,
676            inputs: &[&dyn AutogradTensor<T>],
677        ) -> Result<Vec<Box<dyn AutogradTensor<T>>>>
678        where
679            T: torsh_core::dtype::TensorElement + num_traits::Float,
680        {
681            if inputs.len() != 1 {
682                return Err(TorshError::AutogradError(
683                    "relu requires exactly 1 input".to_string(),
684                ));
685            }
686
687            // For now, return a cloned tensor (in real implementation, apply relu)
688            Ok(vec![inputs[0].clone_tensor()])
689        }
690
691        fn subgradient<T>(
692            &self,
693            _ctx: &mut FunctionContext,
694            grad_outputs: &[&dyn AutogradTensor<T>],
695        ) -> Result<Vec<Option<SubgradientSet<T>>>>
696        where
697            T: torsh_core::dtype::TensorElement + num_traits::Float,
698        {
699            if grad_outputs.len() != 1 {
700                return Err(TorshError::AutogradError(
701                    "relu grad requires exactly 1 output".to_string(),
702                ));
703            }
704
705            let grad_output = grad_outputs[0];
706
707            // Primary subgradient: use 1 for x >= 0, 0 for x < 0
708            let primary = grad_output.clone_tensor();
709
710            // Alternative for x = 0: use 0 instead of 1
711            let zero_grad = grad_output.zeros_like();
712
713            let subgrad_set = SubgradientSet {
714                primary,
715                alternatives: vec![zero_grad],
716                selection_strategy: SubgradientSelection::Primary,
717            };
718
719            Ok(vec![Some(subgrad_set)])
720        }
721    }
722
723    /// Maximum function: f(x, y) = max(x, y)
724    /// Subgradient depends on which input is larger
725    #[derive(Debug)]
726    pub struct MaxFunction;
727
728    impl DynFunction for MaxFunction {
729        fn name(&self) -> &str {
730            "max"
731        }
732        fn is_differentiable(&self) -> bool {
733            false
734        }
735    }
736
737    impl SubgradientFunction for MaxFunction {
738        fn forward<T>(
739            &self,
740            _ctx: &mut FunctionContext,
741            inputs: &[&dyn AutogradTensor<T>],
742        ) -> Result<Vec<Box<dyn AutogradTensor<T>>>>
743        where
744            T: torsh_core::dtype::TensorElement + num_traits::Float,
745        {
746            if inputs.len() != 2 {
747                return Err(TorshError::AutogradError(
748                    "max requires exactly 2 inputs".to_string(),
749                ));
750            }
751
752            // For now, return first input (in real implementation, compute element-wise max)
753            Ok(vec![inputs[0].clone_tensor()])
754        }
755
756        fn subgradient<T>(
757            &self,
758            _ctx: &mut FunctionContext,
759            grad_outputs: &[&dyn AutogradTensor<T>],
760        ) -> Result<Vec<Option<SubgradientSet<T>>>>
761        where
762            T: torsh_core::dtype::TensorElement + num_traits::Float,
763        {
764            if grad_outputs.len() != 1 {
765                return Err(TorshError::AutogradError(
766                    "max grad requires exactly 1 output".to_string(),
767                ));
768            }
769
770            let grad_output = grad_outputs[0];
771
772            // Primary: gradient flows to the larger input
773            let grad_x = grad_output.clone_tensor();
774            let grad_y = grad_output.zeros_like();
775
776            // Alternative: when inputs are equal, gradient can be split
777            let half_grad_x = grad_output.mul_scalar(0.5_f64)?;
778            let half_grad_y = grad_output.mul_scalar(0.5_f64)?;
779
780            let subgrad_set_x = SubgradientSet {
781                primary: grad_x,
782                alternatives: vec![half_grad_x],
783                selection_strategy: SubgradientSelection::Primary,
784            };
785
786            let subgrad_set_y = SubgradientSet {
787                primary: grad_y,
788                alternatives: vec![half_grad_y],
789                selection_strategy: SubgradientSelection::Primary,
790            };
791
792            Ok(vec![Some(subgrad_set_x), Some(subgrad_set_y)])
793        }
794    }
795
796    /// L1 norm function: f(x) = ||x||_1 = Σ|x_i|
797    /// Non-differentiable at zero, but has subgradients
798    #[derive(Debug)]
799    pub struct L1NormFunction;
800
801    impl DynFunction for L1NormFunction {
802        fn name(&self) -> &str {
803            "l1_norm"
804        }
805        fn is_differentiable(&self) -> bool {
806            false
807        }
808    }
809
810    impl SubgradientFunction for L1NormFunction {
811        fn forward<T>(
812            &self,
813            _ctx: &mut FunctionContext,
814            inputs: &[&dyn AutogradTensor<T>],
815        ) -> Result<Vec<Box<dyn AutogradTensor<T>>>>
816        where
817            T: torsh_core::dtype::TensorElement + num_traits::Float,
818        {
819            if inputs.len() != 1 {
820                return Err(TorshError::AutogradError(
821                    "l1_norm requires exactly 1 input".to_string(),
822                ));
823            }
824
825            // For now, return a scalar ones tensor (in real implementation, compute L1 norm)
826            Ok(vec![inputs[0].ones_like()])
827        }
828
829        fn subgradient<T>(
830            &self,
831            _ctx: &mut FunctionContext,
832            grad_outputs: &[&dyn AutogradTensor<T>],
833        ) -> Result<Vec<Option<SubgradientSet<T>>>>
834        where
835            T: torsh_core::dtype::TensorElement + num_traits::Float,
836        {
837            if grad_outputs.len() != 1 {
838                return Err(TorshError::AutogradError(
839                    "l1_norm grad requires exactly 1 output".to_string(),
840                ));
841            }
842
843            let grad_output = grad_outputs[0];
844
845            // Primary subgradient: sign function
846            let sign_data: Vec<T> = grad_output
847                .to_vec()
848                .into_iter()
849                .map(|x| {
850                    let zero = <T as num_traits::Zero>::zero();
851                    let one = <T as num_traits::One>::one();
852                    if x > zero {
853                        one
854                    } else if x < zero {
855                        -one
856                    } else {
857                        zero
858                    }
859                })
860                .collect();
861            let primary = grad_output.with_data(sign_data)?;
862
863            // Alternative subgradients for zero elements: any value in [-1, 1]
864            let zero_grad = grad_output.zeros_like();
865            let neg_grad = grad_output.mul_scalar(-1.0_f64)?;
866
867            let subgrad_set = SubgradientSet {
868                primary,
869                alternatives: vec![zero_grad, neg_grad],
870                selection_strategy: SubgradientSelection::MinNorm, // Prefer smaller gradients
871            };
872
873            Ok(vec![Some(subgrad_set)])
874        }
875    }
876}
877
878/// Function serialization and deployment framework
879pub mod serialization {
880    use super::deployment::compute_signature;
881    use super::subgradient_functions::*;
882    use super::*;
883    use std::fs::{self, File};
884    use std::io::{BufReader, BufWriter};
885
886    /// Trait for serializable functions
887    pub trait SerializableFunction: DynFunction {
888        /// Serialize the function to bytes
889        fn serialize(&self) -> Result<Vec<u8>>;
890
891        /// Deserialize the function from bytes
892        fn deserialize(data: &[u8]) -> Result<Box<dyn SerializableFunction>>
893        where
894            Self: Sized;
895
896        /// Get the function's serialization format version
897        fn format_version(&self) -> u32 {
898            1
899        }
900
901        /// Validate the function after deserialization
902        fn validate(&self) -> Result<()> {
903            Ok(())
904        }
905    }
906
907    /// Concrete implementations of SerializableFunction for common functions
908    impl SerializableFunction for AbsFunction {
909        fn serialize(&self) -> Result<Vec<u8>> {
910            let data = serde_json::to_vec(&"abs_function")
911                .map_err(|e| TorshError::AutogradError(format!("Serialization error: {e}")))?;
912            Ok(data)
913        }
914
915        fn deserialize(data: &[u8]) -> Result<Box<dyn SerializableFunction>>
916        where
917            Self: Sized,
918        {
919            let _function_type: String = serde_json::from_slice(data)
920                .map_err(|e| TorshError::AutogradError(format!("Deserialization error: {e}")))?;
921            Ok(Box::new(AbsFunction))
922        }
923    }
924
925    impl SerializableFunction for ReLUFunction {
926        fn serialize(&self) -> Result<Vec<u8>> {
927            let data = serde_json::to_vec(&"relu_function")
928                .map_err(|e| TorshError::AutogradError(format!("Serialization error: {e}")))?;
929            Ok(data)
930        }
931
932        fn deserialize(data: &[u8]) -> Result<Box<dyn SerializableFunction>>
933        where
934            Self: Sized,
935        {
936            let _function_type: String = serde_json::from_slice(data)
937                .map_err(|e| TorshError::AutogradError(format!("Deserialization error: {e}")))?;
938            Ok(Box::new(ReLUFunction))
939        }
940    }
941
942    impl SerializableFunction for MaxFunction {
943        fn serialize(&self) -> Result<Vec<u8>> {
944            let data = serde_json::to_vec(&"max_function")
945                .map_err(|e| TorshError::AutogradError(format!("Serialization error: {e}")))?;
946            Ok(data)
947        }
948
949        fn deserialize(data: &[u8]) -> Result<Box<dyn SerializableFunction>>
950        where
951            Self: Sized,
952        {
953            let _function_type: String = serde_json::from_slice(data)
954                .map_err(|e| TorshError::AutogradError(format!("Deserialization error: {e}")))?;
955            Ok(Box::new(MaxFunction))
956        }
957    }
958
959    impl SerializableFunction for L1NormFunction {
960        fn serialize(&self) -> Result<Vec<u8>> {
961            let data = serde_json::to_vec(&"l1_norm_function")
962                .map_err(|e| TorshError::AutogradError(format!("Serialization error: {e}")))?;
963            Ok(data)
964        }
965
966        fn deserialize(data: &[u8]) -> Result<Box<dyn SerializableFunction>>
967        where
968            Self: Sized,
969        {
970            let _function_type: String = serde_json::from_slice(data)
971                .map_err(|e| TorshError::AutogradError(format!("Deserialization error: {e}")))?;
972            Ok(Box::new(L1NormFunction))
973        }
974    }
975
976    /// Function factory for creating functions from serialized data
977    pub struct FunctionFactory;
978
979    impl FunctionFactory {
980        /// Create a function from a package
981        pub fn create_from_package(
982            package: &FunctionPackage,
983        ) -> Result<Box<dyn SerializableFunction>> {
984            let function_type: String = serde_json::from_slice(&package.function_data)
985                .map_err(|e| TorshError::AutogradError(format!("Deserialization error: {e}")))?;
986
987            match function_type.as_str() {
988                "abs_function" => AbsFunction::deserialize(&package.function_data),
989                "relu_function" => ReLUFunction::deserialize(&package.function_data),
990                "max_function" => MaxFunction::deserialize(&package.function_data),
991                "l1_norm_function" => L1NormFunction::deserialize(&package.function_data),
992                _ => Err(TorshError::AutogradError(format!(
993                    "Unknown function type: {function_type}"
994                ))),
995            }
996        }
997
998        /// Create a package from a serializable function
999        pub fn create_package_from_function(
1000            function: &dyn SerializableFunction,
1001            metadata: FunctionMetadata,
1002        ) -> Result<FunctionPackage> {
1003            let function_data = function.serialize()?;
1004            let signature = compute_signature(&metadata, &function_data);
1005            Ok(FunctionPackage::new(metadata, function_data, signature))
1006        }
1007    }
1008
1009    /// Function package for deployment
1010    #[derive(Debug, Clone, Serialize, Deserialize)]
1011    pub struct FunctionPackage {
1012        /// Function metadata
1013        pub metadata: FunctionMetadata,
1014        /// Serialized function data
1015        pub function_data: Vec<u8>,
1016        /// Package format version
1017        pub format_version: u32,
1018        /// Package signature for verification
1019        pub signature: String,
1020        /// Required runtime dependencies
1021        pub runtime_dependencies: Vec<String>,
1022        /// Minimum supported framework version
1023        pub min_framework_version: String,
1024    }
1025
1026    impl FunctionPackage {
1027        /// Create a new function package
1028        pub fn new(metadata: FunctionMetadata, function_data: Vec<u8>, signature: String) -> Self {
1029            Self {
1030                metadata,
1031                function_data,
1032                format_version: 1,
1033                signature,
1034                runtime_dependencies: vec!["torsh-autograd".to_string()],
1035                min_framework_version: "0.1.0".to_string(),
1036            }
1037        }
1038
1039        /// Verify package integrity
1040        pub fn verify(&self) -> Result<()> {
1041            // Simple checksum verification (in production, use proper cryptographic signatures)
1042            let computed_checksum = self.compute_checksum();
1043            if computed_checksum != self.signature {
1044                return Err(TorshError::AutogradError(
1045                    "Function package signature verification failed".to_string(),
1046                ));
1047            }
1048            Ok(())
1049        }
1050
1051        /// Compute package checksum
1052        fn compute_checksum(&self) -> String {
1053            use std::collections::hash_map::DefaultHasher;
1054            use std::hash::{Hash, Hasher};
1055
1056            let mut hasher = DefaultHasher::new();
1057            self.metadata.name.hash(&mut hasher);
1058            self.metadata.version.hash(&mut hasher);
1059            self.function_data.hash(&mut hasher);
1060            format!("{:x}", hasher.finish())
1061        }
1062
1063        /// Save package to file
1064        pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()> {
1065            let file = File::create(path)?;
1066            let writer = BufWriter::new(file);
1067            serde_json::to_writer_pretty(writer, self)
1068                .map_err(|e| TorshError::AutogradError(format!("Serialization error: {e}")))?;
1069            Ok(())
1070        }
1071
1072        /// Load package from file
1073        pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
1074            let file = File::open(path)?;
1075            let reader = BufReader::new(file);
1076            let package: FunctionPackage = serde_json::from_reader(reader)
1077                .map_err(|e| TorshError::AutogradError(format!("Deserialization error: {e}")))?;
1078            package.verify()?;
1079            Ok(package)
1080        }
1081    }
1082
1083    /// Function deployment manager
1084    pub struct FunctionDeploymentManager {
1085        /// Directory for storing deployed functions
1086        deploy_dir: std::path::PathBuf,
1087        /// Registry of deployed functions
1088        deployed_functions: RwLock<HashMap<String, FunctionPackage>>,
1089    }
1090
1091    impl FunctionDeploymentManager {
1092        /// Create a new deployment manager
1093        pub fn new<P: AsRef<Path>>(deploy_dir: P) -> Result<Self> {
1094            let deploy_dir = deploy_dir.as_ref().to_path_buf();
1095            fs::create_dir_all(&deploy_dir)?;
1096
1097            Ok(Self {
1098                deploy_dir,
1099                deployed_functions: RwLock::new(HashMap::new()),
1100            })
1101        }
1102
1103        /// Deploy a function package
1104        pub fn deploy(&self, package: FunctionPackage) -> Result<()> {
1105            // Verify package before deployment
1106            package.verify()?;
1107
1108            // Check version compatibility
1109            if !self.is_compatible_version(&package.min_framework_version) {
1110                return Err(TorshError::AutogradError(format!(
1111                    "Function {} requires framework version {}, but current version is incompatible",
1112                    package.metadata.name, package.min_framework_version
1113                )));
1114            }
1115
1116            // Save package to deployment directory
1117            let package_path = self
1118                .deploy_dir
1119                .join(format!("{}.pkg", package.metadata.name));
1120            package.save(&package_path)?;
1121
1122            // Register deployed function
1123            let mut deployed = self.deployed_functions.write();
1124            deployed.insert(package.metadata.name.clone(), package);
1125
1126            Ok(())
1127        }
1128
1129        /// Undeploy a function
1130        pub fn undeploy(&self, name: &str) -> Result<()> {
1131            let package_path = self.deploy_dir.join(format!("{}.pkg", name));
1132            if package_path.exists() {
1133                fs::remove_file(package_path)?;
1134            }
1135
1136            let mut deployed = self.deployed_functions.write();
1137            deployed.remove(name);
1138
1139            Ok(())
1140        }
1141
1142        /// List deployed functions
1143        pub fn list_deployed(&self) -> Vec<String> {
1144            self.deployed_functions.read().keys().cloned().collect()
1145        }
1146
1147        /// Get deployed function metadata
1148        pub fn get_deployed_metadata(&self, name: &str) -> Option<FunctionMetadata> {
1149            self.deployed_functions
1150                .read()
1151                .get(name)
1152                .map(|pkg| pkg.metadata.clone())
1153        }
1154
1155        /// Load deployed function
1156        pub fn load_deployed(&self, name: &str) -> Result<Vec<u8>> {
1157            let deployed = self.deployed_functions.read();
1158            let package = deployed.get(name).ok_or_else(|| {
1159                TorshError::AutogradError(format!("Deployed function '{}' not found", name))
1160            })?;
1161            Ok(package.function_data.clone())
1162        }
1163
1164        /// Check framework version compatibility
1165        fn is_compatible_version(&self, required_version: &str) -> bool {
1166            // Simplified version check (in production, use proper semantic versioning)
1167            let current_version = "0.1.0";
1168            required_version <= current_version
1169        }
1170
1171        /// Import function from package file
1172        pub fn import_from_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
1173            let package = FunctionPackage::load(path)?;
1174            self.deploy(package)
1175        }
1176
1177        /// Export function to package file
1178        pub fn export_to_file<P: AsRef<Path>>(&self, name: &str, path: P) -> Result<()> {
1179            let deployed = self.deployed_functions.read();
1180            let package = deployed.get(name).ok_or_else(|| {
1181                TorshError::AutogradError(format!("Deployed function '{}' not found", name))
1182            })?;
1183            package.save(path)
1184        }
1185    }
1186
1187    /// Function library for managing collections of functions
1188    #[derive(Debug, Clone, Serialize, Deserialize)]
1189    pub struct FunctionLibrary {
1190        /// Library name
1191        pub name: String,
1192        /// Library version
1193        pub version: String,
1194        /// Library description
1195        pub description: String,
1196        /// Functions in the library
1197        pub functions: Vec<FunctionPackage>,
1198        /// Library dependencies
1199        pub dependencies: Vec<String>,
1200    }
1201
1202    impl FunctionLibrary {
1203        /// Create a new function library
1204        pub fn new(name: String, version: String, description: String) -> Self {
1205            Self {
1206                name,
1207                version,
1208                description,
1209                functions: Vec::new(),
1210                dependencies: Vec::new(),
1211            }
1212        }
1213
1214        /// Add a function to the library
1215        pub fn add_function(&mut self, package: FunctionPackage) {
1216            self.functions.push(package);
1217        }
1218
1219        /// Add a dependency to the library
1220        pub fn add_dependency(&mut self, dependency: String) {
1221            if !self.dependencies.contains(&dependency) {
1222                self.dependencies.push(dependency);
1223            }
1224        }
1225
1226        /// Save library to file
1227        pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()> {
1228            let file = File::create(path)?;
1229            let writer = BufWriter::new(file);
1230            serde_json::to_writer_pretty(writer, self)
1231                .map_err(|e| TorshError::AutogradError(format!("Serialization error: {e}")))?;
1232            Ok(())
1233        }
1234
1235        /// Load library from file
1236        pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
1237            let file = File::open(path)?;
1238            let reader = BufReader::new(file);
1239            let library: FunctionLibrary = serde_json::from_reader(reader)
1240                .map_err(|e| TorshError::AutogradError(format!("Deserialization error: {e}")))?;
1241            Ok(library)
1242        }
1243
1244        /// Deploy all functions in the library
1245        pub fn deploy_all(&self, manager: &FunctionDeploymentManager) -> Result<()> {
1246            for package in &self.functions {
1247                manager.deploy(package.clone())?;
1248            }
1249            Ok(())
1250        }
1251
1252        /// List function names in the library
1253        pub fn list_functions(&self) -> Vec<String> {
1254            self.functions
1255                .iter()
1256                .map(|pkg| pkg.metadata.name.clone())
1257                .collect()
1258        }
1259    }
1260}
1261
1262/// Function deployment utilities
1263pub mod deployment {
1264    use super::serialization::*;
1265    use super::*;
1266
1267    /// Global deployment manager
1268    static DEPLOYMENT_MANAGER: std::sync::OnceLock<FunctionDeploymentManager> =
1269        std::sync::OnceLock::new();
1270
1271    /// Get the global deployment manager
1272    pub fn global_deployment_manager() -> &'static FunctionDeploymentManager {
1273        DEPLOYMENT_MANAGER.get_or_init(|| {
1274            FunctionDeploymentManager::new("./torsh_functions").unwrap_or_else(|_| {
1275                // Fallback to temporary directory
1276                let temp_dir = std::env::temp_dir().join("torsh_functions");
1277                FunctionDeploymentManager::new(temp_dir)
1278                    .expect("Failed to create deployment manager")
1279            })
1280        })
1281    }
1282
1283    /// Deploy a function globally
1284    pub fn deploy_function(package: FunctionPackage) -> Result<()> {
1285        global_deployment_manager().deploy(package)
1286    }
1287
1288    /// Undeploy a function globally
1289    pub fn undeploy_function(name: &str) -> Result<()> {
1290        global_deployment_manager().undeploy(name)
1291    }
1292
1293    /// List all deployed functions
1294    pub fn list_deployed_functions() -> Vec<String> {
1295        global_deployment_manager().list_deployed()
1296    }
1297
1298    /// Get deployed function metadata
1299    pub fn get_deployed_function_metadata(name: &str) -> Option<FunctionMetadata> {
1300        global_deployment_manager().get_deployed_metadata(name)
1301    }
1302
1303    /// Create a function package from metadata and data
1304    pub fn create_function_package(
1305        metadata: FunctionMetadata,
1306        function_data: Vec<u8>,
1307    ) -> FunctionPackage {
1308        let signature = compute_signature(&metadata, &function_data);
1309        FunctionPackage::new(metadata, function_data, signature)
1310    }
1311
1312    /// Compute function signature for verification
1313    pub fn compute_signature(metadata: &FunctionMetadata, data: &[u8]) -> String {
1314        use std::collections::hash_map::DefaultHasher;
1315        use std::hash::{Hash, Hasher};
1316
1317        let mut hasher = DefaultHasher::new();
1318        metadata.name.hash(&mut hasher);
1319        metadata.version.hash(&mut hasher);
1320        data.hash(&mut hasher);
1321        format!("{:x}", hasher.finish())
1322    }
1323
1324    /// Function deployment builder
1325    pub struct FunctionDeploymentBuilder {
1326        metadata: FunctionMetadata,
1327        function_data: Option<Vec<u8>>,
1328        dependencies: Vec<String>,
1329    }
1330
1331    impl FunctionDeploymentBuilder {
1332        /// Create a new deployment builder
1333        pub fn new(name: String) -> Self {
1334            Self {
1335                metadata: FunctionMetadata {
1336                    name,
1337                    is_differentiable: true,
1338                    memory_complexity: MemoryComplexity::Linear,
1339                    computational_complexity: ComputationalComplexity::Linear,
1340                    is_fusable: false,
1341                    version: "1.0.0".to_string(),
1342                    description: "".to_string(),
1343                    author: "".to_string(),
1344                    created_at: SystemTime::now()
1345                        .duration_since(SystemTime::UNIX_EPOCH)
1346                        .unwrap_or_else(|_| std::time::Duration::from_secs(0))
1347                        .as_secs()
1348                        .to_string(),
1349                    checksum: "".to_string(),
1350                    dependencies: vec![],
1351                },
1352                function_data: None,
1353                dependencies: vec![],
1354            }
1355        }
1356
1357        /// Set function version
1358        pub fn version(mut self, version: String) -> Self {
1359            self.metadata.version = version;
1360            self
1361        }
1362
1363        /// Set function description
1364        pub fn description(mut self, description: String) -> Self {
1365            self.metadata.description = description;
1366            self
1367        }
1368
1369        /// Set function author
1370        pub fn author(mut self, author: String) -> Self {
1371            self.metadata.author = author;
1372            self
1373        }
1374
1375        /// Set function data
1376        pub fn data(mut self, data: Vec<u8>) -> Self {
1377            self.function_data = Some(data);
1378            self
1379        }
1380
1381        /// Add dependency
1382        pub fn dependency(mut self, dependency: String) -> Self {
1383            self.dependencies.push(dependency);
1384            self
1385        }
1386
1387        /// Set memory complexity
1388        pub fn memory_complexity(mut self, complexity: MemoryComplexity) -> Self {
1389            self.metadata.memory_complexity = complexity;
1390            self
1391        }
1392
1393        /// Set computational complexity
1394        pub fn computational_complexity(mut self, complexity: ComputationalComplexity) -> Self {
1395            self.metadata.computational_complexity = complexity;
1396            self
1397        }
1398
1399        /// Set fusable flag
1400        pub fn fusable(mut self, fusable: bool) -> Self {
1401            self.metadata.is_fusable = fusable;
1402            self
1403        }
1404
1405        /// Set differentiable flag
1406        pub fn differentiable(mut self, differentiable: bool) -> Self {
1407            self.metadata.is_differentiable = differentiable;
1408            self
1409        }
1410
1411        /// Build the function package
1412        pub fn build(mut self) -> Result<FunctionPackage> {
1413            let function_data = self
1414                .function_data
1415                .ok_or_else(|| TorshError::AutogradError("Function data not set".to_string()))?;
1416
1417            self.metadata.dependencies = self.dependencies;
1418            Ok(create_function_package(self.metadata, function_data))
1419        }
1420    }
1421}
1422
1423#[cfg(test)]
1424mod tests {
1425    use super::*;
1426
1427    #[test]
1428    fn test_function_registry() {
1429        let registry = FunctionRegistry::new();
1430        let scaled_add = examples::ScaledAdd { scale: 2.0 };
1431
1432        // Test registration
1433        assert!(registry
1434            .register("scaled_add".to_string(), scaled_add)
1435            .is_ok());
1436
1437        // Test duplicate registration fails
1438        let scaled_add2 = examples::ScaledAdd { scale: 3.0 };
1439        assert!(registry
1440            .register("scaled_add".to_string(), scaled_add2)
1441            .is_err());
1442
1443        // Test retrieval
1444        assert!(registry.get("scaled_add").is_some());
1445        assert!(registry.get("nonexistent").is_none());
1446
1447        // Test listing
1448        let functions = registry.list_functions();
1449        assert_eq!(functions.len(), 1);
1450        assert!(functions.contains(&"scaled_add".to_string()));
1451
1452        // Test metadata
1453        let metadata = registry.get_metadata("scaled_add").unwrap();
1454        assert_eq!(metadata.name, "ScaledAdd");
1455        assert!(metadata.is_differentiable);
1456        assert!(metadata.is_fusable);
1457    }
1458
1459    #[test]
1460    fn test_function_context() {
1461        let mut ctx = FunctionContext::new();
1462
1463        // Test saving and retrieving values
1464        ctx.save_value(42i32);
1465        ctx.save_value(3.14f64);
1466
1467        assert_eq!(*ctx.get_saved_value::<i32>(0).unwrap(), 42);
1468        assert_eq!(*ctx.get_saved_value::<f64>(1).unwrap(), 3.14);
1469
1470        // Test type mismatch
1471        assert!(ctx.get_saved_value::<f32>(0).is_err());
1472    }
1473
1474    #[test]
1475    fn test_function_serialization() {
1476        use super::deployment::create_function_package;
1477
1478        // Create test metadata
1479        let metadata = FunctionMetadata {
1480            name: "test_function".to_string(),
1481            is_differentiable: true,
1482            memory_complexity: MemoryComplexity::Linear,
1483            computational_complexity: ComputationalComplexity::Linear,
1484            is_fusable: false,
1485            version: "1.0.0".to_string(),
1486            description: "Test function for serialization".to_string(),
1487            author: "Test Author".to_string(),
1488            created_at: "1640995200".to_string(), // Fixed timestamp for testing
1489            checksum: "".to_string(),
1490            dependencies: vec!["torsh-autograd".to_string()],
1491        };
1492
1493        // Create test function data
1494        let function_data = vec![1, 2, 3, 4, 5];
1495
1496        // Create function package
1497        let package = create_function_package(metadata.clone(), function_data.clone());
1498
1499        // Test package verification
1500        assert!(package.verify().is_ok());
1501
1502        // Test package metadata
1503        assert_eq!(package.metadata.name, "test_function");
1504        assert_eq!(package.metadata.version, "1.0.0");
1505        assert_eq!(package.function_data, function_data);
1506    }
1507
1508    #[test]
1509    fn test_function_deployment_builder() {
1510        use super::deployment::*;
1511
1512        let builder = FunctionDeploymentBuilder::new("test_func".to_string())
1513            .version("2.0.0".to_string())
1514            .description("Test function".to_string())
1515            .author("Test Author".to_string())
1516            .data(vec![1, 2, 3])
1517            .dependency("test_dep".to_string())
1518            .memory_complexity(MemoryComplexity::Constant)
1519            .computational_complexity(ComputationalComplexity::Quadratic)
1520            .fusable(true)
1521            .differentiable(false);
1522
1523        let package = builder.build().unwrap();
1524
1525        assert_eq!(package.metadata.name, "test_func");
1526        assert_eq!(package.metadata.version, "2.0.0");
1527        assert_eq!(package.metadata.description, "Test function");
1528        assert_eq!(package.metadata.author, "Test Author");
1529        assert_eq!(package.function_data, vec![1, 2, 3]);
1530        assert_eq!(package.metadata.dependencies, vec!["test_dep"]);
1531        assert_eq!(
1532            package.metadata.memory_complexity,
1533            MemoryComplexity::Constant
1534        );
1535        assert_eq!(
1536            package.metadata.computational_complexity,
1537            ComputationalComplexity::Quadratic
1538        );
1539        assert!(package.metadata.is_fusable);
1540        assert!(!package.metadata.is_differentiable);
1541    }
1542
1543    #[test]
1544    fn test_function_library() {
1545        use super::deployment::*;
1546        use super::serialization::*;
1547
1548        let mut library = FunctionLibrary::new(
1549            "test_library".to_string(),
1550            "1.0.0".to_string(),
1551            "Test function library".to_string(),
1552        );
1553
1554        // Create test packages
1555        let package1 = FunctionDeploymentBuilder::new("func1".to_string())
1556            .data(vec![1, 2, 3])
1557            .build()
1558            .unwrap();
1559
1560        let package2 = FunctionDeploymentBuilder::new("func2".to_string())
1561            .data(vec![4, 5, 6])
1562            .build()
1563            .unwrap();
1564
1565        // Add packages to library
1566        library.add_function(package1);
1567        library.add_function(package2);
1568        library.add_dependency("dep1".to_string());
1569        library.add_dependency("dep2".to_string());
1570
1571        // Test library properties
1572        assert_eq!(library.name, "test_library");
1573        assert_eq!(library.version, "1.0.0");
1574        assert_eq!(library.functions.len(), 2);
1575        assert_eq!(library.dependencies, vec!["dep1", "dep2"]);
1576
1577        // Test function listing
1578        let function_names = library.list_functions();
1579        assert!(function_names.contains(&"func1".to_string()));
1580        assert!(function_names.contains(&"func2".to_string()));
1581    }
1582
1583    #[test]
1584    fn test_function_serialization_implementations() {
1585        use super::serialization::*;
1586        use super::subgradient_functions::*;
1587
1588        // Test AbsFunction serialization
1589        let abs_func = AbsFunction;
1590        let serialized = abs_func.serialize().unwrap();
1591        let _deserialized = AbsFunction::deserialize(&serialized).unwrap();
1592
1593        // Verify the function type matches
1594        let function_type: String = serde_json::from_slice(&serialized).unwrap();
1595        assert_eq!(function_type, "abs_function");
1596
1597        // Test ReLUFunction serialization
1598        let relu_func = ReLUFunction;
1599        let serialized = relu_func.serialize().unwrap();
1600        let _deserialized = ReLUFunction::deserialize(&serialized).unwrap();
1601
1602        let function_type: String = serde_json::from_slice(&serialized).unwrap();
1603        assert_eq!(function_type, "relu_function");
1604
1605        // Test MaxFunction serialization
1606        let max_func = MaxFunction;
1607        let serialized = max_func.serialize().unwrap();
1608        let _deserialized = MaxFunction::deserialize(&serialized).unwrap();
1609
1610        let function_type: String = serde_json::from_slice(&serialized).unwrap();
1611        assert_eq!(function_type, "max_function");
1612
1613        // Test L1NormFunction serialization
1614        let l1_func = L1NormFunction;
1615        let serialized = l1_func.serialize().unwrap();
1616        let _deserialized = L1NormFunction::deserialize(&serialized).unwrap();
1617
1618        let function_type: String = serde_json::from_slice(&serialized).unwrap();
1619        assert_eq!(function_type, "l1_norm_function");
1620    }
1621
1622    #[test]
1623    fn test_function_factory() {
1624        use super::deployment::create_function_package;
1625        use super::serialization::*;
1626        use super::subgradient_functions::*;
1627
1628        // Create a test function package
1629        let metadata = FunctionMetadata {
1630            name: "test_abs".to_string(),
1631            is_differentiable: true,
1632            memory_complexity: MemoryComplexity::Linear,
1633            computational_complexity: ComputationalComplexity::Linear,
1634            is_fusable: true,
1635            version: "1.0.0".to_string(),
1636            description: "Test absolute value function".to_string(),
1637            author: "Test Author".to_string(),
1638            created_at: "2024-01-01T00:00:00Z".to_string(),
1639            checksum: "".to_string(),
1640            dependencies: vec![],
1641        };
1642
1643        let abs_func = AbsFunction;
1644        let function_data = abs_func.serialize().unwrap();
1645        let package = create_function_package(metadata, function_data);
1646
1647        // Test factory creation
1648        let created_function = FunctionFactory::create_from_package(&package).unwrap();
1649
1650        // Verify the function can be serialized again
1651        let re_serialized = created_function.serialize().unwrap();
1652        let function_type: String = serde_json::from_slice(&re_serialized).unwrap();
1653        assert_eq!(function_type, "abs_function");
1654    }
1655
1656    #[test]
1657    fn test_function_package_from_serializable() {
1658        use super::serialization::*;
1659        use super::subgradient_functions::*;
1660
1661        let metadata = FunctionMetadata {
1662            name: "test_relu".to_string(),
1663            is_differentiable: true,
1664            memory_complexity: MemoryComplexity::Constant,
1665            computational_complexity: ComputationalComplexity::Linear,
1666            is_fusable: true,
1667            version: "1.0.0".to_string(),
1668            description: "Test ReLU function".to_string(),
1669            author: "Test Author".to_string(),
1670            created_at: "2024-01-01T00:00:00Z".to_string(),
1671            checksum: "".to_string(),
1672            dependencies: vec![],
1673        };
1674
1675        let relu_func = ReLUFunction;
1676        let package = FunctionFactory::create_package_from_function(&relu_func, metadata).unwrap();
1677
1678        // Test package verification
1679        assert!(package.verify().is_ok());
1680        assert_eq!(package.metadata.name, "test_relu");
1681
1682        // Test that we can recreate the function from the package
1683        let recreated_function = FunctionFactory::create_from_package(&package).unwrap();
1684        let serialized_again = recreated_function.serialize().unwrap();
1685        let function_type: String = serde_json::from_slice(&serialized_again).unwrap();
1686        assert_eq!(function_type, "relu_function");
1687    }
1688}