Skip to content

Commit

Permalink
Maxicode: Fixed final latch and optimise ECI tables
Browse files Browse the repository at this point in the history
  • Loading branch information
gitlost authored and terryburton committed Nov 11, 2024
1 parent 2a892a6 commit 5ae614c
Showing 1 changed file with 39 additions and 47 deletions.
86 changes: 39 additions & 47 deletions src/maxicode.ps.src
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@ begin
/sete charvals 4 get def
} ctxdef

/maxlen mode 5 eq {77} {mode 3 le {84} {93} ifelse} ifelse def

encoding (legacy) eq {

% Compute numeric runlengths
Expand Down Expand Up @@ -311,7 +313,7 @@ begin
{ % loop
% Exit when no characters remain latching back to A if necessary
i msglen eq {
cset (seta) ne cset (setb) ne and {
cset (seta) ne cset (setb) ne and out length maxlen lt and {
la cset load enc
/cset (seta) def
} if
Expand Down Expand Up @@ -497,13 +499,13 @@ begin
{32768 lt {4} {5} ifelse} ifelse} def

% Operations that don't fit directly into the list below
/enc_eci1 {c neg 1000000 sub } def % Extended
/enc_eci2 {c neg 1000000 sub dup -6 bitshift 32 or exch 63 and} def % Channel
/enc_eci3 {c neg 1000000 sub dup -12 bitshift 48 or exch % Interpretation
dup -6 bitshift 63 and exch 63 and} def
/enc_eci4 {c neg 1000000 sub dup -18 bitshift 56 or exch
/enc_eci {c neg 1000000 sub dup 32 ge {dup 1024 lt {
dup -6 bitshift 32 or exch 63 and} {dup 32768 lt {
dup -12 bitshift 48 or exch
dup -6 bitshift 63 and exch 63 and} {
dup -18 bitshift 56 or exch
dup -12 bitshift 63 and exch
dup -6 bitshift 63 and exch 63 and} def
dup -6 bitshift 63 and exch 63 and} ifelse} ifelse} if} def
/enc_ns {0 msg n 9 getinterval {48 sub exch 10 mul add} forall % Numeric
dup -24 bitshift exch % Sequence
dup -18 bitshift 63 and exch
Expand All @@ -514,24 +516,21 @@ begin
seta msg n 2 add get get} def % Shift 3 A

% Table of operations - operating table?
/op_tab [ % predicate applicable sets encoding
<< /can {2 eci eq } /intake 1 /output 2 /sets 2#11111 /enc {27 enc_eci1 } >> % ECI1 ABCDE
<< /can {3 eci eq } /intake 1 /output 3 /sets 2#11111 /enc {27 enc_eci2 } >> % ECI2 ABCDE
<< /can {4 eci eq } /intake 1 /output 4 /sets 2#11111 /enc {27 enc_eci3 } >> % ECI3 ABCDE
<< /can {5 eci eq } /intake 1 /output 5 /sets 2#11111 /enc {27 enc_eci4 } >> % ECI4 ABCDE
<< /can {digits 9 ge } /intake 9 /output 6 /sets 2#11111 /enc {31 enc_ns } >> % NS ABCDE
<< /can {seta c known} /intake 1 /output 1 /sets 2#00001 /enc { seta c get} >> % A A
<< /can {setb c known} /intake 1 /output 1 /sets 2#00010 /enc { setb c get} >> % B B
<< /can {setc c known} /intake 1 /output 1 /sets 2#00100 /enc { setc c get} >> % C C
<< /can {setd c known} /intake 1 /output 1 /sets 2#01000 /enc { setd c get} >> % D D
<< /can {sete c known} /intake 1 /output 1 /sets 2#10000 /enc { sete c get} >> % E E
<< /can {num_a 1 ge } /intake 1 /output 2 /sets 2#00010 /enc {59 seta c get} >> % SHA B
<< /can {num_a 2 ge } /intake 2 /output 3 /sets 2#00010 /enc {56 enc_sha2 } >> % SHA2 B
<< /can {num_a 3 ge } /intake 3 /output 4 /sets 2#00010 /enc {57 enc_sha3 } >> % SHA3 B
<< /can {setb c known} /intake 1 /output 2 /sets 2#00001 /enc {59 setb c get} >> % SHB A
<< /can {setc c known} /intake 1 /output 2 /sets 2#11011 /enc {60 setc c get} >> % SHC ABCDE
<< /can {setd c known} /intake 1 /output 2 /sets 2#10111 /enc {61 setd c get} >> % SHD ABCDE
<< /can {sete c known} /intake 1 /output 2 /sets 2#01111 /enc {62 sete c get} >> % SHE ABCDE
/op_tab [ % predicate applicable sets encoding
<< /can {eci 1 ge } /intake 1 /output {out_eci} /sets 2#11111 /enc {27 enc_eci } >> % ECI ABCDE
<< /can {digits 9 ge } /intake 9 /output {6 } /sets 2#11111 /enc {31 enc_ns } >> % NS ABCDE
<< /can {seta c known} /intake 1 /output {1 } /sets 2#00001 /enc { seta c get} >> % A A
<< /can {setb c known} /intake 1 /output {1 } /sets 2#00010 /enc { setb c get} >> % B B
<< /can {setc c known} /intake 1 /output {1 } /sets 2#00100 /enc { setc c get} >> % C C
<< /can {setd c known} /intake 1 /output {1 } /sets 2#01000 /enc { setd c get} >> % D D
<< /can {sete c known} /intake 1 /output {1 } /sets 2#10000 /enc { sete c get} >> % E E
<< /can {num_a 1 ge } /intake 1 /output {2 } /sets 2#00010 /enc {59 seta c get} >> % SHA B
<< /can {num_a 2 ge } /intake 2 /output {3 } /sets 2#00010 /enc {56 enc_sha2 } >> % SHA2 B
<< /can {num_a 3 ge } /intake 3 /output {4 } /sets 2#00010 /enc {57 enc_sha3 } >> % SHA3 B
<< /can {setb c known} /intake 1 /output {2 } /sets 2#00001 /enc {59 setb c get} >> % SHB A
<< /can {setc c known} /intake 1 /output {2 } /sets 2#11011 /enc {60 setc c get} >> % SHC ABCDE
<< /can {setd c known} /intake 1 /output {2 } /sets 2#10111 /enc {61 setd c get} >> % SHD ABCDE
<< /can {sete c known} /intake 1 /output {2 } /sets 2#01111 /enc {62 sete c get} >> % SHE ABCDE
] def

% Add idx to each entry
Expand All @@ -543,23 +542,22 @@ begin
% Get the shortest encoded length for the code set (state) and plot the path
/get_best_length {
/latch_length_s latch_length state get def % Get latch length row targetting the code set
max_int /op op_tab 0 get def /org 0 def % Values used if this is not a viable code set
max_int % Length returned if this is not a viable code set
code_set_operations state get { % Loop over operations that apply to this code set
/op_ exch def op_ /can get exec { % Execute predicate to see if the operation applies to input
/m n op_ /intake get sub 15 and def % Use intake to index back into circular history buffers
/org_ best_origin m get state get def % Get the best prior code set
best_length m get org_ get % Get the corresponding length of encoding
latch_length_s org_ get add % Add latch length
op_ /output get add % Add output length to yield resulting length
2 copy gt {
exch /op op_ def /org org_ def % Pick the shortest length and make a note of it
/op exch def %
op /can get exec { % Determine if the operation accepts the input
/m n op /intake get sub 15 and def % Get index into circular history buffers
/org best_origin m get state get def % Get the best prior code set
best_length m get org get % Get the corresponding encoding length
latch_length_s org get add % Add latch length
op /output get exec add % Add output length to yield resulting length
2 copy gt { % Compare lengths
exch % Keep the shorter length
path_op_0 state op /idx get put % Store operation in path
prior_code_set_0 state org put % Store prior set in path
} if pop % Pop off the longer (or equal) length
} if
} forall

% Plot the path
prior_code_set_0 state org put
path_op_0 state op /idx get put
} def

% Unrolled loop to get the best prior code set using a row of
Expand Down Expand Up @@ -601,22 +599,16 @@ begin

% Get the best code set to end with. Code sets with a pad code are first pick
/priority [0 1 4 2 3] def
priority 0 get dup best_length_0 exch get
priority 1 4 getinterval {dup best_length_0 exch get dup 3 index lt {4 2 roll} if pop pop} forall
0 max_int priority {dup best_length_0 exch get dup 3 index lt {4 2 roll} if pop pop} forall
/j exch def
/state exch def

% End in a code set which has a pad code
/pad_code [33 33 0 0 28] def
/final_code_set pad_code state get 0 eq {0} {state} ifelse def

% Insert a latch to A if the code set does not have a pad code.
% There is something about this that doesn't seem right.
% To paraphrase the standard:
% If the message codewords exactly fill out all the message
% regions of the symbol then the latch to A would be unnecessary
% and would in fact overflow the buffer and cause an error.
pad_code state get 0 eq {j 1 add array dup j 58 put} {j array} ifelse
% Insert a latch to A if padding is necessary and the code set does not have a pad code.
pad_code state get 0 eq j maxlen lt and {j 1 add array dup j 58 put} {j array} ifelse
/padval pad_code final_code_set get def
/len j def

Expand Down

0 comments on commit 5ae614c

Please sign in to comment.