@@ -4,116 +4,123 @@ import org.operatorfoundation.codex.symbols.Symbol
44import kotlin.math.min
55
66/* *
7- * Encoder class that converts an integer to a list of encoded symbols .
7+ * Encoder class that converts an integer to a list of encoded values .
88 *
9- * The encoder uses a list of symbols to represent different parts of the integer.
10- * It works like converting to a mixed-radix number system, where each position
11- * can have a different base (determined by the symbol's size).
9+ * The encoder divides the integer into parts using a mixed-radix system,
10+ * where each symbol encodes a portion based on its size and position.
1211 *
1312 * @param symbols List of Symbol objects used for encoding
1413 */
15- class Encoder (private val symbols : List <Symbol >) {
16-
14+ class Encoder (private val symbols : List <Symbol >)
15+ {
1716 /* *
1817 * Creates a Decoder instance with the same symbol list.
19- * Useful for round-trip encoding/decoding operations.
2018 */
2119 fun decoder (): Decoder {
2220 return Decoder (symbols)
2321 }
2422
2523 /* *
26- * Encodes an integer value into a list of symbol representations.
27- *
28- * The encoding process divides the input number into parts, with each symbol
29- * encoding a portion based on its size and position. This is similar to
30- * converting a decimal number to a mixed-radix representation.
24+ * Encodes an integer value into a list of ByteArrays.
25+ * Each ByteArray in the result corresponds to one symbol.
3126 *
32- * @param valueToEncode The integer value to encode
33- * @return List of encoded values , one for each symbol
34- * @throws Exception if the value is too large to encode with the given symbols
27+ * @param integerToEncode The integer value to encode
28+ * @return List of ByteArrays , one for each symbol
29+ * @throws Exception if the value is too large to encode
3530 */
36- fun encode (valueToEncode : Int ): List <Any > {
37- val encodedResults = mutableListOf<Any >()
38- var remainingValue = valueToEncode
31+ fun encode (integerToEncode : Int ): List <ByteArray >
32+ {
33+ val results = mutableListOf<ByteArray >()
34+ var remainingValue = integerToEncode
3935
4036 // Process each symbol in sequence
41- symbols.forEachIndexed { symbolIndex , symbol ->
42- val (encodedPart , leftoverValue) = encodeStep(remainingValue, symbol, symbolIndex )
43- encodedResults .add(encodedPart )
37+ symbols.forEachIndexed { index , symbol ->
38+ val (encodedBytes , leftoverValue) = encodeStep(remainingValue, symbol, index )
39+ results .add(encodedBytes )
4440 remainingValue = leftoverValue
4541 }
4642
47- // If there's a leftover value, the input was too large for our symbol set
4843 if (remainingValue != 0 ) {
49- throw Exception (" Encoder error, results: $encodedResults , leftover: $remainingValue " )
44+ throw Exception (" Encoder error, results: ${results.map { it.decodeToString() }} , leftover: $remainingValue " )
5045 }
5146
52- return encodedResults
47+ return results
5348 }
5449
5550 /* *
5651 * Performs a single encode step for one symbol position.
5752 *
58- * For symbols with size > 1:
59- * - Determines how much of the remaining value this symbol should encode
60- * - Uses division and modulo based on the product of remaining symbol sizes
61- *
62- * For symbols with size = 1:
63- * - These are fixed values (like Required symbols) that don't encode data
64- *
65- * @param remainingValue The value left to encode
53+ * @param currentValue The value left to encode
6654 * @param symbol The symbol to use for encoding
67- * @param symbolIndex The position of this symbol in the list
68- * @return Pair of (encoded result for this symbol, remaining value for next symbols )
55+ * @param index The position of this symbol in the list
56+ * @return Pair of (encoded ByteArray for this symbol, remaining value)
6957 */
70- private fun encodeStep (remainingValue : Int , symbol : Symbol , symbolIndex : Int ): Pair <Any , Int > {
71- return if (symbol.size() == 1 ) {
58+ private fun encodeStep (currentValue : Int , symbol : Symbol , index : Int ): Pair <ByteArray , Int >
59+ {
60+ if (symbol.size() == 1 )
61+ {
7262 // Fixed symbols (size = 1) don't consume any of the value
73- println (" encode_step($remainingValue , $symbol , $symbolIndex )" )
63+ println (" encode_step($currentValue , $symbol , $index )" )
7464
75- // Calculate product of all symbols up to this point (for debugging)
76- val relevantSymbols = if (symbolIndex == 0 ) {
65+ // For debugging: show symbol capacity up to this point
66+ val symbolsUpToHere = if (index == 0 )
67+ {
7768 symbols
78- } else {
79- symbols.subList(0 , symbols.size - symbolIndex)
8069 }
81- val symbolSizes = relevantSymbols.map { it.size() }
82- val product = symbolSizes.fold(1 ) { acc, size -> acc * size }
70+ else
71+ {
72+ symbols.subList(0 , symbols.size - index)
73+ }
74+
75+ val symbolSizes = symbolsUpToHere.map { it.size() }
76+ val totalCapacity = symbolSizes.fold(1 ) { acc, size -> acc * size }
8377
84- println (" history: $symbolSizes , p: $product " )
78+ println (" history: $symbolSizes , p: $totalCapacity " )
8579
86- val result = Pair (symbol.encode(remainingValue), remainingValue)
87- println (" result: $result " )
88- result
89- } else {
90- println (" encode_step($remainingValue , $symbol , $symbolIndex )" )
80+ // Symbol with size 1 encodes its fixed value and passes through the current value
81+ val encodedBytes = symbol.encode(currentValue)
82+ val result = Pair (encodedBytes, currentValue)
83+ println (" result: (${encodedBytes.decodeToString()} , $currentValue )" )
9184
92- if (symbolIndex == symbols.size - 1 ) {
85+ return result
86+ }
87+ else
88+ {
89+ println (" encode_step($currentValue , $symbol , $index )" )
90+
91+ if (index == symbols.size - 1 )
92+ {
9393 // Last symbol: encode all remaining value
94- val result = Pair (symbol.encode(remainingValue), 0 )
95- println (" result: $result " )
96- result
97- } else {
98- // Calculate how much this symbol should encode based on remaining symbols
99- val remainingSymbols = symbols.subList(symbolIndex + 1 , symbols.size)
100- val remainingSizes = remainingSymbols.map { it.size() }
101- val remainingCapacity = remainingSizes.fold(1 ) { acc, size -> acc * size }
102-
103- println (" history: $remainingSizes , p: $remainingCapacity " )
104-
105- // Determine the value for this symbol position
106- // Use min to ensure we don't exceed the symbol's capacity
107- val symbolValue = min(remainingValue / remainingCapacity, symbol.size() - 1 )
94+ val encodedBytes = symbol.encode(currentValue)
95+ val result = Pair (encodedBytes, 0 )
96+ println (" result: (${encodedBytes.decodeToString()} , 0)" )
97+
98+ return result
99+ }
100+ else
101+ {
102+ // Calculate capacity of remaining symbols
103+ val remainingSymbols = symbols.subList(index + 1 , symbols.size)
104+ val remainingSymbolSizes = remainingSymbols.map { it.size() }
105+ val remainingCapacity = remainingSymbolSizes.fold(1 ) { acc, size -> acc * size }
106+
107+ println (" history: $remainingSymbolSizes , p: $remainingCapacity " )
108+
109+ // Determine value for this symbol position
110+ // Division gives us how many "chunks" of remaining capacity we have
111+ val symbolValue = min(currentValue / remainingCapacity, symbol.size() - 1 )
108112 println (" n: $symbolValue " )
109113
110- // Calculate what's left for the remaining symbols
111- val leftoverValue = remainingValue % remainingCapacity
114+ // Modulo gives us what's left for the remaining symbols
115+ val leftoverValue = currentValue % remainingCapacity
112116 println (" m: $leftoverValue " )
113117
114- val result = Pair (symbol.encode(symbolValue), leftoverValue)
115- println (" result: $result " )
116- result
118+ // Encode this symbol's portion
119+ val encodedBytes = symbol.encode(symbolValue)
120+ val result = Pair (encodedBytes, leftoverValue)
121+ println (" result: (${encodedBytes.decodeToString()} , $leftoverValue )" )
122+
123+ return result
117124 }
118125 }
119126 }
0 commit comments