SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
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]

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.
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

int main (int argc, char **argv)
 

Function Documentation

◆ main()

int main ( int argc,
char ** argv )

Definition at line 93 of file sddsmatrixmult.c.

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