You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
digikam/digikam/libs/lprof/cmsmatn.cpp

324 lines
8.0 KiB

/* */
/* Little cms - profiler construction set */
/* Copyright (C) 1998-2001 Marti Maria <marti@littlecms.com> */
/* */
/* THIS SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY */
/* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. */
/* */
/* IN NO EVENT SHALL MARTI MARIA BE LIABLE FOR ANY SPECIAL, INCIDENTAL, */
/* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, */
/* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, */
/* WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF */
/* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE */
/* OF THIS SOFTWARE. */
/* */
/* This file is free software; you can redistribute it and/or modify it */
/* under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* */
/* This program is distributed in the hope that it will be useful, but */
/* WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
/* General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* */
/* As a special exception to the GNU General Public License, if you */
/* distribute this file as part of a program that contains a */
/* configuration script generated by Autoconf, you may include it under */
/* the same distribution terms that you use for the rest of that program. */
/* */
/* Version 1.09a */
#include "lcmsprf.h"
LPMATN cdecl MATNalloc(int Rows, int Cols);
void cdecl MATNfree (LPMATN mat);
LPMATN cdecl MATNmult(LPMATN a1, LPMATN a2);
double cdecl MATNcross(LPMATN a);
void cdecl MATNscalar (LPMATN a, double scl, LPMATN b);
LPMATN cdecl MATNtranspose (LPMATN a);
BOOL cdecl MATNsolve(LPMATN a, LPMATN b);
/* ------------------------------------------------------------ Implementation */
/* Free matrix */
void MATNfree(LPMATN mat)
{
int i;
if (mat == NULL) return;
for (i = 0; i < mat->Rows; i++)
{
if (mat -> Values[i] != NULL)
free (mat->Values[i]);
}
free(mat->Values);
free(mat);
}
/* Allocate (and Zero) a new matrix */
LPMATN MATNalloc(int Rows, int Cols)
{
int i;
LPMATN mat = (LPMATN) malloc (sizeof (MATN));
if (mat == NULL) return mat;
ZeroMemory(mat, sizeof(MATN));
mat->Rows = Rows;
mat->Cols = Cols;
mat->Values = (double**) malloc(Rows * sizeof (double*));
if (mat->Values == NULL) {
free(mat);
return NULL;
}
ZeroMemory(mat -> Values, Rows * sizeof (double*));
for (i = 0; i < Rows; i++)
{
mat-> Values [i] = (double*) malloc(Cols * sizeof (double));
if (mat -> Values[i] == NULL) {
MATNfree(mat);
return NULL;
}
}
return mat;
}
#define DO_SWAP(a, b, tmp) { tmp = (a); (a) = (b); (b) = tmp; }
/* Gauss-Jordan elimination. There is also a more */
/* exahustive non-singular matrix checking part. */
BOOL MATNsolve(LPMATN a, LPMATN b)
{
BOOL status;
int n = a->Rows;
int i, iCol=0, iRow=0, j, k;
double fMax, fAbs, fSave, fInf, temp;
int* aiColIndex;
int* aiRowIndex=0;
int* aiPivoted=0;
if (a->Rows != a->Cols) return false;
status = false;
if((aiColIndex = (int*) malloc(n * sizeof(int))) == NULL)
goto GotError;
if((aiRowIndex = (int*) malloc(n * sizeof(int))) == NULL)
goto GotError;
if((aiPivoted = (int*) malloc(n * sizeof(int))) == NULL)
goto GotError;
ZeroMemory(aiPivoted, n * sizeof(int));
for(i = 0; i < n; i++) {
/* search matrix (excluding pivoted rows) for maximum absolute entry */
fMax = 0.0;
for (j = 0; j < n; j++)
if (aiPivoted[j] != 1)
for (k = 0; k < n; k++)
{
fAbs = fabs(a->Values[j][k]);
if (fAbs >= fMax) {
fMax = fAbs;
iRow = j;
iCol = k;
}
else
if (aiPivoted[k] > 1) {
status = false;
goto GotError;
}
}
aiPivoted[iCol]++;
/* swap rows so that A[iCol][iCol] contains the pivot entry */
if (iRow != iCol) {
for(j = 0; j < n; j++)
DO_SWAP(a->Values[iRow][j], a->Values[iCol][j], temp)
DO_SWAP(b->Values[iRow][0], b->Values[iCol][0], temp)
}
/* keep track of the permutations of the rows */
aiRowIndex[i] = iRow;
aiColIndex[i] = iCol;
if (a->Values[iCol][iCol] == 0.0)
{
status = false;
goto GotError;
}
/* scale the row so that the pivot entry is 1 */
fInf = 1.0 / a->Values[iCol][iCol];
a->Values[iCol][iCol] = 1.0;
for(j = 0; j < n; j++)
a->Values[iCol][j] *= fInf;
b->Values[iCol][0] *= fInf;
/* zero out the pivot column locations in the other rows */
for(j = 0; j < n; j++)
if (j != iCol) {
fSave = a->Values[j][iCol];
a->Values[j][iCol] = 0.0;
for(k = 0; k < n; k++)
a->Values[j][k] -= a->Values[iCol][k] * fSave;
b->Values[j][0] -= b->Values[iCol][0] * fSave;
}
}
/* reorder rows so that A[][] stores the inverse of the original matrix */
for(i = n - 1; i >= 0; i--) {
if(aiRowIndex[i] != aiColIndex[i])
for(j = 0; j < n; j++)
DO_SWAP(a->Values[j][aiRowIndex[i]], a->Values[j][aiColIndex[i]], temp)
}
status = true;
GotError:
if(aiColIndex) free(aiColIndex);
if(aiRowIndex) free(aiRowIndex);
if(aiPivoted) free(aiPivoted);
return status;
}
#undef DO_SWAP
LPMATN MATNmult(LPMATN a1, LPMATN a2)
{
int i, j, k;
LPMATN b;
if (a1->Cols != a2->Rows)
return NULL;
b = MATNalloc (a1->Rows, a2->Cols);
if (b == NULL)
return NULL;
for (i = 0; i < b->Rows; i++) {
for (j = 0; j < b->Cols; j++) {
b->Values[i][j] = 0.0;
for (k = 0; k < a1->Cols; k++) {
b->Values[i][j] += a1->Values[i][k] * a2->Values[k][j];
}
}
}
return b;
}
double MATNcross(LPMATN a)
{
int i;
double prod = 0.0;
for (i = 0; i < a->Rows; i++) {
prod += a->Values[i][0]*a->Values[i][0];
}
return prod;
}
void MATNscalar(LPMATN a, double scl, LPMATN b)
{
int i, j;
if (a->Rows != b->Rows || a->Cols != b->Cols)
return;
for (i = 0; i < a->Rows; i++) {
for (j = 0; j < a->Cols; j++)
b->Values[i][j] = a->Values[i][j] * scl;
}
}
LPMATN MATNtranspose(LPMATN a)
{
LPMATN b = MATNalloc(a->Cols, a->Rows);
if (b != NULL) {
int i, j;
for (i = 0; i < a->Rows; i++)
{
for (j = 0; j < a->Cols; j++)
b->Values[j][i] = a->Values [i][j];
}
}
return b;
}
/* Used for debug purposes */
#ifdef DEBUG
void MATNprintf(char* name, LPMATN mat)
{
int i, j;
printf ("%s:\n", name);
for (i= 0; i < mat->Rows; i++) {
printf ("%3d", i);
for (j = 0; j < mat->Cols; j++)
printf (" %.5f", mat->Values[i][j]);
printf ("\n");
}
}
#endif