infmachine_config 0.1.0

The Infinite Machine configuration.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
#![cfg_attr(docsrs, feature(doc_cfg))]
//! ## InfMachine Config
//!
//! The configuration module for the Infinite Machine. The library provides basic interface
//! for the configuration for the Infinite Machine. The library provides serialization and
//! deserialization by `serde` crate.
//!
//! Configuration is very simple structure with 3 fields:
//! * state_len - state length.
//! * data_part_len - data part length. Length of parts for the memory address and the temp buffer.
//! * cell_len_bits - length of length of the main memory cell.
//!
//! The library provides structures:
//! * `InfParMachineConfig` - machine configuration.
//! * `InfParInterfaceConfig` - machine configuration used by generators.
//! * `InfParEnvConfig` - machine configuration and environment configuration.
//! * `InfParMachineData` - machine data contains config, environment config and circuit.

use gatesim::*;

pub use toml;

use serde::de::{DeserializeOwned, Error};
use serde::{Deserialize, Serialize};

use std::fmt::Debug;
use std::str::FromStr;

/// Error that describe all errors of configuration and environment of machine.
#[derive(thiserror::Error, Debug)]
pub enum ValidError {
    /// Invalid state length.
    #[error("Invalid state length")]
    InvalidStateLength,
    /// Invalid data length.
    #[error("Invalid data part length")]
    InvalidDataPartLength,
    /// Invalid cell length bits.
    #[error("Invalid cell length bits")]
    InvalidCellLenBits,
    /// Invalid processor's number.
    #[error("Invalid processor's number")]
    InvalidProcNum,
    /// Invalid maximal temp buffer length.
    #[error("Invalid max temp buffer length")]
    InvalidMaxTempBufferLength,
    /// Invalid circuit input length.
    #[error("Invalid circuit input length")]
    InvalidCircuitInputLength,
    /// Invalid circuit output length.
    #[error("Invalid circuit output length")]
    InvalidCircuitOutputLength,
}

/// Main structure that describes machine configuration. It describes
/// general features that doesn't includes specific implementation configuration.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct InfParMachineConfig {
    /// State length in bits.
    pub state_len: u32,
    /// Data part length. In bits.
    pub data_part_len: u32,
    /// Cell lengh bits. Exactly power of two of memory cell length in bits.
    /// Example: 3 - memory cell has 8 bits (2^3)==8.
    pub cell_len_bits: u32,
}

impl InfParMachineConfig {
    /// Check configuration. It returns Ok if no errors and returns ValidError if error.
    pub fn valid(&self) -> Result<(), ValidError> {
        if self.state_len == 0 {
            return Err(ValidError::InvalidStateLength);
        }
        if self.data_part_len == 0 {
            return Err(ValidError::InvalidDataPartLength);
        }
        if self.cell_len_bits >= 64 {
            return Err(ValidError::InvalidCellLenBits);
        }
        Ok(())
    }
}

/// Structure describes machine configuration that can be used by generator of machines.
/// It doesn't provide state length.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct InfParInterfaceConfig {
    /// Data part length. In bits.
    pub data_part_len: u32,
    /// Cell lengh bits. Exactly power of two of memory cell length in bits.
    /// Example: 3 - memory cell has 8 bits (2^3)==8.
    pub cell_len_bits: u32,
}

impl InfParInterfaceConfig {
    /// Check configuration. It returns Ok if no errors and returns ValidError if error.
    pub fn valid(&self) -> Result<(), ValidError> {
        if self.data_part_len == 0 {
            return Err(ValidError::InvalidDataPartLength);
        }
        if self.cell_len_bits >= 64 {
            return Err(ValidError::InvalidCellLenBits);
        }
        Ok(())
    }
}

/// Convert interface configuration with state length to machine configuration.
impl From<(InfParInterfaceConfig, u32)> for InfParMachineConfig {
    fn from((c, s): (InfParInterfaceConfig, u32)) -> Self {
        Self {
            state_len: s,
            data_part_len: c.data_part_len,
            cell_len_bits: c.cell_len_bits,
        }
    }
}

/// Structure describes an execution environment for machine.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct InfParEnvConfig {
    /// Number of processors.
    pub proc_num: u64,
    /// If flat model of memory used. Currently only flat model can be used.
    pub flat_memory: bool,
    /// Maximal temp buffer length in bits.
    pub max_temp_buffer_len: u32,
    /// Maximal memory size (length) in bytes. If not specified then memory length can be
    /// unlimited.
    pub max_mem_size: Option<u64>,
}

impl InfParEnvConfig {
    /// Check configuration. It returns Ok if no errors and returns ValidError if error.
    pub fn valid(&self) -> Result<(), ValidError> {
        if self.proc_num == 0 || self.proc_num < 1024 {
            return Err(ValidError::InvalidProcNum);
        }
        if self.max_temp_buffer_len == 0 {
            return Err(ValidError::InvalidMaxTempBufferLength);
        }
        Ok(())
    }
}

/// Structure describes same machine. It contains machine configuration, execution
/// environment configuration and circuit that describes behavior of the machine.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct InfParMachineData<T>
where
    T: Clone + Copy + FromStr + Debug + Default + PartialOrd + Ord + std::ops::Add<Output = T>,
    T: From<u8>,
    usize: TryFrom<T>,
    <usize as TryFrom<T>>::Error: Debug,
    T: TryFrom<usize>,
    <T as TryFrom<usize>>::Error: Debug,
    <T as FromStr>::Err: Debug,
{
    /// Machine configuration.
    pub config: InfParMachineConfig,
    /// Execution environment configuration.
    pub env_config: InfParEnvConfig,
    /// Machine circuit.
    pub circuit: Circuit<T>,
}

impl<T> InfParMachineData<T>
where
    T: Clone + Copy + FromStr + Debug + Default + PartialOrd + Ord + std::ops::Add<Output = T>,
    T: From<u8> + Serialize + DeserializeOwned,
    usize: TryFrom<T>,
    <usize as TryFrom<T>>::Error: Debug,
    T: TryFrom<usize>,
    <T as TryFrom<usize>>::Error: Debug,
    <T as FromStr>::Err: Debug,
{
    /// Check configuration. It returns Ok if no errors and returns ValidError if error.
    pub fn valid(&self) -> Result<(), ValidError> {
        self.config.valid()?;
        self.env_config.valid()?;
        let circuit_input_len = usize::try_from(self.circuit.input_len()).unwrap();
        let state_len = circuit_input_len
            - (1 << self.config.cell_len_bits)
            - self.config.data_part_len as usize
            - 1;
        if state_len != self.config.state_len as usize {
            return Err(ValidError::InvalidCircuitInputLength);
        }
        if self.circuit.outputs().len() != circuit_input_len + 8 {
            return Err(ValidError::InvalidCircuitOutputLength);
        }
        Ok(())
    }

    /// Convert to TOML format. It returns string of TOML data or `serde` error.
    pub fn to_toml(&self) -> Result<String, toml::ser::Error> {
        toml::to_string_pretty(self)
    }

    /// Convert from TOML format that TOML data provides as string.
    /// It returns structure or `serde` error.
    pub fn from_toml(s: &str) -> Result<Self, toml::de::Error> {
        let d: Self = toml::from_str(s)?;
        if let Err(e) = d.valid() {
            return Err::<Self, _>(toml::de::Error::custom(e.to_string()));
        }
        Ok(d)
    }
}

/// Type for circuit with 16-bit length type.
pub type InfParMachineData16 = InfParMachineData<u16>;
/// Type for circuit with 32-bit length type.
pub type InfParMachineData32 = InfParMachineData<u32>;
/// Type for circuit with system (usize) length type.
pub type InfParMachineDataSys = InfParMachineData<usize>;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_serialize() {
        let config = InfParMachineConfig {
            state_len: 44,
            data_part_len: 32,
            cell_len_bits: 5,
        };
        let env_config = InfParEnvConfig {
            proc_num: 64 * 1024,
            flat_memory: true,
            max_temp_buffer_len: 96,
            max_mem_size: Some(400 * 1024),
        };
        assert_eq!(
            r##"state_len = 44
data_part_len = 32
cell_len_bits = 5
"##,
            toml::to_string_pretty(&config).unwrap()
        );
        assert_eq!(
            r##"proc_num = 65536
flat_memory = true
max_temp_buffer_len = 96
max_mem_size = 409600
"##,
            toml::to_string_pretty(&env_config).unwrap()
        );
        let machine_data = InfParMachineData {
            config,
            env_config,
            circuit: Circuit::<u32>::new(2, [Gate::new_and(0, 1)], [(2, false)]).unwrap(),
        };
        assert_eq!(
            r##"circuit = """
    {
        0
        1
        and(0,1):0
    }(2)
"""

[config]
state_len = 44
data_part_len = 32
cell_len_bits = 5

[env_config]
proc_num = 65536
flat_memory = true
max_temp_buffer_len = 96
max_mem_size = 409600
"##,
            machine_data.to_toml().unwrap()
        );
    }

    #[test]
    fn test_deserialize() {
        let config = InfParMachineConfig {
            state_len: 44,
            data_part_len: 32,
            cell_len_bits: 5,
        };
        let env_config = InfParEnvConfig {
            proc_num: 64 * 1024,
            flat_memory: true,
            max_temp_buffer_len: 96,
            max_mem_size: Some(400 * 1024),
        };
        let mem_cell_data_part_len = (1 << config.cell_len_bits) + config.data_part_len;
        let circuit_input_len = config.state_len + mem_cell_data_part_len + 1;
        assert_eq!(
            InfParMachineData {
                config,
                env_config,
                circuit: Circuit::<u32>::new(
                    circuit_input_len,
                    [Gate::new_nor(0, circuit_input_len - 1)],
                    std::iter::once((circuit_input_len, true)).chain(
                        (1..circuit_input_len - 1)
                            .chain(0..9)
                            .map(|i| (i, i >= config.state_len && i < circuit_input_len - 1)),
                    ),
                )
                .unwrap(),
            },
            InfParMachineData::<u32>::from_toml(
                r##"circuit = """{
    0:108
    1:1:109
    2:2:110
    3:3:111
    4:4:112
    5:5:113
    6:6:114
    7:7:115
    8:8:116
    9:9
    10:10
    11:11
    12:12
    13:13
    14:14
    15:15
    16:16
    17:17
    18:18
    19:19
    20:20
    21:21
    22:22
    23:23
    24:24
    25:25
    26:26
    27:27
    28:28
    29:29
    30:30
    31:31
    32:32
    33:33
    34:34
    35:35
    36:36
    37:37
    38:38
    39:39
    40:40
    41:41
    42:42
    43:43
    44:44n
    45:45n
    46:46n
    47:47n
    48:48n
    49:49n
    50:50n
    51:51n
    52:52n
    53:53n
    54:54n
    55:55n
    56:56n
    57:57n
    58:58n
    59:59n
    60:60n
    61:61n
    62:62n
    63:63n
    64:64n
    65:65n
    66:66n
    67:67n
    68:68n
    69:69n
    70:70n
    71:71n
    72:72n
    73:73n
    74:74n
    75:75n
    76:76n
    77:77n
    78:78n
    79:79n
    80:80n
    81:81n
    82:82n
    83:83n
    84:84n
    85:85n
    86:86n
    87:87n
    88:88n
    89:89n
    90:90n
    91:91n
    92:92n
    93:93n
    94:94n
    95:95n
    96:96n
    97:97n
    98:98n
    99:99n
    100:100n
    101:101n
    102:102n
    103:103n
    104:104n
    105:105n
    106:106n
    107:107n
    108
    nor(0,108):0n
}(109)
"""

[config]
state_len = 44
data_part_len = 32
cell_len_bits = 5

[env_config]
proc_num = 65536
flat_memory = true
max_temp_buffer_len = 96
max_mem_size = 409600
"##
            )
            .unwrap()
        )
    }
}