Skip to content

Commit 89c8c1c

Browse files
kbowers-jumpReisen
authored andcommitted
Code generators for efficient sorting algorithms usable on and off chain with off-chain standalone tests
1 parent d443c23 commit 89c8c1c

File tree

6 files changed

+444
-0
lines changed

6 files changed

+444
-0
lines changed

program/src/oracle/sort/clean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/sh
2+
rm -rfv bin
3+

program/src/oracle/sort/run_tests

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/bin/sh
2+
3+
module purge || exit 1
4+
module load gcc-9.3.0 || exit 1
5+
6+
./clean || exit 1
7+
mkdir -pv bin || exit 1
8+
9+
CC="gcc -g -Wall -Werror -Wextra -Wconversion -Wstrict-aliasing=2 -Wimplicit-fallthrough=2 -pedantic -D_XOPEN_SOURCE=600 -O2 -march=native -std=c17"
10+
11+
set -x
12+
13+
$CC test_sort_stable.c -o bin/test_sort_stable || exit 1
14+
15+
bin/test_sort_stable || exit 1
16+
17+
echo all tests passed
18+
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
4+
void
5+
sort_gen( int n ) {
6+
7+
# if 0
8+
9+
/* In register variant (PSEUDO OPS ~ 9+4n+3n(n-1))
10+
Assumes switch ~ 3 PSEUDO OPS (LDA,LD,JMP) -> 3 switch statements / 9 pseudo ops
11+
Assumes load ~ 2 PSEUDO OPS (LDA,LD) -> n loads / 2n pseudo ops
12+
Assumes store ~ "
13+
Assumes cswap ~ 6 PSEUDO OPS (CMP,MOV,TESTEQ,CMOV,TESTNEQ,CMOV) / 6*0.5*n*(n-1) pseudo ops */
14+
15+
//printf( "static inline key_t * /* returns (sorted) x */\n" );
16+
//printf( "sort_network_stable( key_t * x, /* indexed [0,n) */\n" );
17+
//printf( " ulong n ) { /* assumes n in [0,%i) */\n", n );
18+
printf( " int c;\n" );
19+
printf( " key_t t" );
20+
for( int i=0; i<n; i++ ) printf( ", x%i", i );
21+
printf( ";\n" );
22+
printf( "\n" );
23+
printf( " switch( n ) {\n" );
24+
for( int i=n; i; i-- ) printf( " case %2iUL: x%i = x[%i]; /* fall through */\n", i, i-1, i-1 );
25+
printf( " default: break;\n" );
26+
printf( " }\n" );
27+
printf( "\n" );
28+
printf( "# define _(i,j) c = BEFORE( x##j, x##i ); t = x##i; x##i = c ? x##j : x##i; x##j = c ? t : x##j\n" );
29+
printf( " switch( n ) {\n" );
30+
for( int i=n-1; i; i-- ) {
31+
printf( " case %2iUL:", i+1 );
32+
for( int j=0; j<i; j++ ) printf( " _(%2i,%2i);", j,j+1 );
33+
printf( " /* fall through */\n" );
34+
}
35+
printf( " default: break;\n" );
36+
printf( " }\n" );
37+
printf( "# undef _\n" );
38+
printf( "\n" );
39+
printf( " switch( n ) {\n" );
40+
for( int i=n; i; i-- ) printf( " case %2iUL: x[%i] = x%i; /* fall through */\n", i, i-1, i-1 );
41+
printf( " default: break;\n" );
42+
printf( " }\n" );
43+
44+
//printf( "\n" );
45+
//printf( " return x;\n" );
46+
//printf( "}\n" );
47+
48+
# else
49+
50+
/* Memory variant (PSEUDO OPS ~ 3+4.5n(n-1))
51+
Assumes switch ~ 3 PSEUDO OPS (LDA,LD,JMP) -> 3 pseudo ops
52+
Assumes cswap ~ 9 PSEUDO OPS (LDA,LDA,LD,LD,CMP,CMOV,CMOV,ST,ST) / 9*0.5*n*(n-1) pseudo ops */
53+
54+
//printf( "static inline key_t * /* returns (sorted) x */\n" );
55+
//printf( "sort_network_stable( key_t * x, /* indexed [0,n) */\n" );
56+
//printf( " ulong n ) { /* assumes n in [0,%i) */\n", n );
57+
58+
printf( " do { /* BEGIN AUTOGENERATED CODE (n=%2i) *****************************/\n", n );
59+
printf( "# define SORT_STABLE_CE(i,j) u = x[(SORT_IDX_T)i]; v = x[(SORT_IDX_T)j]; c = SORT_BEFORE( v, u ); x[(SORT_IDX_T)i] = c ? v : u; x[(SORT_IDX_T)j] = c ? u : v\n" );
60+
printf( " int c;\n" );
61+
printf( " SORT_KEY_T u;\n" );
62+
printf( " SORT_KEY_T v;\n" );
63+
printf( " switch( n ) {\n" );
64+
for( int i=n-1; i>=0; i-- ) {
65+
printf( " case (SORT_IDX_T)%2i:", i+1 );
66+
for( int j=0; j<i; j++ ) printf( " SORT_STABLE_CE(%2i,%2i);", j,j+1 );
67+
printf( " /* fall through */\n" );
68+
}
69+
printf( " case (SORT_IDX_T) 0: return x;\n" );
70+
printf( " default: break;\n" );
71+
printf( " }\n" );
72+
printf( "# undef SORT_STABLE_CE\n" );
73+
printf( " } while(0); /* END AUTOGENERATED CODE *******************************/\n" );
74+
75+
//printf( "\n" );
76+
//printf( " return x;\n" );
77+
//printf( "}\n" );
78+
79+
# endif
80+
81+
}
82+
83+
int
84+
main( int argc,
85+
char ** argv ) {
86+
if( argc!=2 ) { fprintf( stderr, "Usage: %s [max_base_case]\n", argv[0] ); return 1; }
87+
int n = atoi( argv[1] );
88+
if( n<1 ) { fprintf( stderr, "n (%i) must be positive\n", n ); return 1; }
89+
sort_gen( n );
90+
return 0;
91+
}
92+
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#include <stdio.h>
2+
#include "../util/util.h"
3+
4+
#define BEFORE(i,j) (((i)>>16)<((j)>>16))
5+
6+
#define SORT_NAME sort
7+
#define SORT_KEY_T int
8+
#define SORT_IDX_T int
9+
#define SORT_BEFORE(i,j) BEFORE(i,j)
10+
#include "tmpl/sort_stable.c"
11+
12+
int
13+
main( int argc,
14+
char ** argv ) {
15+
(void)argc; (void)argv;
16+
17+
# define N 96
18+
int x[N];
19+
int y[N];
20+
int w[N];
21+
22+
/* Brute force validate small sizes via the 0-1 principle (with
23+
additional information in the keys to validate stability as well). */
24+
25+
for( int n=0; n<=24; n++ ) {
26+
printf( "Zero-One: Testing n=%i\n", n );
27+
for( long b=0L; b<(1L<<n); b++ ) {
28+
for( int i=0; i<n; i++ ) x[i] = (((int)((b>>i) & 1L))<<16) | i;
29+
for( int i=0; i<n; i++ ) w[i] = x[i];
30+
31+
int * z = sort_stable( x,n, y );
32+
33+
/* Make sure that z is a permutation of input data */
34+
for( int i=0; i<n; i++ ) {
35+
int j = z[i] & (int)0xffff; /* j is the index where z was initially */
36+
if( j<0 || j>=n || z[i]!=w[j] ) { printf( "FAIL (corrupt)\n" ); return 1; }
37+
w[j] = -1; /* Mark that this entry has already been confirmed */
38+
}
39+
for( int i=0; i<n; i++ ) if( w[i]!=-1 ) { printf( "FAIL (perm)\n" ); return 1; }
40+
41+
/* Make sure that z is in order and stable */
42+
for( int i=1; i<n; i++ )
43+
if( z[i]<=z[i-1] ) { printf( "FAIL (%s, b=%lx)\n", BEFORE( z[i], z[i-1] ) ? "order" : "stable", b ); return 1; }
44+
}
45+
}
46+
47+
/* Randomized validation for larger sizes */
48+
49+
prng_t _prng[1];
50+
prng_t * prng = prng_join( prng_new( _prng, (uint32_t)0, (uint64_t)0 ) );
51+
52+
int ctr = 0;
53+
for( int iter=0; iter<10000000; iter++ ) {
54+
if( !ctr ) { printf( "Randomized: Completed %i iterations\n", iter ); ctr = 100000; }
55+
ctr--;
56+
57+
int n = (int)(prng_uint32( prng ) % (uint32_t)(N+1)); /* In [0,N], approx uniform IID */
58+
for( int i=0; i<n; i++ ) x[i] = (int)((prng_uint32( prng ) & UINT32_C( 0x00ff0000 )) | (uint32_t)i);
59+
for( int i=0; i<n; i++ ) w[i] = x[i];
60+
61+
int * z = sort_stable( x,n, y );
62+
63+
/* Make sure that z is a permutation of input data */
64+
for( int i=0; i<n; i++ ) {
65+
int j = z[i] & (int)0xffff; /* j is the index where z was initially */
66+
if( j<0 || j>=n || z[i]!=w[j] ) { printf( "FAIL (corrupt)\n" ); return 1; }
67+
w[j] = -1; /* Mark that this entry has already been confirmed */
68+
}
69+
for( int i=0; i<n; i++ ) if( w[i]!=-1 ) { printf( "FAIL (perm)\n" ); return 1; }
70+
71+
/* Make sure that z is in order and stable */
72+
for( int i=1; i<n; i++ )
73+
if( z[i]<=z[i-1] ) { printf( "FAIL (%s)\n", BEFORE( z[i], z[i-1] ) ? "order" : "stable" ); return 1; }
74+
}
75+
76+
prng_delete( prng_leave( prng ) );
77+
78+
printf( "pass\n" );
79+
return 0;
80+
}
81+
82+
#undef BEFORE
83+

0 commit comments

Comments
 (0)