Commit: bce389f0d683d84cf92632e9e2f314505b928d8d
Parent: dca23e416ee968820bb82665c120e15000143278
Author: Randy Palamar
Date:   Tue, 29 Oct 2024 09:46:14 -0600
support inverse hadamard matrices with dimension 2^n * 12
we need this for arrays with 48 columns
Diffstat:
2 files changed, 55 insertions(+), 3 deletions(-)
diff --git a/beamformer.c b/beamformer.c
@@ -119,7 +119,8 @@ alloc_shader_storage(BeamformerCtx *ctx, Arena a)
 	cs->hadamard_dim       = (uv2){.x = dec_data_dim.z, .y = dec_data_dim.z};
 	size hadamard_elements = dec_data_dim.z * dec_data_dim.z;
 	i32  *hadamard         = alloc(&a, i32, hadamard_elements);
-	fill_hadamard(hadamard, dec_data_dim.z);
+	i32  *tmp              = alloc(&a, i32, hadamard_elements);
+	fill_hadamard_transpose(hadamard, tmp, dec_data_dim.z);
 	glDeleteBuffers(1, &cs->hadamard_ssbo);
 	glCreateBuffers(1, &cs->hadamard_ssbo);
 	glNamedBufferStorage(cs->hadamard_ssbo, hadamard_elements * sizeof(i32), hadamard, 0);
diff --git a/util.c b/util.c
@@ -1,4 +1,19 @@
 /* See LICENSE for license details. */
+static i32 hadamard_12_12_transpose[] = {
+	1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+	1, -1, -1,  1, -1, -1, -1,  1,  1,  1, -1,  1,
+	1,  1, -1, -1,  1, -1, -1, -1,  1,  1,  1, -1,
+	1, -1,  1, -1, -1,  1, -1, -1, -1,  1,  1,  1,
+	1,  1, -1,  1, -1, -1,  1, -1, -1, -1,  1,  1,
+	1,  1,  1, -1,  1, -1, -1,  1, -1, -1, -1,  1,
+	1,  1,  1,  1, -1,  1, -1, -1,  1, -1, -1, -1,
+	1, -1,  1,  1,  1, -1,  1, -1, -1,  1, -1, -1,
+	1, -1, -1,  1,  1,  1, -1,  1, -1, -1,  1, -1,
+	1, -1, -1, -1,  1,  1,  1, -1,  1, -1, -1,  1,
+	1,  1, -1, -1, -1,  1,  1,  1, -1,  1, -1, -1,
+	1, -1,  1, -1, -1, -1,  1,  1,  1, -1,  1, -1,
+};
+
 static void *
 mem_clear(u8 *p, u8 c, size len)
 {
@@ -258,9 +273,41 @@ parse_f64(s8 s)
 }
 
 static void
-fill_hadamard(i32 *m, u32 dim)
+fill_kronecker_sub_matrix(i32 *out, i32 out_stride, i32 scale, i32 *b, uv2 b_dim)
+{
+	for (u32 i = 0; i < b_dim.y; i++)
+		for (u32 j = 0; j < b_dim.x; j++)
+			out[i * out_stride + j] = scale * b[i * b_dim.x + j];
+}
+
+/* NOTE: this won't check for valid space/etc and assumes row major order */
+static void
+kronecker_product(i32 *out, i32 *a, uv2 a_dim, i32 *b, uv2 b_dim)
 {
-	ASSERT(dim && ISPOWEROF2(dim));
+	uv2 out_dim = {.x = a_dim.x * b_dim.x, .y = a_dim.y * b_dim.y};
+	for (u32 i = 0; i < a_dim.y; i++) {
+		for (u32 j = 0; j < a_dim.x; j++) {
+			fill_kronecker_sub_matrix(out + j * b_dim.y + i * out_dim.y * b_dim.x,
+			                          out_dim.y, a[i * a_dim.x + j], b, b_dim);
+		}
+	}
+}
+
+/* NOTE/TODO: to support even more hadamard sizes use the Paley construction */
+static void
+fill_hadamard_transpose(i32 *out, i32 *tmp, u32 dim)
+{
+	ASSERT(dim);
+	b32 power_of_2 = ISPOWEROF2(dim);
+
+	if (!power_of_2) {
+		ASSERT(dim % 12 == 0);
+		dim /= 12;
+	}
+
+	i32 *m;
+	if (power_of_2) m = out;
+	else            m = tmp;
 
 	#define IND(i, j) ((i) * dim + (j))
 	m[0] = 1;
@@ -275,4 +322,8 @@ fill_hadamard(i32 *m, u32 dim)
 		}
 	}
 	#undef IND
+
+	if (!power_of_2)
+		kronecker_product(out, tmp, (uv2){.x = dim, .y = dim}, hadamard_12_12_transpose,
+		                  (uv2){.x = 12, .y = 12});
 }