1use crate::data_pipeline::PipelineStageProperties;
2use crate::data_types::descriptors::{
3 ImageFrameProperties, MiscDataDimensions, PercentageChannelDimensionality,
4 SegmentedImageFrameProperties,
5};
6use crate::data_types::{
7 GazeProperties, ImageFilteringSettings, ImageFrame, MiscData, Percentage, Percentage2D,
8 Percentage3D, Percentage4D, SegmentedImageFrame, SignedPercentage, SignedPercentage2D,
9 SignedPercentage3D, SignedPercentage4D,
10};
11use crate::feedbacks::FeedbackRegistrar;
12use crate::neuron_voxel_coding::xyzp::decoders::{
13 GazePropertiesNeuronVoxelXYZPDecoder, ImageFilteringSettingsNeuronVoxelXYZPDecoder,
14 MiscDataNeuronVoxelXYZPDecoder, PercentageNeuronVoxelXYZPDecoder,
15};
16use crate::neuron_voxel_coding::xyzp::encoders::{
17 BooleanNeuronVoxelXYZPEncoder, CartesianPlaneNeuronVoxelXYZPEncoder,
18 MiscDataNeuronVoxelXYZPEncoder, PercentageNeuronVoxelXYZPEncoder,
19 SegmentedImageFrameNeuronVoxelXYZPEncoder,
20};
21use crate::neuron_voxel_coding::xyzp::{NeuronVoxelXYZPDecoder, NeuronVoxelXYZPEncoder};
22use crate::wrapped_io_data::WrappedIOData;
23use feagi_structures::genomic::cortical_area::descriptors::{
24 CorticalChannelCount, CorticalChannelIndex, CorticalUnitIndex, NeuronDepth,
25};
26use feagi_structures::genomic::cortical_area::io_cortical_area_configuration_flag::PercentageNeuronPositioning;
27use feagi_structures::genomic::cortical_area::CorticalID;
28use feagi_structures::genomic::{MotorCorticalUnit, SensoryCorticalUnit};
29use feagi_structures::FeagiDataError;
30use serde::{Deserialize, Serialize};
31use std::collections::HashMap;
32
33#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)]
36pub struct JSONInputOutputDefinition {
37 input_units_and_encoder_properties:
38 HashMap<SensoryCorticalUnit, Vec<(JSONUnitDefinition, JSONEncoderProperties)>>,
39 output_units_and_decoder_properties:
40 HashMap<MotorCorticalUnit, Vec<(JSONUnitDefinition, JSONDecoderProperties)>>,
41 feedbacks: FeedbackRegistrar,
42}
43
44impl JSONInputOutputDefinition {
45 pub fn new() -> JSONInputOutputDefinition {
46 JSONInputOutputDefinition {
47 input_units_and_encoder_properties: HashMap::new(),
48 output_units_and_decoder_properties: HashMap::new(),
49 feedbacks: FeedbackRegistrar::new(),
50 }
51 }
52
53 pub fn get_input_units_and_encoder_properties(
54 &self,
55 ) -> &HashMap<SensoryCorticalUnit, Vec<(JSONUnitDefinition, JSONEncoderProperties)>> {
56 &self.input_units_and_encoder_properties
57 }
58
59 pub fn get_output_units_and_decoder_properties(
60 &self,
61 ) -> &HashMap<MotorCorticalUnit, Vec<(JSONUnitDefinition, JSONDecoderProperties)>> {
62 &self.output_units_and_decoder_properties
63 }
64
65 pub fn verify_valid_structure(&self) -> Result<(), FeagiDataError> {
66 for units_and_encoders in self.input_units_and_encoder_properties.values() {
67 let mut unit_indexes: Vec<CorticalUnitIndex> = Vec::new();
68 for unit in units_and_encoders {
69 unit.0.verify_valid_structure()?;
70 if unit_indexes.contains(&unit.0.cortical_unit_index) {
71 return Err(FeagiDataError::DeserializationError(
72 "Duplicate cortical unit indexes found!".into(),
73 ));
74 }
75 unit_indexes.push(unit.0.cortical_unit_index);
76 }
77 }
78 for units_and_decoders in self.output_units_and_decoder_properties.values() {
79 let mut unit_indexes: Vec<CorticalUnitIndex> = Vec::new();
80 for unit in units_and_decoders {
81 unit.0.verify_valid_structure()?;
82 if unit_indexes.contains(&unit.0.cortical_unit_index) {
83 return Err(FeagiDataError::DeserializationError(
84 "Duplicate cortical unit indexes found!".into(),
85 ));
86 }
87 unit_indexes.push(unit.0.cortical_unit_index);
88 }
89 }
90
91 Ok(())
92 }
93
94 pub fn insert_motor(
95 &mut self,
96 motor: MotorCorticalUnit,
97 unit_definition: JSONUnitDefinition,
98 decoder_properties: JSONDecoderProperties,
99 ) {
100 if let std::collections::hash_map::Entry::Vacant(entry) =
101 self.output_units_and_decoder_properties.entry(motor)
102 {
103 entry.insert(vec![(unit_definition, decoder_properties)]);
104 return;
105 }
106 let vec = self
107 .output_units_and_decoder_properties
108 .get_mut(&motor)
109 .unwrap();
110 vec.push((unit_definition, decoder_properties));
111 }
112
113 pub fn insert_sensor(
114 &mut self,
115 sensor: SensoryCorticalUnit,
116 unit_definition: JSONUnitDefinition,
117 encoder_properties: JSONEncoderProperties,
118 ) {
119 if let std::collections::hash_map::Entry::Vacant(entry) =
120 self.input_units_and_encoder_properties.entry(sensor)
121 {
122 entry.insert(vec![(unit_definition, encoder_properties)]);
123 return;
124 }
125 let vec = self
126 .input_units_and_encoder_properties
127 .get_mut(&sensor)
128 .unwrap();
129 vec.push((unit_definition, encoder_properties));
130 }
131
132 pub(crate) fn get_feedbacks(&self) -> &FeedbackRegistrar {
133 &self.feedbacks
134 }
135 pub(crate) fn set_feedbacks(&mut self, feedbacks: FeedbackRegistrar) {
136 self.feedbacks = feedbacks;
137 }
138}
139
140impl Default for JSONInputOutputDefinition {
141 fn default() -> Self {
142 Self::new()
143 }
144}
145
146#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
149pub struct JSONUnitDefinition {
150 pub(crate) friendly_name: Option<String>,
151 pub(crate) cortical_unit_index: CorticalUnitIndex,
152 pub(crate) io_configuration_flags: serde_json::Map<String, serde_json::Value>, pub(crate) device_grouping: Vec<JSONDeviceGrouping>,
154}
155
156impl JSONUnitDefinition {
157 pub fn verify_valid_structure(&self) -> Result<(), FeagiDataError> {
158 if self.device_grouping.is_empty() {
159 return Err(FeagiDataError::DeserializationError(
160 "Cannot have a cortical unit of 0 device grouping!".to_string(),
161 ));
162 }
163 let number_channels = self.device_grouping.len() as u32;
164 for device_grouping in &self.device_grouping {
165 if let Some(channel_override) = device_grouping.channel_index_override {
166 if *channel_override > number_channels {
167 return Err(FeagiDataError::DeserializationError(
168 "Device has invalid channel override!".to_string(),
169 ));
170 }
171 }
172
173 let _stages = &device_grouping.pipeline_stages;
174 }
176 Ok(())
177 }
178
179 pub fn get_channel_count(&self) -> Result<CorticalChannelCount, FeagiDataError> {
180 CorticalChannelCount::new(self.device_grouping.len() as u32)
181 }
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
186pub struct JSONDeviceGrouping {
187 pub(crate) friendly_name: Option<String>,
188 pub(crate) device_properties: JSONDeviceProperties,
189 pub(crate) channel_index_override: Option<CorticalChannelIndex>,
190 pub(crate) pipeline_stages: Vec<PipelineStageProperties>,
191}
192
193#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
197pub enum JSONEncoderProperties {
198 Boolean,
199 CartesianPlane(ImageFrameProperties),
200 MiscData(MiscDataDimensions),
201 Percentage(
202 NeuronDepth,
203 PercentageNeuronPositioning,
204 bool,
205 PercentageChannelDimensionality,
206 ),
207 SegmentedImageFrame(SegmentedImageFrameProperties),
208}
209
210impl JSONEncoderProperties {
211 pub fn to_box_encoder(
212 &self,
213 number_channels: CorticalChannelCount,
214 cortical_ids: &[CorticalID],
215 ) -> Result<Box<dyn NeuronVoxelXYZPEncoder + Sync + Send>, FeagiDataError> {
216 match self {
217 JSONEncoderProperties::Boolean => {
218 if cortical_ids.len() != 1 {
219 return Err(FeagiDataError::InternalError(
220 "Expected one cortical id!".to_string(),
221 ));
222 }
223 BooleanNeuronVoxelXYZPEncoder::new_box(
224 *cortical_ids.first().unwrap(),
225 number_channels,
226 )
227 }
228 JSONEncoderProperties::CartesianPlane(image_frame) => {
229 if cortical_ids.len() != 1 {
230 return Err(FeagiDataError::InternalError(
231 "Expected one cortical id!".to_string(),
232 ));
233 }
234 CartesianPlaneNeuronVoxelXYZPEncoder::new_box(
235 *cortical_ids.first().unwrap(),
236 image_frame,
237 number_channels,
238 )
239 }
240 JSONEncoderProperties::MiscData(misc_data_dimensions) => {
241 if cortical_ids.len() != 1 {
242 return Err(FeagiDataError::InternalError(
243 "Expected one cortical id!".to_string(),
244 ));
245 }
246 MiscDataNeuronVoxelXYZPEncoder::new_box(
247 *cortical_ids.first().unwrap(),
248 *misc_data_dimensions,
249 number_channels,
250 )
251 }
252 JSONEncoderProperties::Percentage(
253 neuron_depth,
254 percentage,
255 is_signed,
256 number_dimensions,
257 ) => {
258 if cortical_ids.len() != 1 {
259 return Err(FeagiDataError::InternalError(
260 "Expected one cortical id!".to_string(),
261 ));
262 }
263 PercentageNeuronVoxelXYZPEncoder::new_box(
264 *cortical_ids.first().unwrap(),
265 *neuron_depth,
266 number_channels,
267 *percentage,
268 *is_signed,
269 *number_dimensions,
270 )
271 }
272 JSONEncoderProperties::SegmentedImageFrame(segmented_properties) => {
273 if cortical_ids.len() != 9 {
274 return Err(FeagiDataError::InternalError(
275 "Expected nine cortical ids!".to_string(),
276 ));
277 }
278 let cortical_ids: [CorticalID; 9] = (*cortical_ids).try_into().map_err(|_| {
279 FeagiDataError::InternalError("Unable to get cortical ids!".to_string())
280 })?;
281 SegmentedImageFrameNeuronVoxelXYZPEncoder::new_box(
282 cortical_ids,
283 *segmented_properties,
284 number_channels,
285 )
286 }
287 }
288 }
289
290 pub fn default_wrapped_value(&self) -> Result<WrappedIOData, FeagiDataError> {
291 match self {
292 JSONEncoderProperties::Boolean => Ok(WrappedIOData::Boolean(false)),
293 JSONEncoderProperties::CartesianPlane(image_frame_properties) => {
294 Ok(WrappedIOData::ImageFrame(
295 ImageFrame::new_from_image_frame_properties(image_frame_properties)?,
296 ))
297 }
298 JSONEncoderProperties::MiscData(misc_data_dimensions) => Ok(WrappedIOData::MiscData(
299 MiscData::new(misc_data_dimensions)?,
300 )),
301 JSONEncoderProperties::Percentage(
302 _neuron_depth,
303 _percentage,
304 is_signed,
305 number_dimensions,
306 ) => match number_dimensions {
307 PercentageChannelDimensionality::D1 => {
308 if *is_signed {
309 Ok(WrappedIOData::SignedPercentage(
310 SignedPercentage::new_from_m1_1_unchecked(0.0),
311 ))
312 } else {
313 Ok(WrappedIOData::Percentage(Percentage::new_zero()))
314 }
315 }
316 PercentageChannelDimensionality::D2 => {
317 if *is_signed {
318 Ok(WrappedIOData::SignedPercentage_2D(
319 SignedPercentage2D::new_zero(),
320 ))
321 } else {
322 Ok(WrappedIOData::Percentage_2D(Percentage2D::new_zero()))
323 }
324 }
325 PercentageChannelDimensionality::D3 => {
326 if *is_signed {
327 Ok(WrappedIOData::SignedPercentage_3D(
328 SignedPercentage3D::new_zero(),
329 ))
330 } else {
331 Ok(WrappedIOData::Percentage_3D(Percentage3D::new_zero()))
332 }
333 }
334 PercentageChannelDimensionality::D4 => {
335 if *is_signed {
336 Ok(WrappedIOData::SignedPercentage_4D(
337 SignedPercentage4D::new_zero(),
338 ))
339 } else {
340 Ok(WrappedIOData::Percentage_4D(Percentage4D::new_zero()))
341 }
342 }
343 },
344 JSONEncoderProperties::SegmentedImageFrame(segmented_properties) => {
345 Ok(WrappedIOData::SegmentedImageFrame(
346 SegmentedImageFrame::from_segmented_image_frame_properties(
347 segmented_properties,
348 )?,
349 ))
350 }
351 }
352 }
353}
354
355#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
356pub enum JSONDecoderProperties {
357 CartesianPlane(ImageFrameProperties),
358 MiscData(MiscDataDimensions),
359 Percentage(
360 NeuronDepth,
361 PercentageNeuronPositioning,
362 bool,
363 PercentageChannelDimensionality,
364 ),
365 PositionalServo(NeuronDepth, PercentageNeuronPositioning), GazeProperties(NeuronDepth, NeuronDepth, PercentageNeuronPositioning), ImageFilteringSettings(
368 NeuronDepth,
369 NeuronDepth,
370 NeuronDepth,
371 PercentageNeuronPositioning,
372 ), }
374
375impl JSONDecoderProperties {
376 pub fn to_box_decoder(
377 &self,
378 number_channels: CorticalChannelCount,
379 cortical_ids: &[CorticalID],
380 ) -> Result<Box<dyn NeuronVoxelXYZPDecoder + Sync + Send>, FeagiDataError> {
381 match self {
382 JSONDecoderProperties::CartesianPlane(image_frame_properties) => {
383 if cortical_ids.len() != 1 {
384 return Err(FeagiDataError::InternalError(
385 "Expected one cortical id!".to_string(),
386 ));
387 }
388 crate::neuron_voxel_coding::xyzp::decoders::CartesianPlaneNeuronVoxelXYZPDecoder::new_box(
389 *cortical_ids.first().unwrap(),
390 image_frame_properties,
391 number_channels,
392 )
393 }
394 JSONDecoderProperties::MiscData(misc_data_dimensions) => {
395 if cortical_ids.len() != 1 {
396 return Err(FeagiDataError::InternalError(
397 "Expected one cortical id!".to_string(),
398 ));
399 }
400 MiscDataNeuronVoxelXYZPDecoder::new_box(
401 *cortical_ids.first().unwrap(), *misc_data_dimensions,
403 number_channels,
404 )
405 }
406 JSONDecoderProperties::Percentage(
407 neuron_depth,
408 percentage_neuron_positioning,
409 is_signed,
410 dimension_count,
411 ) => {
412 if cortical_ids.len() != 1 {
413 return Err(FeagiDataError::InternalError(
414 "Expected one cortical id!".to_string(),
415 ));
416 }
417 PercentageNeuronVoxelXYZPDecoder::new_box(
418 *cortical_ids.first().unwrap(), *neuron_depth,
420 number_channels,
421 *percentage_neuron_positioning,
422 *is_signed,
423 *dimension_count,
424 )
425 }
426 JSONDecoderProperties::PositionalServo(neuron_depth, percentage_neuron_positioning) => {
427 if cortical_ids.len() != 2 {
428 return Err(FeagiDataError::InternalError(
429 "Expected two cortical ids for PositionalServo!".to_string(),
430 ));
431 }
432 crate::neuron_voxel_coding::xyzp::decoders::PositionalServoNeuronVoxelXYZPDecoder::new_box(
433 *cortical_ids.first().unwrap(), *cortical_ids.get(1).unwrap(), *neuron_depth,
436 number_channels,
437 *percentage_neuron_positioning,
438 )
439 }
440 JSONDecoderProperties::GazeProperties(
441 eccentricity_neuron_depth,
442 modularity_neuron_depth,
443 percentage_neuron_positioning,
444 ) => {
445 if cortical_ids.len() != 2 {
446 return Err(FeagiDataError::InternalError(
447 "Expected two cortical ids!".to_string(),
448 ));
449 }
450 GazePropertiesNeuronVoxelXYZPDecoder::new_box(
451 *cortical_ids.first().unwrap(), *cortical_ids.get(1).unwrap(), *eccentricity_neuron_depth,
454 *modularity_neuron_depth,
455 number_channels,
456 *percentage_neuron_positioning,
457 )
458 }
459 JSONDecoderProperties::ImageFilteringSettings(
460 brightness_z_depth,
461 contrast_z_depth,
462 diff_z_depth,
463 percentage_neuron_positioning,
464 ) => {
465 if cortical_ids.len() != 3 {
466 return Err(FeagiDataError::InternalError(
467 "Expected three cortical ids for ImageFilteringSettings!".to_string(),
468 ));
469 }
470 ImageFilteringSettingsNeuronVoxelXYZPDecoder::new_box(
471 *cortical_ids.first().unwrap(), *cortical_ids.get(1).unwrap(), *cortical_ids.get(2).unwrap(), *brightness_z_depth,
475 *contrast_z_depth,
476 *diff_z_depth,
477 number_channels,
478 *percentage_neuron_positioning,
479 )
480 }
481 }
482 }
483
484 pub fn default_wrapped_value(&self) -> Result<WrappedIOData, FeagiDataError> {
485 match self {
486 JSONDecoderProperties::CartesianPlane(image_frame_properties) => {
487 Ok(WrappedIOData::ImageFrame(
488 ImageFrame::new_from_image_frame_properties(image_frame_properties)?,
489 ))
490 }
491 JSONDecoderProperties::MiscData(misc_data_dimensions) => Ok(WrappedIOData::MiscData(
492 MiscData::new(misc_data_dimensions)?,
493 )),
494 JSONDecoderProperties::Percentage(
495 _neuron_depth,
496 _percentage_neuron_positioning,
497 is_signed,
498 number_dimensions,
499 ) => match number_dimensions {
500 PercentageChannelDimensionality::D1 => {
501 if *is_signed {
502 Ok(WrappedIOData::SignedPercentage(
503 SignedPercentage::new_from_m1_1_unchecked(0.0),
504 ))
505 } else {
506 Ok(WrappedIOData::Percentage(Percentage::new_zero()))
507 }
508 }
509 PercentageChannelDimensionality::D2 => {
510 if *is_signed {
511 Ok(WrappedIOData::SignedPercentage_2D(
512 SignedPercentage2D::new_zero(),
513 ))
514 } else {
515 Ok(WrappedIOData::Percentage_2D(Percentage2D::new_zero()))
516 }
517 }
518 PercentageChannelDimensionality::D3 => {
519 if *is_signed {
520 Ok(WrappedIOData::SignedPercentage_3D(
521 SignedPercentage3D::new_zero(),
522 ))
523 } else {
524 Ok(WrappedIOData::Percentage_3D(Percentage3D::new_zero()))
525 }
526 }
527 PercentageChannelDimensionality::D4 => {
528 if *is_signed {
529 Ok(WrappedIOData::SignedPercentage_4D(
530 SignedPercentage4D::new_zero(),
531 ))
532 } else {
533 Ok(WrappedIOData::Percentage_4D(Percentage4D::new_zero()))
534 }
535 }
536 },
537 JSONDecoderProperties::GazeProperties(
538 _eccentricity,
539 _modularity,
540 _percentage_neuron_positioning,
541 ) => Ok(WrappedIOData::GazeProperties(
542 GazeProperties::create_default_centered(),
543 )),
544 JSONDecoderProperties::PositionalServo(
545 _neuron_depth,
546 _percentage_neuron_positioning,
547 ) => Ok(WrappedIOData::Percentage(Percentage::new_zero())),
548 JSONDecoderProperties::ImageFilteringSettings(
549 _brightness,
550 _contrast,
551 _diff,
552 _percentage_neuron_positioning,
553 ) => Ok(WrappedIOData::ImageFilteringSettings(
554 ImageFilteringSettings::default(),
555 )),
556 }
557 }
558}
559
560pub type JSONDeviceProperties = HashMap<String, JSONDevicePropertyValue>;
567
568#[derive(Serialize, Deserialize)]
571#[serde(tag = "type", content = "value")]
572#[derive(Debug, Clone, PartialEq)]
573pub enum JSONDevicePropertyValue {
574 String(String),
575 Integer(i32),
576 Float(f32),
577 Dictionary(JSONDeviceProperties),
578}
579
580