be4311c07e14feb728abc6425ee606ffaa611a58
markd
  Fri Jan 22 06:46:58 2021 -0800
merge with master

diff --git src/lib/matrixMarket.c src/lib/matrixMarket.c
new file mode 100644
index 0000000..cced410
--- /dev/null
+++ src/lib/matrixMarket.c
@@ -0,0 +1,130 @@
+#include "common.h"
+#include "linefile.h"
+#include "obscure.h"
+#include "sqlNum.h"
+#include "matrixMarket.h"
+
+void matrixMarketJustNumberCoordinates(struct matrixMarket *mm, char *fileName)
+/* Make sure that the matrix is of the type we can handle */
+{
+if (differentWord(mm->format, "coordinate"))
+    errAbort("%s is not a MatrixMarket matrix in coordinate format", fileName);
+if (differentWord(mm->type, "integer") && differentWord(mm->type, "real"))
+    errAbort("%s has numbers in %s format, can only handle real and integer",
+	fileName, mm->type);
+if (differentWord(mm->symmetries, "general"))
+    errAbort("%s has %s symmetries, can only handle general symmetries", 
+        fileName, mm->symmetries);
+}
+
+struct matrixMarket *matrixMarketOpen(char *fileName)
+/* Open a matrixMarket file and read header, return a handle for use in more routines. */
+{
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[6];	// Big enough for header
+int rowSize;
+
+/* Get header line, check for errors */
+rowSize = lineFileChopNext(lf, row, ArraySize(row));
+lineFileExpectWords(lf, 5, rowSize);
+if (differentString(row[0], "%%MatrixMarket"))
+   errAbort("%s is not a MatrixMarket file", fileName);
+if (differentWord(row[1], "matrix"))
+    errAbort("%s is not a MatrixMarket matrix", fileName);
+
+/* Allocate our return object and fill in what we can from the header line */
+struct matrixMarket *mm;
+AllocVar(mm);
+mm->lf = lf;
+mm->format = cloneString(row[2]);
+mm->type = cloneString(row[3]);
+mm->symmetries = cloneString(row[4]);
+
+/* Precalculate a shortcut or two */
+mm->isInt = sameWord(mm->type, "integer");
+
+/* Get the dimensions line and save it in our data structure */
+rowSize = lineFileChopNext(lf, row, ArraySize(row));
+lineFileExpectWords(lf, 3, rowSize);
+mm->colCount = lineFileNeedNum(lf, row, 0);
+mm->rowCount = lineFileNeedNum(lf, row, 1);
+mm->valCount = lineFileNeedNum(lf, row, 2);
+if (mm->colCount <= 0 || mm->rowCount <= 0)
+    errAbort("%d x %d matrix in %s, dimensions must be positive)", mm->colCount, mm->rowCount, fileName);
+
+return mm;
+}
+
+void matrixMarketClose(struct matrixMarket **pMm)
+/* Close down matrix market and free up associated resources */
+{
+struct matrixMarket *mm = *pMm;
+if (mm != NULL)
+    {
+    lineFileClose(&mm->lf);
+    freeMem(mm->format);
+    freeMem(mm->type);
+    freeMem(mm->symmetries);
+    freeMem(mm->row);
+    freez(pMm);
+    }
+}
+
+
+boolean matrixMarketNext(struct matrixMarket *mm)
+/* Fetch next value from matrix market, returning FALSE if at end of file */
+{
+char *row[4];
+struct lineFile *lf = mm->lf;
+int rowSize = lineFileChopNext(lf, row, ArraySize(row));
+if (rowSize <= 0)
+    return FALSE;
+lineFileExpectWords(lf, 3, rowSize);
+mm->x = sqlUnsigned(row[0]) - 1;
+if (mm->x >= mm->colCount)
+    errAbort("X coordinate %d too big, %d max, line %d of %s", mm->x+1, mm->colCount, 
+	lf->lineIx, lf->fileName);
+mm->y = sqlUnsigned(row[1]) - 1;
+if (mm->y >= mm->rowCount)
+    errAbort("Y coordinate %d too big, %d max, line %d of %s", mm->y+1, mm->rowCount, 
+	lf->lineIx, lf->fileName);
+char *val = row[2];
+mm->val = (mm->isInt ? sqlSigned(val) : sqlDouble(val));
+return TRUE;
+}
+
+boolean matrixMarketNextRow(struct matrixMarket *mm)
+/* Fetch next row into mm->row, return FALSE at eof.  Beware this may skip rows
+ * so look at mm->rowIx as well */
+{
+if (mm->lastRow)
+    return FALSE;
+if (mm->row == NULL)
+    {
+    if (!matrixMarketNext(mm))   /* We always start one into the row - this catches empty matrix*/
+        return FALSE;
+    mm->rowIx = mm->y;
+    AllocArray(mm->row, mm->colCount);
+    }
+zeroBytes(mm->row, mm->colCount * sizeof(mm->row[0]));
+mm->rowIx = mm->y;
+mm->row[mm->x] = mm->val;
+for (;;)
+    {
+    if (!matrixMarketNext(mm))
+        {
+	mm->lastRow = TRUE;
+	break;
+	}
+    if (mm->y != mm->rowIx)
+        {
+	if (mm->y < mm->rowIx)
+	    errAbort("%s is not a sorted-by-y matrix-market on line %d", mm->lf->fileName, 
+		mm->lf->lineIx);
+	break;
+	}
+    mm->row[mm->x] = mm->val;
+    }
+return TRUE;
+}
+