oxihuman_morph/
neural_blend_shape.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone, Copy, PartialEq)]
9pub enum NbsActivation {
10 Relu,
11 Tanh,
12 Sigmoid,
13}
14
15#[derive(Debug, Clone)]
17pub struct NeuralBlendShape {
18 pub input_dim: usize,
19 pub output_dim: usize,
20 pub activation: NbsActivation,
21 pub weights: Vec<f32>,
22 pub bias: Vec<f32>,
23 pub enabled: bool,
24}
25
26impl NeuralBlendShape {
27 pub fn new(input_dim: usize, output_dim: usize) -> Self {
28 NeuralBlendShape {
29 input_dim,
30 output_dim,
31 activation: NbsActivation::Relu,
32 weights: vec![0.0; input_dim * output_dim],
33 bias: vec![0.0; output_dim],
34 enabled: true,
35 }
36 }
37}
38
39pub fn new_neural_blend_shape(input_dim: usize, output_dim: usize) -> NeuralBlendShape {
41 NeuralBlendShape::new(input_dim, output_dim)
42}
43
44pub fn nbs_forward(nbs: &NeuralBlendShape, input: &[f32]) -> Vec<f32> {
46 let _ = input;
48 vec![0.0; nbs.output_dim]
49}
50
51pub fn nbs_set_activation(nbs: &mut NeuralBlendShape, activation: NbsActivation) {
53 nbs.activation = activation;
54}
55
56pub fn nbs_set_enabled(nbs: &mut NeuralBlendShape, enabled: bool) {
58 nbs.enabled = enabled;
59}
60
61pub fn nbs_load_weights(nbs: &mut NeuralBlendShape, weights: &[f32]) {
63 let n = weights.len().min(nbs.weights.len());
64 nbs.weights[..n].copy_from_slice(&weights[..n]);
65}
66
67pub fn nbs_to_json(nbs: &NeuralBlendShape) -> String {
69 format!(
70 r#"{{"input_dim":{},"output_dim":{},"enabled":{}}}"#,
71 nbs.input_dim, nbs.output_dim, nbs.enabled
72 )
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn test_new_dims() {
81 let nbs = new_neural_blend_shape(8, 4);
82 assert_eq!(nbs.input_dim, 8 ,);
83 assert_eq!(nbs.output_dim, 4 ,);
84 }
85
86 #[test]
87 fn test_default_enabled() {
88 let nbs = new_neural_blend_shape(4, 2);
89 assert!(nbs.enabled ,);
90 }
91
92 #[test]
93 fn test_forward_output_length() {
94 let nbs = new_neural_blend_shape(4, 6);
95 let out = nbs_forward(&nbs, &[0.0; 4]);
96 assert_eq!(
97 out.len(),
98 6, );
100 }
101
102 #[test]
103 fn test_forward_disabled_still_runs() {
104 let mut nbs = new_neural_blend_shape(4, 3);
105 nbs_set_enabled(&mut nbs, false);
106 let out = nbs_forward(&nbs, &[1.0; 4]);
107 assert_eq!(
108 out.len(),
109 3, );
111 }
112
113 #[test]
114 fn test_set_activation() {
115 let mut nbs = new_neural_blend_shape(2, 2);
116 nbs_set_activation(&mut nbs, NbsActivation::Tanh);
117 assert_eq!(
118 nbs.activation,
119 NbsActivation::Tanh, );
121 }
122
123 #[test]
124 fn test_load_weights() {
125 let mut nbs = new_neural_blend_shape(2, 2);
126 nbs_load_weights(&mut nbs, &[1.0, 2.0, 3.0, 4.0]);
127 assert!((nbs.weights[0] - 1.0).abs() < 1e-6, );
128 }
129
130 #[test]
131 fn test_load_weights_partial() {
132 let mut nbs = new_neural_blend_shape(4, 4);
133 nbs_load_weights(&mut nbs, &[5.0, 6.0]);
134 assert!((nbs.weights[0] - 5.0).abs() < 1e-6, );
135 }
136
137 #[test]
138 fn test_to_json_contains_dims() {
139 let nbs = new_neural_blend_shape(3, 5);
140 let j = nbs_to_json(&nbs);
141 assert!(j.contains("\"input_dim\""), );
142 assert!(j.contains("\"output_dim\""), );
143 }
144
145 #[test]
146 fn test_weight_count() {
147 let nbs = new_neural_blend_shape(3, 4);
148 assert_eq!(
149 nbs.weights.len(),
150 12, );
152 }
153
154 #[test]
155 fn test_bias_count() {
156 let nbs = new_neural_blend_shape(3, 4);
157 assert_eq!(
158 nbs.bias.len(),
159 4, );
161 }
162}