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