Skip to main content

trustformers_core/
traits.rs

1//! Core traits defining the fundamental abstractions of TrustformeRS.
2//!
3//! This module contains the essential traits that form the foundation of the TrustformeRS
4//! transformer library. These traits define the interfaces for models, layers, configuration,
5//! tokenization, optimization, and parameter initialization.
6//!
7//! # Overview
8//!
9//! The traits in this module establish a consistent API across all transformer implementations:
10//!
11//! - [`Model`]: The main trait for transformer models with forward pass and loading capabilities
12//! - [`Layer`]: Building blocks for neural network architectures
13//! - [`Config`]: Configuration management for models and components
14//! - [`WeightReader`]: Interface for loading pretrained model weights
15//! - [`Tokenizer`]: Text tokenization and encoding/decoding
16//! - [`Optimizer`]: Parameter optimization algorithms
17//! - [`ParameterInit`]: Weight initialization strategies
18//!
19//! # Examples
20//!
21//! ```no_run
22//! use trustformers_core::traits::{Model, Config};
23//! use trustformers_core::tensor::Tensor;
24//! use trustformers_core::errors::Result;
25//! use std::io::Read;
26//! use serde::{Deserialize, Serialize};
27//!
28//! // Example model configuration
29//! #[derive(Debug, Deserialize, Serialize)]
30//! struct MyConfig { hidden_size: usize }
31//! impl Config for MyConfig {
32//!     fn architecture(&self) -> &'static str { "my_model" }
33//! }
34//!
35//! // Example model implementation
36//! struct MyModel {
37//!     config: MyConfig,
38//!     // ... model layers
39//! }
40//!
41//! impl Model for MyModel {
42//!     type Config = MyConfig;
43//!     type Input = Tensor;
44//!     type Output = Tensor;
45//!
46//!     fn forward(&self, input: Self::Input) -> Result<Self::Output> {
47//!         // Model forward pass implementation
48//!         Ok(input)
49//!     }
50//!
51//!     fn load_pretrained(&mut self, _reader: &mut dyn Read) -> Result<()> {
52//!         // Load pretrained weights
53//!         Ok(())
54//!     }
55//!
56//!     fn get_config(&self) -> &Self::Config {
57//!         &self.config
58//!     }
59//!
60//!     fn num_parameters(&self) -> usize { 0 }
61//! }
62//! ```
63
64use crate::errors::Result;
65use crate::tensor::Tensor;
66use serde::{Deserialize, Serialize};
67use std::io::Read;
68
69/// The main trait for transformer models.
70///
71/// This trait defines the interface that all transformer models must implement,
72/// providing a consistent API for forward passes, weight loading, and configuration access.
73///
74/// # Type Parameters
75///
76/// - `Config`: The configuration type for this model, must implement [`Config`]
77/// - `Input`: The input type for the model's forward pass
78/// - `Output`: The output type produced by the model
79///
80/// # Thread Safety
81///
82/// Models must be `Send + Sync` to support multi-threaded inference and training.
83///
84/// # Example
85///
86/// ```no_run
87/// use trustformers_core::traits::{Model, Config};
88/// use trustformers_core::tensor::Tensor;
89/// use trustformers_core::errors::Result;
90/// use std::io::Read;
91/// use serde::{Deserialize, Serialize};
92///
93/// #[derive(Deserialize, Serialize)]
94/// struct BertConfig {
95///     hidden_size: usize,
96///     num_attention_heads: usize,
97///     // ... other config fields
98/// }
99///
100/// impl Config for BertConfig {
101///     fn architecture(&self) -> &'static str {
102///         "bert"
103///     }
104/// }
105///
106/// struct BertModel {
107///     config: BertConfig,
108///     // ... model layers
109/// }
110///
111/// impl Model for BertModel {
112///     type Config = BertConfig;
113///     type Input = Tensor;
114///     type Output = Tensor;
115///
116///     fn forward(&self, input: Self::Input) -> Result<Self::Output> {
117///         // BERT forward pass implementation
118///         Ok(input)
119///     }
120///
121///     fn load_pretrained(&mut self, _reader: &mut dyn Read) -> Result<()> {
122///         // Load BERT weights from reader
123///         Ok(())
124///     }
125///
126///     fn get_config(&self) -> &Self::Config {
127///         &self.config
128///     }
129///
130///     fn num_parameters(&self) -> usize { 0 }
131/// }
132/// ```
133pub trait Model: Send + Sync {
134    type Config: Config;
135    type Input;
136    type Output;
137
138    /// Performs a forward pass through the model.
139    ///
140    /// # Arguments
141    ///
142    /// * `input` - The input data for the model
143    ///
144    /// # Returns
145    ///
146    /// Returns `Ok(output)` on success, or an error if the forward pass fails.
147    ///
148    /// # Errors
149    ///
150    /// May return errors for:
151    /// - Invalid input dimensions
152    /// - Numerical computation errors
153    /// - Out of memory conditions
154    fn forward(&self, input: Self::Input) -> Result<Self::Output>;
155
156    /// Loads pretrained weights into the model.
157    ///
158    /// This method reads model weights from a reader (typically a file or network stream)
159    /// and updates the model's parameters accordingly.
160    ///
161    /// # Arguments
162    ///
163    /// * `reader` - A reader providing access to the pretrained weight data
164    ///
165    /// # Returns
166    ///
167    /// Returns `Ok(())` on successful loading, or an error if loading fails.
168    ///
169    /// # Errors
170    ///
171    /// May return errors for:
172    /// - IO errors while reading
173    /// - Incompatible weight formats
174    /// - Mismatched tensor shapes
175    fn load_pretrained(&mut self, reader: &mut dyn Read) -> Result<()>;
176
177    /// Returns a reference to the model's configuration.
178    ///
179    /// # Returns
180    ///
181    /// A reference to the model's configuration object.
182    fn get_config(&self) -> &Self::Config;
183
184    /// Returns the total number of parameters in the model.
185    ///
186    /// This method calculates the total number of trainable parameters
187    /// across all layers in the model. It's useful for compression metrics,
188    /// model size analysis, and memory usage calculations.
189    ///
190    /// # Returns
191    ///
192    /// The total number of parameters as a `usize`.
193    ///
194    /// # Example
195    ///
196    /// ```no_run
197    /// use trustformers_core::traits::Model;
198    ///
199    /// fn analyze_model_size<M: Model>(model: &M) {
200    ///     let params = model.num_parameters();
201    ///     let memory_mb = params * 4 / (1024 * 1024); // Assuming f32 weights
202    ///     println!("Model has {} parameters ({} MB)", params, memory_mb);
203    /// }
204    /// ```
205    fn num_parameters(&self) -> usize;
206
207    /// Enumerates the model's parameters as `(name, tensor)` pairs.
208    ///
209    /// This is the canonical way to read a model's weights without knowing its
210    /// concrete type. Names should follow the checkpoint convention used by the
211    /// model family (for example `encoder.layer.0.attention.self.query.weight`),
212    /// because downstream tooling keys off them.
213    ///
214    /// # Contract
215    ///
216    /// * Every returned name must be unique.
217    /// * The returned tensors must be the *live* parameters of the model, not
218    ///   copies that were synthesised on the fly.
219    /// * The order should be stable across calls on an unmodified model so that
220    ///   serialised artifacts are reproducible.
221    ///
222    /// # Default Implementation
223    ///
224    /// The default returns an empty vector, so that existing implementations keep
225    /// compiling. **Model implementations that want to be exportable must override
226    /// it**: every exporter in [`crate::export`] refuses to write a file for a model
227    /// that exposes no named tensors, rather than inventing weights. The same is
228    /// true for the checkpoint writers and weight converters.
229    ///
230    /// # Example
231    ///
232    /// ```no_run
233    /// use trustformers_core::traits::Model;
234    ///
235    /// fn total_bytes<M: Model>(model: &M) -> usize {
236    ///     model
237    ///         .named_tensors()
238    ///         .iter()
239    ///         .map(|(_, tensor)| tensor.size_bytes())
240    ///         .sum()
241    /// }
242    /// ```
243    fn named_tensors(&self) -> Vec<(String, &Tensor)> {
244        Vec::new()
245    }
246
247    /// Mutable counterpart of [`Model::named_tensors`].
248    ///
249    /// Used by weight loaders to copy checkpoint tensors into a live model. The
250    /// same contract applies: unique names, live parameters, stable order. The
251    /// default returns an empty vector, which makes weight loading fail loudly
252    /// instead of silently doing nothing.
253    fn named_tensors_mut(&mut self) -> Vec<(String, &mut Tensor)> {
254        Vec::new()
255    }
256}
257
258/// A building block for neural network architectures.
259///
260/// The `Layer` trait represents a single computational unit in a neural network,
261/// such as a linear transformation, attention mechanism, or normalization layer.
262/// Layers can be composed together to build complete models.
263///
264/// # Type Parameters
265///
266/// - `Input`: The input type accepted by this layer
267/// - `Output`: The output type produced by this layer
268///
269/// # Thread Safety
270///
271/// Layers must be `Send + Sync` to support parallel computation.
272///
273/// # Example
274///
275/// ```no_run
276/// use trustformers_core::traits::Layer;
277/// use trustformers_core::tensor::Tensor;
278/// use trustformers_core::errors::Result;
279///
280/// struct LinearLayer {
281///     weight: Tensor,
282///     bias: Option<Tensor>,
283/// }
284///
285/// impl Layer for LinearLayer {
286///     type Input = Tensor;
287///     type Output = Tensor;
288///
289///     fn forward(&self, input: Self::Input) -> Result<Self::Output> {
290///         // Compute linear transformation: y = xW^T + b
291///         let output = input.matmul(&self.weight.transpose(0, 1)?)?;
292///         if let Some(bias) = &self.bias {
293///             output.add(bias)
294///         } else {
295///             Ok(output)
296///         }
297///     }
298/// }
299/// ```
300pub trait Layer: Send + Sync {
301    type Input;
302    type Output;
303
304    /// Performs the forward computation of this layer.
305    ///
306    /// # Arguments
307    ///
308    /// * `input` - The input data to process
309    ///
310    /// # Returns
311    ///
312    /// Returns `Ok(output)` containing the layer's output, or an error if computation fails.
313    ///
314    /// # Errors
315    ///
316    /// May return errors for:
317    /// - Invalid input dimensions
318    /// - Numerical errors during computation
319    /// - Resource allocation failures
320    fn forward(&self, input: Self::Input) -> Result<Self::Output>;
321
322    /// Performs the forward computation **without taking ownership** of the input.
323    ///
324    /// # Why this exists
325    ///
326    /// Attention projects one hidden-state tensor into query, key and value. With
327    /// an owning-only API that is three deep copies of a `[batch, seq, hidden]`
328    /// tensor per attention block, per forward pass — pure waste, because none of
329    /// the projection code needs to own its input. Layers that can compute from a
330    /// borrow override this method; the attention layers call it.
331    ///
332    /// # Contract
333    ///
334    /// An override **must** produce exactly the same output as
335    /// [`Layer::forward`] for the same input. The two are checked against each
336    /// other in the layer test suites.
337    ///
338    /// # Default Implementation
339    ///
340    /// Clones the input and delegates to [`Layer::forward`], so every existing
341    /// implementation keeps working unchanged. A type that overrides
342    /// `forward_ref` must therefore implement `forward` in terms of
343    /// `forward_ref` (or independently) — never the other way round, which would
344    /// recurse forever.
345    ///
346    /// # Errors
347    ///
348    /// The same conditions as [`Layer::forward`].
349    fn forward_ref(&self, input: &Self::Input) -> Result<Self::Output>
350    where
351        Self::Input: Clone,
352    {
353        self.forward(input.clone())
354    }
355}
356
357/// Configuration trait for models and components.
358///
359/// This trait provides a standardized interface for configuration objects
360/// that can be serialized, deserialized, and validated. All model configurations
361/// must implement this trait to ensure compatibility with the TrustformeRS ecosystem.
362///
363/// # Requirements
364///
365/// Implementing types must be serializable and deserializable using serde.
366///
367/// # Example
368///
369/// ```no_run
370/// use trustformers_core::traits::Config;
371/// use trustformers_core::errors::{Result, TrustformersError};
372/// use serde::{Deserialize, Serialize};
373///
374/// #[derive(Debug, Clone, Deserialize, Serialize)]
375/// struct GPT2Config {
376///     vocab_size: usize,
377///     hidden_size: usize,
378///     num_layers: usize,
379///     num_heads: usize,
380/// }
381///
382/// impl Config for GPT2Config {
383///     fn validate(&self) -> Result<()> {
384///         if self.hidden_size % self.num_heads != 0 {
385///             return Err(TrustformersError::invalid_input(
386///                 "hidden_size must be divisible by num_heads".to_string(),
387///             ));
388///         }
389///         Ok(())
390///     }
391///
392///     fn architecture(&self) -> &'static str {
393///         "gpt2"
394///     }
395/// }
396/// ```
397pub trait Config: for<'de> Deserialize<'de> + Serialize {
398    /// Validates the configuration for correctness.
399    ///
400    /// This method should check that all configuration parameters are valid
401    /// and compatible with each other. The default implementation accepts
402    /// all configurations as valid.
403    ///
404    /// # Returns
405    ///
406    /// Returns `Ok(())` if the configuration is valid, or an error describing
407    /// the validation failure.
408    ///
409    /// # Example
410    ///
411    /// Common validations include:
412    /// - Checking that dimensions are compatible
413    /// - Verifying that values are within acceptable ranges
414    /// - Ensuring required fields are properly set
415    fn validate(&self) -> Result<()> {
416        Ok(())
417    }
418
419    /// Returns the architecture name for this configuration.
420    ///
421    /// This should return a static string identifying the model architecture,
422    /// such as "bert", "gpt2", "t5", etc. This is used for model registration
423    /// and automatic model selection.
424    ///
425    /// # Returns
426    ///
427    /// A static string slice containing the architecture name.
428    fn architecture(&self) -> &'static str;
429}
430
431/// Interface for reading model weights from various sources.
432///
433/// `WeightReader` provides an abstraction over different weight storage formats,
434/// allowing models to load pretrained parameters from files, network sources,
435/// or other storage backends.
436///
437/// # Supported Formats
438///
439/// Implementations may support various formats including:
440/// - SafeTensors (.safetensors)
441/// - PyTorch checkpoints (.pt, .bin)
442/// - NumPy arrays (.npz)
443/// - Custom formats
444///
445/// # Example
446///
447/// ```no_run
448/// use trustformers_core::traits::WeightReader;
449/// use trustformers_core::tensor::Tensor;
450/// use trustformers_core::errors::Result;
451///
452/// struct SafeTensorsReader {
453///     // ... implementation details
454/// }
455///
456/// impl WeightReader for SafeTensorsReader {
457///     fn read_tensor(&mut self, _name: &str) -> Result<Tensor> {
458///         // Read tensor from SafeTensors file
459///         Ok(Tensor::zeros(&[768, 768])?)
460///     }
461///
462///     fn list_tensors(&self) -> Vec<String> {
463///         vec![
464///             "bert.embeddings.word_embeddings.weight".to_string(),
465///             "bert.encoder.layer.0.attention.self.query.weight".to_string(),
466///             // ... more tensor names
467///         ]
468///     }
469/// }
470/// ```
471pub trait WeightReader {
472    /// Reads a tensor by name from the weight source.
473    ///
474    /// # Arguments
475    ///
476    /// * `name` - The name/key of the tensor to read (e.g., "encoder.layer.0.weight")
477    ///
478    /// # Returns
479    ///
480    /// Returns `Ok(tensor)` containing the requested tensor, or an error if the
481    /// tensor cannot be found or loaded.
482    ///
483    /// # Errors
484    ///
485    /// May return errors for:
486    /// - Tensor not found with the given name
487    /// - IO errors while reading
488    /// - Corrupted or invalid tensor data
489    /// - Unsupported tensor format
490    fn read_tensor(&mut self, name: &str) -> Result<Tensor>;
491
492    /// Lists all available tensor names in the weight source.
493    ///
494    /// This method is useful for debugging and for discovering the structure
495    /// of saved model weights.
496    ///
497    /// # Returns
498    ///
499    /// A vector containing the names of all available tensors.
500    fn list_tensors(&self) -> Vec<String>;
501}
502
503/// Text tokenization interface for transformer models.
504///
505/// The `Tokenizer` trait provides methods for converting between text and token IDs,
506/// which is essential for preparing input data for transformer models. Implementations
507/// may use various tokenization algorithms such as WordPiece, BPE, or SentencePiece.
508///
509/// # Thread Safety
510///
511/// Tokenizers must be `Send + Sync` to support concurrent tokenization.
512///
513/// # Example
514///
515/// ```no_run
516/// use trustformers_core::traits::{Tokenizer, TokenizedInput};
517/// use trustformers_core::errors::Result;
518/// use std::collections::HashMap;
519///
520/// struct BertTokenizer {
521///     vocab: HashMap<String, u32>,
522///     // ... other fields
523/// }
524///
525/// impl Tokenizer for BertTokenizer {
526///     fn encode(&self, _text: &str) -> Result<TokenizedInput> {
527///         // Tokenize text into subwords
528///         let tokens: Vec<u32> = vec![101, 2023, 2003, 1037, 3231, 102]; // [CLS] this is a test [SEP]
529///         Ok(TokenizedInput::new(tokens, vec![1; 6]))
530///     }
531///
532///     fn encode_pair(&self, text: &str, text2: &str) -> Result<TokenizedInput> {
533///         // Encode two texts for tasks like question answering
534///         let tokens1 = self.encode(text)?;
535///         let tokens2 = self.encode(text2)?;
536///         // Combine tokens with separator
537///         let len1 = tokens1.input_ids.len();
538///         let len2 = tokens2.input_ids.len();
539///         let mut combined_ids = tokens1.input_ids;
540///         combined_ids.extend_from_slice(&tokens2.input_ids);
541///         let combined_len = combined_ids.len();
542///         Ok(TokenizedInput::with_token_type_ids(
543///             combined_ids,
544///             vec![1; combined_len],
545///             Some(vec![0; len1].into_iter().chain(vec![1; len2]).collect()),
546///         ))
547///     }
548///
549///     fn decode(&self, _ids: &[u32]) -> Result<String> {
550///         // Convert token IDs back to text
551///         Ok("this is a test".to_string())
552///     }
553///
554///     fn vocab_size(&self) -> usize {
555///         30522 // BERT base vocabulary size
556///     }
557///
558///     fn get_vocab(&self) -> HashMap<String, u32> {
559///         self.vocab.clone()
560///     }
561///
562///     fn token_to_id(&self, token: &str) -> Option<u32> {
563///         self.vocab.get(token).copied()
564///     }
565///
566///     fn id_to_token(&self, id: u32) -> Option<String> {
567///         self.vocab.iter().find(|(_, &v)| v == id).map(|(k, _)| k.clone())
568///     }
569/// }
570/// ```
571pub trait Tokenizer: Send + Sync {
572    /// Encodes a single text string into tokens.
573    ///
574    /// # Arguments
575    ///
576    /// * `text` - The input text to tokenize
577    ///
578    /// # Returns
579    ///
580    /// Returns a `TokenizedInput` containing:
581    /// - `input_ids`: The token IDs
582    /// - `attention_mask`: Binary mask indicating real vs padding tokens
583    /// - `token_type_ids`: Optional segment IDs for models like BERT
584    ///
585    /// # Errors
586    ///
587    /// May return errors for:
588    /// - Invalid UTF-8 sequences
589    /// - Text exceeding maximum length
590    /// - Unknown tokens that cannot be handled
591    fn encode(&self, text: &str) -> Result<TokenizedInput>;
592
593    /// Encodes a pair of texts for sequence-pair tasks.
594    ///
595    /// This method is used for tasks that require two input sequences,
596    /// such as question answering, textual entailment, or sequence classification.
597    ///
598    /// # Arguments
599    ///
600    /// * `text` - The first text sequence
601    /// * `text2` - The second text sequence
602    ///
603    /// # Returns
604    ///
605    /// Returns a `TokenizedInput` with both sequences encoded and separated
606    /// by appropriate special tokens (e.g., `[SEP]` for BERT).
607    ///
608    /// # Errors
609    ///
610    /// May return errors for the same reasons as `encode()`.
611    fn encode_pair(&self, text: &str, text2: &str) -> Result<TokenizedInput>;
612
613    /// Decodes token IDs back into text.
614    ///
615    /// # Arguments
616    ///
617    /// * `ids` - The token IDs to decode
618    ///
619    /// # Returns
620    ///
621    /// Returns the decoded text string. Special tokens may be included
622    /// or excluded depending on the implementation.
623    ///
624    /// # Errors
625    ///
626    /// May return errors for:
627    /// - Invalid token IDs
628    /// - Decoding errors
629    fn decode(&self, ids: &[u32]) -> Result<String>;
630
631    /// Returns the size of the tokenizer's vocabulary.
632    ///
633    /// # Returns
634    ///
635    /// The total number of tokens in the vocabulary.
636    fn vocab_size(&self) -> usize;
637
638    /// Returns a copy of the vocabulary as a mapping from tokens to IDs.
639    ///
640    /// # Returns
641    ///
642    /// A HashMap containing the vocabulary mapping.
643    fn get_vocab(&self) -> std::collections::HashMap<String, u32>;
644
645    /// Converts a token string to its corresponding ID.
646    ///
647    /// # Arguments
648    ///
649    /// * `token` - The token string to convert
650    ///
651    /// # Returns
652    ///
653    /// The token ID if the token exists in the vocabulary, None otherwise.
654    fn token_to_id(&self, token: &str) -> Option<u32>;
655
656    /// Converts a token ID to its corresponding token string.
657    ///
658    /// # Arguments
659    ///
660    /// * `id` - The token ID to convert
661    ///
662    /// # Returns
663    ///
664    /// The token string if the ID exists in the vocabulary, None otherwise.
665    fn id_to_token(&self, id: u32) -> Option<String>;
666}
667
668/// Represents tokenized input ready for model consumption.
669///
670/// `TokenizedInput` contains all the necessary components for feeding
671/// text data into a transformer model after tokenization.
672///
673/// # Fields
674///
675/// * `input_ids` - The token IDs representing the input text
676/// * `attention_mask` - Binary mask (0 or 1) indicating which tokens are real vs padding
677/// * `token_type_ids` - Optional segment IDs for models that use them (e.g., BERT)
678///
679/// # Example
680///
681/// ```no_run
682/// use trustformers_core::traits::TokenizedInput;
683///
684/// let input = TokenizedInput::with_token_type_ids(
685///     vec![101, 2023, 2003, 1037, 3231, 102], // [CLS] this is a test [SEP]
686///     vec![1, 1, 1, 1, 1, 1], // All tokens are real (not padding)
687///     Some(vec![0, 0, 0, 0, 0, 0]), // All tokens from first segment
688/// );
689/// ```
690#[derive(Debug, Clone, Default)]
691pub struct TokenizedInput {
692    /// Token IDs representing the encoded text.
693    /// These correspond to entries in the tokenizer's vocabulary.
694    pub input_ids: Vec<u32>,
695
696    /// Binary attention mask indicating real tokens (1) vs padding tokens (0).
697    /// This prevents the model from attending to padding tokens.
698    pub attention_mask: Vec<u8>,
699
700    /// Optional token type IDs for distinguishing between different segments.
701    /// Used by models like BERT for tasks involving multiple sequences.
702    /// Typically 0 for the first sequence and 1 for the second sequence.
703    pub token_type_ids: Option<Vec<u32>>,
704
705    /// Optional special tokens mask indicating special tokens (1) vs regular tokens (0).
706    /// Used to identify tokens like `[CLS]`, `[SEP]`, `[PAD]` etc.
707    pub special_tokens_mask: Option<Vec<u8>>,
708
709    /// Optional offset mapping showing where each token sits in the original text.
710    ///
711    /// Each tuple is a `(start, end)` **byte** offset into that text, so
712    /// `&text[start..end]` is the substring the token came from. Byte offsets —
713    /// not character (code point) offsets — are the in-tree convention:
714    /// every producer of this field emits byte spans, and the tokenizer tests
715    /// assert the round trip against `text.as_bytes()`.
716    ///
717    /// Callers that need character offsets (Python's `str` indexing, for
718    /// instance) convert at the boundary with
719    /// `trustformers_tokenizers::byte_offsets_to_char_offsets`, whose inverse is
720    /// `char_offsets_to_byte_offsets`. Converting anywhere other than the
721    /// boundary risks a double conversion, which is silent for ASCII and wrong
722    /// for everything else.
723    ///
724    /// Special tokens that correspond to no input text (`[CLS]`, `[SEP]`, and
725    /// friends) carry `(0, 0)`.
726    pub offset_mapping: Option<Vec<(usize, usize)>>,
727
728    /// Optional overflowing tokens when text exceeds max length.
729    /// Contains tokens that were truncated from the input.
730    pub overflowing_tokens: Option<Vec<u32>>,
731}
732
733impl TokenizedInput {
734    /// Create a new TokenizedInput with minimal required fields
735    pub fn new(input_ids: Vec<u32>, attention_mask: Vec<u8>) -> Self {
736        Self {
737            input_ids,
738            attention_mask,
739            token_type_ids: None,
740            special_tokens_mask: None,
741            offset_mapping: None,
742            overflowing_tokens: None,
743        }
744    }
745
746    /// Create a new TokenizedInput with token type IDs
747    pub fn with_token_type_ids(
748        input_ids: Vec<u32>,
749        attention_mask: Vec<u8>,
750        token_type_ids: Option<Vec<u32>>,
751    ) -> Self {
752        Self {
753            input_ids,
754            attention_mask,
755            token_type_ids,
756            special_tokens_mask: None,
757            offset_mapping: None,
758            overflowing_tokens: None,
759        }
760    }
761}
762
763/// Parameter optimization algorithms for training neural networks.
764///
765/// The `Optimizer` trait defines the interface for gradient-based optimization
766/// algorithms such as SGD, Adam, AdamW, etc. Optimizers update model parameters
767/// based on computed gradients to minimize the loss function.
768///
769/// # Thread Safety
770///
771/// Optimizers must be `Send + Sync` to support distributed training.
772///
773/// # Example
774///
775/// ```no_run
776/// use trustformers_core::traits::Optimizer;
777/// use trustformers_core::tensor::Tensor;
778/// use trustformers_core::errors::Result;
779///
780/// struct SGD {
781///     learning_rate: f32,
782///     momentum: f32,
783///     velocity: std::collections::HashMap<String, Tensor>,
784/// }
785///
786/// impl Optimizer for SGD {
787///     fn update(&mut self, _parameter: &mut Tensor, _grad: &Tensor) -> Result<()> {
788///         // SGD with momentum: v = momentum * v - lr * grad
789///         // parameter += v
790///         Ok(())
791///     }
792///
793///     fn zero_grad(&mut self) {
794///         // Clear accumulated gradients
795///     }
796///
797///     fn step(&mut self) {
798///         // Apply updates to all parameters
799///     }
800///
801///     fn get_lr(&self) -> f32 {
802///         self.learning_rate
803///     }
804///
805///     fn set_lr(&mut self, lr: f32) {
806///         self.learning_rate = lr;
807///     }
808/// }
809/// ```
810pub trait Optimizer: Send + Sync {
811    /// Updates a parameter based on its gradient.
812    ///
813    /// # Arguments
814    ///
815    /// * `parameter` - The parameter tensor to update
816    /// * `grad` - The gradient tensor for this parameter
817    ///
818    /// # Returns
819    ///
820    /// Returns `Ok(())` on successful update, or an error if the update fails.
821    ///
822    /// # Errors
823    ///
824    /// May return errors for:
825    /// - Mismatched tensor shapes
826    /// - Numerical errors (e.g., NaN or Inf values)
827    /// - Memory allocation failures
828    fn update(&mut self, parameter: &mut Tensor, grad: &Tensor) -> Result<()>;
829
830    /// Clears all accumulated gradients.
831    ///
832    /// This should be called before each backward pass to ensure
833    /// gradients don't accumulate across batches (unless gradient
834    /// accumulation is intentionally being used).
835    fn zero_grad(&mut self);
836
837    /// Performs a single optimization step.
838    ///
839    /// This method applies all pending parameter updates. It should be
840    /// called after gradients have been computed for all parameters.
841    fn step(&mut self);
842
843    /// Gets the current learning rate.
844    ///
845    /// # Returns
846    ///
847    /// The current learning rate value.
848    fn get_lr(&self) -> f32;
849
850    /// Sets a new learning rate.
851    ///
852    /// # Arguments
853    ///
854    /// * `lr` - The new learning rate value
855    ///
856    /// # Note
857    ///
858    /// This is useful for implementing learning rate schedules.
859    fn set_lr(&mut self, lr: f32);
860
861    /// Accumulates gradients for gradient accumulation.
862    ///
863    /// This method is used when training with gradient accumulation,
864    /// where gradients from multiple batches are accumulated before
865    /// performing an update step.
866    ///
867    /// # Arguments
868    ///
869    /// * `parameter` - The parameter tensor
870    /// * `grad` - The gradient to accumulate
871    ///
872    /// # Returns
873    ///
874    /// Returns `Ok(())` on success, or an error if accumulation fails.
875    ///
876    /// # Default Implementation
877    ///
878    /// The default implementation simply calls `update()`. Override this
879    /// method for optimizers that need special gradient accumulation logic.
880    fn accumulate_grad(&mut self, parameter: &mut Tensor, grad: &Tensor) -> Result<()> {
881        // Default implementation: just store the gradient for later use
882        self.update(parameter, grad)
883    }
884
885    /// Applies accumulated gradients after gradient accumulation.
886    ///
887    /// This method should be called after accumulating gradients from
888    /// multiple batches to apply the averaged update.
889    ///
890    /// # Arguments
891    ///
892    /// * `accumulation_steps` - The number of accumulation steps performed
893    ///
894    /// # Returns
895    ///
896    /// Returns `Ok(())` on success, or an error if application fails.
897    ///
898    /// # Default Implementation
899    ///
900    /// The default implementation is a no-op. Override this method for
901    /// optimizers that implement gradient accumulation.
902    fn apply_accumulated_grads(&mut self, accumulation_steps: usize) -> Result<()> {
903        // Default implementation: no-op, override if needed
904        let _ = accumulation_steps;
905        Ok(())
906    }
907}
908
909/// Weight initialization strategies for neural network parameters.
910///
911/// The `ParameterInit` trait provides various initialization methods that help
912/// ensure proper gradient flow and training stability. Different initialization
913/// strategies are optimal for different activation functions and architectures.
914///
915/// # Example
916///
917/// ```no_run
918/// use trustformers_core::traits::ParameterInit;
919///
920/// // Example type implementing ParameterInit
921/// struct WeightMatrix {
922///     data: Vec<f32>,
923///     shape: [usize; 2],
924/// }
925///
926/// impl ParameterInit for WeightMatrix {
927///     fn normal(&mut self, mean: f32, std: f32) {
928///         // fill data with normal distribution values
929///     }
930///     fn uniform(&mut self, min: f32, max: f32) {
931///         // fill data with uniform distribution values
932///     }
933///     fn xavier_uniform(&mut self) {
934///         // Xavier/Glorot initialization
935///     }
936///     fn xavier_normal(&mut self) {}
937///     fn kaiming_uniform(&mut self, _mode: &str, _nonlinearity: &str) {}
938///     fn kaiming_normal(&mut self, _mode: &str, _nonlinearity: &str) {}
939/// }
940///
941/// let mut weight = WeightMatrix { data: vec![0.0; 768 * 768], shape: [768, 768] };
942///
943/// // Initialize with Xavier/Glorot uniform for tanh activations
944/// weight.xavier_uniform();
945///
946/// // Or use Kaiming/He initialization for ReLU activations
947/// weight.kaiming_normal("fan_in", "relu");
948/// ```
949pub trait ParameterInit {
950    /// Initializes the tensor with values from a normal distribution.
951    ///
952    /// # Arguments
953    ///
954    /// * `mean` - The mean of the normal distribution
955    /// * `std` - The standard deviation of the normal distribution
956    ///
957    /// # Example
958    ///
959    /// ```no_run
960    /// # use trustformers_core::traits::ParameterInit;
961    /// # struct Weights { data: Vec<f32> }
962    /// # impl ParameterInit for Weights {
963    /// #     fn normal(&mut self, mean: f32, std: f32) {}
964    /// #     fn uniform(&mut self, min: f32, max: f32) {}
965    /// #     fn xavier_uniform(&mut self) {}
966    /// #     fn xavier_normal(&mut self) {}
967    /// #     fn kaiming_uniform(&mut self, _: &str, _: &str) {}
968    /// #     fn kaiming_normal(&mut self, _: &str, _: &str) {}
969    /// # }
970    /// let mut tensor = Weights { data: vec![0.0; 10000] };
971    /// tensor.normal(0.0, 0.02); // Common for transformer embeddings
972    /// ```
973    fn normal(&mut self, mean: f32, std: f32);
974
975    /// Initializes the tensor with values from a uniform distribution.
976    ///
977    /// # Arguments
978    ///
979    /// * `min` - The minimum value (inclusive)
980    /// * `max` - The maximum value (exclusive)
981    ///
982    /// # Example
983    ///
984    /// ```no_run
985    /// # use trustformers_core::traits::ParameterInit;
986    /// # struct Weights { data: Vec<f32> }
987    /// # impl ParameterInit for Weights {
988    /// #     fn normal(&mut self, mean: f32, std: f32) {}
989    /// #     fn uniform(&mut self, min: f32, max: f32) {}
990    /// #     fn xavier_uniform(&mut self) {}
991    /// #     fn xavier_normal(&mut self) {}
992    /// #     fn kaiming_uniform(&mut self, _: &str, _: &str) {}
993    /// #     fn kaiming_normal(&mut self, _: &str, _: &str) {}
994    /// # }
995    /// let mut tensor = Weights { data: vec![0.0; 10000] };
996    /// tensor.uniform(-0.1, 0.1);
997    /// ```
998    fn uniform(&mut self, min: f32, max: f32);
999
1000    /// Xavier/Glorot uniform initialization.
1001    ///
1002    /// Initializes weights to maintain variance across layers, optimal for
1003    /// tanh and sigmoid activations. The range is [-x, x] where
1004    /// x = sqrt(6 / (fan_in + fan_out)).
1005    ///
1006    /// # References
1007    ///
1008    /// Glorot & Bengio (2010): "Understanding the difficulty of training
1009    /// deep feedforward neural networks"
1010    fn xavier_uniform(&mut self);
1011
1012    /// Xavier/Glorot normal initialization.
1013    ///
1014    /// Similar to `xavier_uniform` but uses a normal distribution with
1015    /// std = sqrt(2 / (fan_in + fan_out)).
1016    fn xavier_normal(&mut self);
1017
1018    /// Kaiming/He uniform initialization.
1019    ///
1020    /// Designed for ReLU and similar activations. Maintains variance when
1021    /// half of the neurons are zeroed out by ReLU.
1022    ///
1023    /// # Arguments
1024    ///
1025    /// * `mode` - Either "fan_in" or "fan_out", determines which dimension to use
1026    /// * `nonlinearity` - The activation function ("relu", "leaky_relu", "linear")
1027    ///
1028    /// # Example
1029    ///
1030    /// ```no_run
1031    /// # use trustformers_core::traits::ParameterInit;
1032    /// # struct Weights { data: Vec<f32> }
1033    /// # impl ParameterInit for Weights {
1034    /// #     fn normal(&mut self, mean: f32, std: f32) {}
1035    /// #     fn uniform(&mut self, min: f32, max: f32) {}
1036    /// #     fn xavier_uniform(&mut self) {}
1037    /// #     fn xavier_normal(&mut self) {}
1038    /// #     fn kaiming_uniform(&mut self, _: &str, _: &str) {}
1039    /// #     fn kaiming_normal(&mut self, _: &str, _: &str) {}
1040    /// # }
1041    /// let mut conv_weight = Weights { data: vec![0.0; 64 * 32 * 3 * 3] };
1042    /// conv_weight.kaiming_uniform("fan_in", "relu");
1043    /// ```
1044    ///
1045    /// # References
1046    ///
1047    /// He et al. (2015): "Delving Deep into Rectifiers: Surpassing
1048    /// Human-Level Performance on ImageNet Classification"
1049    fn kaiming_uniform(&mut self, mode: &str, nonlinearity: &str);
1050
1051    /// Kaiming/He normal initialization.
1052    ///
1053    /// Similar to `kaiming_uniform` but uses a normal distribution.
1054    /// Generally preferred over uniform for deeper networks.
1055    ///
1056    /// # Arguments
1057    ///
1058    /// * `mode` - Either "fan_in" or "fan_out"
1059    /// * `nonlinearity` - The activation function ("relu", "leaky_relu", "linear")
1060    fn kaiming_normal(&mut self, mode: &str, nonlinearity: &str);
1061}