📄 cmat.cpp
字号:
#include "stdafx.h"
#include "str.h"
#include "error.h"
#include "CDiag.h"
#include "CMat.h"
#include "CMatSym.h"
#include "eigen.h"
#include "math.h"
#include "def.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>
CMatrix::CMatrix()
{
li = 0;
col = 0;
bTranspose = FALSE;
bLocked = FALSE;
pData = NULL;
pMem = NULL;
pMemName = NULL;
}
CMatrix::CMatrix(long l, long c)
{
li = l;
col = c;
bTranspose = FALSE;
pData = NULL;
pMem = NULL;
bLocked = FALSE;
pMemName = NULL;
Allocate();
}
CMatrix::~CMatrix()
{
long l;
Unlock();
if (pMem != NULL)
{
delete pMem;
pMem = NULL;
}
if (pMemName != NULL)
{
delete pMemName;
}
}
void CMatrix::Allocate(long l1, long l2)
{
li = l1;
col = l2;
Allocate();
}
/***********************************************************************
* Load a matrix from a text file.
* For the format look at the Save() fct right after this one.
* BEWARE, there is a severe limitation : all numbers MAY NOT be longer than 13 characters.
* Otherwize the matrix actually get is not at all the one expected !!!
* If you save the matrix with the Save() fct (as it is expected), this limitation is
* respected and there is nothing to worry about.
***********************************************************************/
int CMatrix::Load(char *filename)
{
int fh;
long lcol, lrow;
CMemory *pmem;
char *str, *pstr;
valtype val;
long lfilelen, lprevpos;
unsigned int nread, nbuflen = 60000, ntmplen = 40;
Msg(1, str_LOADING, filename);
fh = _open(filename, _O_RDONLY | _O_BINARY); /*Open the file in text mode, overwites it if it doesn't exist*/
if (fh == -1)
{
Msg(-1, str_ERR_FILE_OPEN, strerror(errno));
return ERR_FILE_OPEN;
}
/*Allocate reading memory*/
_lseek(fh, 0, SEEK_END);
lfilelen = _tell(fh); /*Calculates the file lenght*/
if (lfilelen == -1L)
{
Msg(0, strerror(errno));
_close(fh); /*Close the file*/
return -errno;
}
_lseek(fh, 0, SEEK_SET);
if (lfilelen < (long)nbuflen)
nbuflen = lfilelen;
lprevpos = 0;
pmem = new CMemory();
pmem->Allocate(nbuflen);
str = (char *)pmem->GetPtr();
/*Read the first part of the file*/
nread = _read(fh, str, nbuflen);
if (nread == -1)
{
Msg(-1, str_ERR_FILE_READ, strerror(errno));
return -errno;
}
/*Read the matrix's number of rows*/
li = atol(strtok(str, str_TABRT));
if (li == 0L)
{
Msg(-1, str_ERR_MAT_LOAD_ROW);
return ERR_MAT_LOAD_ROW;
}
/*Read the matrix's number of columns*/
col = atol(strtok(NULL, str_TABRT));
if (col == 0L)
{
Msg(-1, str_ERR_MAT_LOAD_COL);
return ERR_MAT_LOAD_COL;
}
pstr = strtok(NULL, str_TABRT);
if (atof(pstr) == 0.0)
{
Msg(-1, str_ERR_MAT_LOAD_HDR);
return ERR_MAT_LOAD_HDR;
}
Allocate(li, col); /*In case of a CMatrixPtr object, it has to allocate memory for the columns*/
Lock();
/* while (isdigit(pstr[0]) == 0 && pstr[0] != '+' && pstr[0] != '-')
pstr++;
pstr = strtok(pstr, str_TABRT);
*/
for (lrow = 1L; lrow <= li; lrow++)
{
for (lcol = 1L; lcol <= col/* - 1L*/; lcol++)
{
val = atof(pstr);
SetAt(lrow, lcol, val);
pstr = strtok(NULL, str_TABRT);
if ((long)pstr - (long)str > (long)(nread - ntmplen))
{ /*read the next part of the file*/
lprevpos = _lseek(fh, lprevpos + (long)pstr - (long)str, SEEK_SET);
nread = _read(fh, str, nbuflen);
if (nread == -1)
{
Msg(-1, str_ERR_FILE_READ, strerror(errno));
return -errno;
}
pstr = strtok(str, str_TABRT);
}
}
}
_close(fh);
Unlock();
pmem->ReleasePtr();
delete pmem;
Msg(-1, str_LOADED);
return 0;
}
/***********************************************************************
* Save the matrix in a text file. The only parameter to this fct is the file name
* The file format is as follow:
*
* <row number>\t<Column number>\n
* <col1 name>\t<col2 name>\t...
* <el11>\t<el12>\t...\t<el1n>\n
* <el21>\t...........\t<el2n>\n
* .
* .
* .
* <elm1>\t...........\t<elmn>\n
* EOF
***********************************************************************/
int CMatrix::Save(char *filename)
{
int fh;
long row, col, lcol, lrow;
char str[20];
Msg(1, str_SAVING, filename);
fh = _open(filename, _O_CREAT | _O_WRONLY | _O_TEXT, _S_IREAD | _S_IWRITE);
/*Create the file in text mode, overwites it if it already exists*/
if (fh == -1)
{
Msg(-1, str_ERR_FILE_OPEN, strerror(errno));
return ERR_FILE_OPEN;
}
lcol = GetCol();
lrow = GetLi();
Lock();
sprintf(str, "%ld\t%ld\n", lrow, lcol);
_write(fh, str, strlen(str));
char name[MAX_NAME];
if (GetColName(1, name, sizeof(name)) == 0)
{
/*There are cols name, so save it*/
for (col = 1L; col <= lcol; col++)
{
if (GetColName(col, name, sizeof(name)) < 0)
break;
if (col == lcol)
sprintf(str, "%s\n", name);
else
sprintf(str, "%s\t", name);
_write(fh, str, strlen(str));
}
}
for (row = 1L; row <= lrow; row++)
{
for (col = 1L; col <= lcol; col++)
{
sprintf(str, "%.6E\t", GetAt(row, col));
_write(fh, str, strlen(str));
}
_write(fh, "\n", 1);
}
Unlock();
if (_close(fh) == -1)
{
Msg(0, str_ERR_FILE_CLOSE, strerror(errno));
}
Msg(-1, str_SAVED);
return 0;
}
/***********************************************************************
* Add to this matrix the matrix pMat2
***********************************************************************/
void CMatrix::Add(CMatrix *pMat2)
{
long c, l, llen, clen;
/*Verify that the matrices have the same dimension*/
if (pMat2->GetCol() != col || pMat2->GetLi() != li)
Fail(NULL);
llen = GetLi();
clen = GetCol();
Lock();
pMat2->Lock();
for (l = 1; l <= llen; l++)
{
for (c = 1; c <= clen; c++)
{
SetAt(l, c, GetAt(l, c) + pMat2->GetAt(l, c));
}
}
Unlock();
pMat2->Unlock();
}
/***********************************************************************
* Multiply pMat1 by pMat2, and put the result in this matrix
*
* if bResize is FALSE, does nothing else than a normal matrix multiplication
*
* if bResize is TRUE, and if the number of rows in pMat2 is < than the number of columns
* of pMat1, it adds some rows at the end of pMat2 (their value being zero) in order to be able
* to actually do the multiplication
* if bResize is true it computes the mulpitiplation only on the elements of this matrix
* up to the column lNewCol and to the row lNewRow
***********************************************************************/
void CMatrix::Multiply(CMatrix *pMat1, CMatrix *pMat2, BOOL bResize, long lNewRow, long lNewCol)
{
long c, l, r, llen, clen, k;
valtype val;
if (col == 0 || li == 0)
{ /*the matrix was not initialised*/
col = pMat2->GetCol();
li = pMat1->GetLi();
Allocate();
}
else
{ /*Verify that the matrices have the same dimension*/
if (bResize != TRUE && (pMat2->GetCol() != col || pMat1->GetLi() != li))
Fail(NULL);
}
//Initialize();
r = lmin(pMat2->GetLi(), pMat1->GetCol());
if (bResize == FALSE)
{
llen = GetLi();
clen = GetCol();
}
else
{
llen = lNewRow;
clen = lNewCol;
}
Lock();
pMat2->Lock();
pMat1->Lock();
for (l = 1L; l <= llen; l++)
{
for (c = 1L; c <= clen; c++)
{
val = (valtype)0;
for (k = 1L; k <= r; k++)
{
val += pMat1->GetAt(l, k) * pMat2->GetAt(k, c);
}
SetAt(l, c, val);
}
}
Unlock();
pMat2->Unlock();
pMat1->Unlock();
}
/***********************************************************************
* Multiply this matrix by the diagonal matrix pDiag
*
* If bResize = FALSE, and the columns' number of this matrix is different than the rows'
* number of the diagonal matrix, an exception is thrown.
*
* If bResize is TRUE, then col's number may be < than the row's number. The diagonal matrix
* will then be seen as a smaller matrix.
***********************************************************************/
void CMatrix::Multiply(CDiag *pDiag, BOOL bResize)
{
long c, l, llen, clen;
/*Verify that the matrices have the same dimension*/
if (bResize == FALSE && pDiag->GetLi() != GetCol())
Fail(NULL);
llen = GetLi();
clen = GetCol();
Lock();
pDiag->Lock();
for (l = 1L; l <= llen; l++)
{
for (c = 1L; c <= clen; c++)
{
SetAt(l, c, GetAt(l, c) * pDiag->GetAt(c));
}
}
Unlock();
pDiag->Unlock();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -