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.
324 lines
8.0 KiB
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
|
|
|
|
|