SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
sddsmatrixmult.c File Reference

Detailed Description

Multiplies matrices from SDDS files and outputs the result.

This program reads two SDDS files containing matrix data, performs matrix multiplication, and writes the resulting product matrix to an output SDDS file. It supports options for data reuse, matrix commutation, output format selection, and verbosity for debugging and diagnostics.

Usage

sddsmatrixmult [<file1>] <file2> [<output>]
[-pipe=[input][,output]]
[-majorOrder=row|column]
[-commute]
[-reuse]
[-verbose]
[-ascii]
[-threads=<number>]

Options

Option Description
-pipe Use input and/or output pipes.
-majorOrder Specify output in row-major or column-major order.
-commute Swap file1 and file2 to reverse the order of multiplication.
-reuse Reuse the last data page if a file runs out of pages.
-ascii Output file in ASCII mode.
-verbose Enable detailed output for diagnostics.
-threads Number of threads for matrix multiplication.
License
This file is distributed under the terms of the Software License Agreement found in the file LICENSE included with this distribution.
Author
M. Borland, C. Saunders, L. Emery, R. Soliday, H. Shang

Definition in file sddsmatrixmult.c.

#include "mdb.h"
#include "scan.h"
#include "match_string.h"
#include "matlib.h"
#include "SDDS.h"

Go to the source code of this file.

Functions

static int threaded_matrix_mult (MATRIX *C, MATRIX *A, MATRIX *B, int threads)
 
int main (int argc, char **argv)
 

Function Documentation

◆ main()

int main ( int argc,
char ** argv )

Definition at line 101 of file sddsmatrixmult.c.

101 {
102 SCANNED_ARG *s_arg;
103 SDDS_TABLE input1Page, input2Page, outputPage;
104
105 char *inputfile1, *inputfile2, *outputfile;
106 char **Input1Column, **Input1DoubleColumn;
107 char **Input2Column, **Input2DoubleColumn;
108 char **OutputDoubleColumn;
109 long Input1Rows, Input1DoubleColumns;
110 long Input2Rows, Input2DoubleColumns;
111 long OutputRows;
112 int32_t Input1Columns, Input2Columns, OutputDoubleColumns;
113
114 long i, i_arg, col, commute;
115#define BUFFER_SIZE_INCREMENT 20
116 MATRIX *R1, *R1Trans, *R2, *R2Trans, *R3, *R3Trans;
117 long verbose;
118 long ipage, ipage1, ipage2, lastPage1, lastPage2, ascii;
119 unsigned long pipeFlags, majorOrderFlag;
120 long tmpfile_used, noWarnings;
121 long reuse;
122 int threads;
123 short columnMajorOrder = -1;
124
126 argc = scanargs(&s_arg, argc, argv);
127 if (argc == 1)
128 bomb(NULL, USAGE);
129
130 inputfile1 = inputfile2 = outputfile = NULL;
131 Input1DoubleColumn = Input2DoubleColumn = OutputDoubleColumn = NULL;
132 Input1Rows = Input1DoubleColumns = Input2Rows = Input2DoubleColumns = OutputRows = lastPage1 = lastPage2 = 0;
133 tmpfile_used = 0;
134 verbose = 0;
135 pipeFlags = 0;
136 noWarnings = 0;
137 reuse = commute = ascii = 0;
138 threads = 1;
139
140 for (i_arg = 1; i_arg < argc; i_arg++) {
141 if (s_arg[i_arg].arg_type == OPTION) {
142 switch (match_string(s_arg[i_arg].list[0], commandline_option, N_OPTIONS, UNIQUE_MATCH)) {
143 case CLO_MAJOR_ORDER:
144 majorOrderFlag = 0;
145 s_arg[i_arg].n_items--;
146 if (s_arg[i_arg].n_items > 0 &&
147 (!scanItemList(&majorOrderFlag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
148 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
149 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL))) {
150 SDDS_Bomb("Invalid -majorOrder syntax/values");
151 }
152 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
153 columnMajorOrder = 1;
154 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
155 columnMajorOrder = 0;
156 break;
157 case CLO_PIPE:
158 if (!processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags))
159 SDDS_Bomb("Invalid -pipe syntax");
160 break;
161 case CLO_VERBOSE:
162 verbose = 1;
163 break;
164 case CLO_ASCII:
165 ascii = 1;
166 break;
167 case CLO_REUSE:
168 reuse = 1;
169 break;
170 case CLO_COMMUTE:
171 commute = 1;
172 break;
173 case CLO_THREADS:
174 if (s_arg[i_arg].n_items != 2 ||
175 sscanf(s_arg[i_arg].list[1], "%d", &threads) != 1 || threads < 1)
176 SDDS_Bomb("Invalid -threads syntax");
177 break;
178 default:
179 bomb("Unrecognized option given", USAGE);
180 }
181 } else {
182 if (!inputfile1)
183 inputfile1 = s_arg[i_arg].list[0];
184 else if (!inputfile2)
185 inputfile2 = s_arg[i_arg].list[0];
186 else if (!outputfile)
187 outputfile = s_arg[i_arg].list[0];
188 else
189 bomb("Too many filenames given", USAGE);
190 }
191 }
192
193 if (pipeFlags & USE_STDIN && inputfile1) {
194 if (outputfile)
195 SDDS_Bomb("Too many filenames (sddsxref)");
196 outputfile = inputfile2;
197 inputfile2 = inputfile1;
198 inputfile1 = NULL;
199 }
200
201 processFilenames("sddsmatrixmult", &inputfile1, &outputfile, pipeFlags, noWarnings, &tmpfile_used);
202 if (!inputfile2)
203 SDDS_Bomb("Second input file not specified");
204
205 if (commute) {
206 char *ptr = inputfile1;
207 inputfile1 = inputfile2;
208 inputfile2 = ptr;
209 }
210
211 /* Initialize input files */
212 if (!SDDS_InitializeInput(&input1Page, inputfile1))
213 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
214
215 Input1Column = (char **)SDDS_GetColumnNames(&input1Page, &Input1Columns);
216
217 if (!SDDS_InitializeInput(&input2Page, inputfile2))
218 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
219
220 Input2Column = (char **)SDDS_GetColumnNames(&input2Page, &Input2Columns);
221
222 if (!SDDS_InitializeOutput(&outputPage, ascii ? SDDS_ASCII : SDDS_BINARY, 1, "Matrix product", "Matrix product", outputfile))
223 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
224
225 if (columnMajorOrder != -1)
226 outputPage.layout.data_mode.column_major = columnMajorOrder;
227 else
228 outputPage.layout.data_mode.column_major = input1Page.layout.data_mode.column_major;
229
230 /* Process data pages */
231 while ((ipage1 = SDDS_ReadTable(&input1Page)) && (ipage2 = SDDS_ReadTable(&input2Page))) {
232 if ((reuse && (ipage1 < 0 && ipage2 < 0)) ||
233 (!reuse && (ipage1 < 0 || ipage2 < 0)))
234 break;
235
236 ipage = MAX(ipage1, ipage2);
237
238 /* Process first input file */
239 if (ipage1 == 1) {
240 Input1DoubleColumns = 0;
241 Input1DoubleColumn = (char **)malloc(Input1Columns * sizeof(char *));
242 /* Count the numerical columns in input1 */
243 for (i = 0; i < Input1Columns; i++) {
244 if (SDDS_NUMERIC_TYPE(SDDS_GetColumnType(&input1Page, i))) {
245 Input1DoubleColumn[Input1DoubleColumns] = Input1Column[i];
246 Input1DoubleColumns++;
247 }
248 }
249 if (!Input1DoubleColumns) {
250 if (verbose) {
251 fprintf(stderr, "No numerical columns in page %ld of file %s.\n", ipage, inputfile1 ? inputfile1 : "stdin");
252 }
253 }
254 Input1Rows = SDDS_CountRowsOfInterest(&input1Page);
255 if (Input1DoubleColumns && Input1Rows)
256 m_alloc(&R1, Input1DoubleColumns, Input1Rows);
257 else if (!Input1Rows) {
258 if (verbose)
259 fprintf(stderr, "No rows in page %ld of file %s.\n", ipage, inputfile1 ? inputfile1 : "stdin");
260 }
261 }
262
263 if (ipage1 > 0) {
264 if (Input1Rows != SDDS_CountRowsOfInterest(&input1Page))
265 fprintf(stderr, "Number of rows in page %ld of file %s changed.\n", ipage, inputfile1 ? inputfile1 : "stdin");
266 for (col = 0; col < Input1DoubleColumns; col++) {
267 if (!(R1->a[col] = (double *)SDDS_GetColumnInDoubles(&input1Page, Input1DoubleColumn[col])))
268 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
269 }
270 lastPage1 = ipage1;
271 if (verbose)
272 fprintf(stderr, "Using page %ld of file %s.\n", lastPage1, inputfile1 ? inputfile1 : "stdin");
273 } else if (ipage1 < 0) {
274 if (verbose)
275 fprintf(stderr, "Reusing page %ld of file %s.\n", lastPage1, inputfile1 ? inputfile1 : "stdin");
276 }
277
278 if (verbose && Input1DoubleColumns && Input1Rows) {
279 m_alloc(&R1Trans, Input1Rows, Input1DoubleColumns);
280 m_trans(R1Trans, R1);
281 m_show(R1Trans, "%9.6le ", "Input matrix 1:\n", stderr);
282 m_free(&R1Trans);
283 }
284
285 /* Process second input file */
286 if (ipage2 == 1) {
287 Input2DoubleColumns = 0;
288 Input2DoubleColumn = (char **)malloc(Input2Columns * sizeof(char *));
289 /* Count the numerical columns in input2 */
290 for (i = 0; i < Input2Columns; i++) {
291 if (SDDS_NUMERIC_TYPE(SDDS_GetColumnType(&input2Page, i))) {
292 Input2DoubleColumn[Input2DoubleColumns] = Input2Column[i];
293 Input2DoubleColumns++;
294 }
295 }
296 if (!Input2DoubleColumns) {
297 if (verbose) {
298 fprintf(stderr, "No numerical columns in page %ld of file %s.\n", ipage, inputfile2);
299 }
300 }
301 Input2Rows = SDDS_CountRowsOfInterest(&input2Page);
302 if (Input2DoubleColumns && Input2Rows)
303 m_alloc(&R2, Input2DoubleColumns, Input2Rows);
304 else if (!Input2Rows) {
305 if (verbose)
306 fprintf(stderr, "No rows in page %ld of file %s.\n", ipage, inputfile2);
307 }
308 }
309
310 if (ipage2 > 0) {
311 if (Input2Rows != SDDS_CountRowsOfInterest(&input2Page))
312 fprintf(stderr, "Number of rows in page %ld of file %s changed.\n", ipage, inputfile2);
313 for (col = 0; col < Input2DoubleColumns; col++) {
314 if (!(R2->a[col] = (double *)SDDS_GetColumnInDoubles(&input2Page, Input2DoubleColumn[col])))
315 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
316 }
317 lastPage2 = ipage2;
318 if (verbose)
319 fprintf(stderr, "Using page %ld of file %s.\n", lastPage2, inputfile2 ? inputfile2 : "stdin");
320 } else if (ipage2 < 0) {
321 if (verbose)
322 fprintf(stderr, "Reusing page %ld of file %s.\n", lastPage2, inputfile2 ? inputfile2 : "stdin");
323 }
324
325 if (verbose && Input2DoubleColumns && Input2Rows) {
326 m_alloc(&R2Trans, Input2Rows, Input2DoubleColumns);
327 m_trans(R2Trans, R2);
328 m_show(R2Trans, "%9.6le ", "Input matrix 2:\n", stderr);
329 m_free(&R2Trans);
330 }
331
332 /* Define output table */
333 if (ipage == 1) {
334 OutputRows = Input1Rows;
335 OutputDoubleColumns = Input2DoubleColumns;
336 if (Input1DoubleColumns != Input2Rows) {
337 fprintf(stderr, "Error: Dimension mismatch in files.\n");
338 fprintf(stderr, "Right-hand matrix (%s) is %ldx%ld.\n",
339 inputfile2 ? inputfile2 : "stdin", Input2Rows, Input2DoubleColumns);
340 fprintf(stderr, "Left-hand matrix (%s) is %ldx%ld.\n",
341 inputfile1 ? inputfile1 : "stdin", Input1Rows, Input1DoubleColumns);
342 exit(EXIT_FAILURE);
343 }
344 }
345
346 /* Perform matrix multiplication */
347 if (OutputRows && OutputDoubleColumns) {
348 if (ipage == 1)
349 m_alloc(&R3, OutputDoubleColumns, OutputRows);
350 if (verbose)
351 fprintf(stderr, "Multiplying %d x %d matrix by %d x %d matrix\n", R2->m, R2->n, R1->m, R1->n);
352 if (!threaded_matrix_mult(R3, R2, R1, threads))
353 SDDS_Bomb("Matrix multiplication failed");
354 if (verbose) {
355 m_alloc(&R3Trans, OutputRows, OutputDoubleColumns);
356 m_trans(R3Trans, R3);
357 m_show(R3Trans, "%9.6le ", "Output matrix:\n", stderr);
358 m_free(&R3Trans);
359 }
360 } else {
361 if (verbose)
362 fprintf(stderr, "Output file will either have no columns or no rows in page %ld.\n", ipage);
363 }
364
365 if (ipage == 1) {
366 for (i = 0; i < Input2DoubleColumns; i++) {
367 if (SDDS_TransferColumnDefinition(&outputPage, &input2Page, Input2DoubleColumn[i], NULL) < 0)
368 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
369 }
370 OutputDoubleColumn = (char **)SDDS_GetColumnNames(&outputPage, &OutputDoubleColumns);
371 if (!SDDS_WriteLayout(&outputPage))
372 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
373 }
374
375 if (!SDDS_StartTable(&outputPage, OutputRows))
376 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
377
378 /* Assign values to output table */
379 if (OutputRows && OutputDoubleColumns) {
380 for (i = 0; i < OutputDoubleColumns; i++) { /* i is the column index */
381 if (!SDDS_SetColumnFromDoubles(&outputPage, SDDS_SET_BY_NAME | SDDS_PASS_BY_REFERENCE,
382 R3->a[i], OutputRows, OutputDoubleColumn[i]))
383 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
384 }
385 }
386
387 if (!SDDS_WriteTable(&outputPage))
388 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
389 }
390
391 /* Terminate SDDS tables */
392 if (!SDDS_Terminate(&input1Page) || !SDDS_Terminate(&input2Page) || !SDDS_Terminate(&outputPage))
393 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
394
395 if (tmpfile_used && !replaceFileAndBackUp(inputfile1, outputfile))
396 return EXIT_FAILURE;
397
398 return EXIT_SUCCESS;
399}
int32_t SDDS_SetColumnFromDoubles(SDDS_DATASET *SDDS_dataset, int32_t mode, double *data, int64_t rows,...)
Sets the values for a single data column using double-precision floating-point numbers.
int64_t SDDS_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset)
Counts the number of rows marked as "of interest" in the current data table.
double * SDDS_GetColumnInDoubles(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of doubles, considering only rows mark...
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:50
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_InitializeOutput(SDDS_DATASET *SDDS_dataset, int32_t data_mode, int32_t lines_per_row, const char *description, const char *contents, const char *filename)
Initializes the SDDS output dataset.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
int32_t SDDS_TransferColumnDefinition(SDDS_DATASET *target, SDDS_DATASET *source, char *name, char *newName)
Transfers a column definition from a source dataset to a target dataset.
char ** SDDS_GetColumnNames(SDDS_DATASET *SDDS_dataset, int32_t *number)
Retrieves the names of all columns in the SDDS dataset.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:474
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:318
int32_t SDDS_GetColumnType(SDDS_DATASET *SDDS_dataset, int32_t index)
Retrieves the data type of a column in the SDDS dataset by its index.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:380
#define SDDS_NUMERIC_TYPE(type)
Checks if the given type identifier corresponds to any numeric type.
Definition SDDStypes.h:138
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
Definition bomb.c:26
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.
long replaceFileAndBackUp(char *file, char *replacement)
Replaces a file with a replacement file and creates a backup of the original.
Definition replacefile.c:78
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
Definition scanargs.c:36
long processPipeOption(char **item, long items, unsigned long *flags)
Definition scanargs.c:357
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:391
long scanItemList(unsigned long *flags, char **item, long *items, unsigned long mode,...)
Scans a list of items and assigns values based on provided keywords and types.

◆ threaded_matrix_mult()

static int threaded_matrix_mult ( MATRIX * C,
MATRIX * A,
MATRIX * B,
int threads )
static

Definition at line 401 of file sddsmatrixmult.c.

401 {
402 long i;
403 long n, m, p;
404
405 if ((m = A->m) != B->n || (n = A->n) != C->n || (p = B->m) != C->m)
406 return 0;
407 if (threads <= 1)
408 return m_mult(C, A, B);
409
410#pragma omp parallel for if (threads > 1) num_threads(threads)
411 for (i = 0; i < n; i++) {
412 long j, k;
413 double *a_i = A->a[i];
414 double *c_i = C->a[i];
415 for (j = 0; j < p; j++) {
416 double sum = 0;
417 for (k = 0; k < m; k++)
418 sum += a_i[k] * B->a[k][j];
419 c_i[j] = sum;
420 }
421 }
422 return 1;
423}