MagickCore  7.1.2-29
Convert, Edit, Or Compose Bitmap Images
matrix.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % M M AAA TTTTT RRRR IIIII X X %
7 % MM MM A A T R R I X X %
8 % M M M AAAAA T RRRR I X %
9 % M M A A T R R I X X %
10 % M M A A T R R IIIII X X %
11 % %
12 % %
13 % MagickCore Matrix Methods %
14 % %
15 % Software Design %
16 % Cristy %
17 % August 2007 %
18 % %
19 % %
20 % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/license/ %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 ␌
39 /*
40  Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/blob-private.h"
45 #include "MagickCore/cache.h"
46 #include "MagickCore/exception.h"
47 #include "MagickCore/exception-private.h"
48 #include "MagickCore/image-private.h"
49 #include "MagickCore/matrix.h"
50 #include "MagickCore/matrix-private.h"
51 #include "MagickCore/memory_.h"
52 #include "MagickCore/memory-private.h"
53 #include "MagickCore/nt-base-private.h"
54 #include "MagickCore/pixel-accessor.h"
55 #include "MagickCore/resource_.h"
56 #include "MagickCore/semaphore.h"
57 #include "MagickCore/thread-private.h"
58 #include "MagickCore/utility.h"
59 #include "MagickCore/utility-private.h"
60 ␌
61 /*
62  Typedef declaration.
63 */
65 {
66  CacheType
67  type;
68 
69  size_t
70  columns,
71  rows,
72  stride;
73 
74  MagickSizeType
75  length;
76 
77  MagickBooleanType
78  mapped,
79  synchronize;
80 
81  char
82  path[MagickPathExtent];
83 
84  int
85  file;
86 
87  void
88  *elements;
89 
91  *semaphore;
92 
93  size_t
94  signature;
95 };
96 ␌
97 /*
98 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
99 % %
100 % %
101 % %
102 % A c q u i r e M a t r i x I n f o %
103 % %
104 % %
105 % %
106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107 %
108 % AcquireMatrixInfo() allocates the ImageInfo structure.
109 %
110 % The format of the AcquireMatrixInfo method is:
111 %
112 % MatrixInfo *AcquireMatrixInfo(const size_t columns,const size_t rows,
113 % const size_t stride,ExceptionInfo *exception)
114 %
115 % A description of each parameter follows:
116 %
117 % o columns: the matrix columns.
118 %
119 % o rows: the matrix rows.
120 %
121 % o stride: the matrix stride.
122 %
123 % o exception: return any errors or warnings in this structure.
124 %
125 */
126 
127 #if defined(SIGBUS)
128 static void MatrixSignalHandler(int magick_unused(status))
129 {
130  magick_unreferenced(status);
131  ThrowFatalException(CacheFatalError,"UnableToExtendMatrixCache");
132 }
133 #endif
134 
135 static inline MagickOffsetType WriteMatrixElements(
136  const MatrixInfo *magick_restrict matrix_info,const MagickOffsetType offset,
137  const MagickSizeType length,const unsigned char *magick_restrict buffer)
138 {
139  MagickOffsetType
140  i;
141 
142  ssize_t
143  count;
144 
145  LockSemaphoreInfo(matrix_info->semaphore);
146  if (lseek(matrix_info->file,offset,SEEK_SET) < 0)
147  {
148  UnlockSemaphoreInfo(matrix_info->semaphore);
149  return((MagickOffsetType) -1);
150  }
151  count=0;
152  for (i=0; i < (MagickOffsetType) length; i+=count)
153  {
154  count=MagickWrite(matrix_info->file,buffer+i,(size_t) MagickMin(length-
155  (MagickSizeType) i,(MagickSizeType) MagickMaxBufferExtent));
156  if (count <= 0)
157  break;
158  }
159  UnlockSemaphoreInfo(matrix_info->semaphore);
160  return(i);
161 }
162 
163 static MagickBooleanType SetMatrixExtent(
164  MatrixInfo *magick_restrict matrix_info,MagickSizeType length)
165 {
166  MagickOffsetType
167  count,
168  extent,
169  offset;
170 
171  if (length != (MagickSizeType) ((MagickOffsetType) length))
172  return(MagickFalse);
173  offset=(MagickOffsetType) lseek(matrix_info->file,0,SEEK_END);
174  if (offset < 0)
175  return(MagickFalse);
176  if ((MagickSizeType) offset >= length)
177  return(MagickTrue);
178  extent=(MagickOffsetType) length-1;
179  count=WriteMatrixElements(matrix_info,extent,1,(const unsigned char *) "");
180 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
181  if (matrix_info->synchronize != MagickFalse)
182  (void) posix_fallocate(matrix_info->file,offset+1,extent-offset);
183 #endif
184 #if defined(SIGBUS)
185  (void) signal(SIGBUS,MatrixSignalHandler);
186 #endif
187  return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
188 }
189 
190 MagickExport MatrixInfo *AcquireMatrixInfo(const size_t columns,
191  const size_t rows,const size_t stride,ExceptionInfo *exception)
192 {
193  char
194  *synchronize;
195 
196  MagickBooleanType
197  status;
198 
199  MatrixInfo
200  *matrix_info;
201 
202  matrix_info=(MatrixInfo *) AcquireMagickMemory(sizeof(*matrix_info));
203  if (matrix_info == (MatrixInfo *) NULL)
204  return((MatrixInfo *) NULL);
205  (void) memset(matrix_info,0,sizeof(*matrix_info));
206  matrix_info->signature=MagickCoreSignature;
207  matrix_info->columns=columns;
208  matrix_info->rows=rows;
209  matrix_info->stride=stride;
210  matrix_info->semaphore=AcquireSemaphoreInfo();
211  synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
212  if (synchronize != (const char *) NULL)
213  {
214  matrix_info->synchronize=IsStringTrue(synchronize);
215  synchronize=DestroyString(synchronize);
216  }
217  matrix_info->length=(MagickSizeType) columns*rows*stride;
218  if (matrix_info->columns != (size_t) (matrix_info->length/rows/stride))
219  {
220  (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
221  "CacheResourcesExhausted","`%s'","matrix cache");
222  return(DestroyMatrixInfo(matrix_info));
223  }
224  matrix_info->type=MemoryCache;
225  status=AcquireMagickResource(AreaResource,matrix_info->length);
226  if ((status != MagickFalse) &&
227  (matrix_info->length == (MagickSizeType) ((size_t) matrix_info->length)) &&
228  ((size_t) matrix_info->length <= GetMaxMemoryRequest()))
229  {
230  status=AcquireMagickResource(MemoryResource,matrix_info->length);
231  if (status != MagickFalse)
232  {
233  matrix_info->mapped=MagickFalse;
234  matrix_info->elements=MagickAssumeAligned(AcquireAlignedMemory(1,
235  (size_t) matrix_info->length));
236  if (matrix_info->elements == NULL)
237  {
238  matrix_info->mapped=MagickTrue;
239  matrix_info->elements=MapBlob(-1,IOMode,0,(size_t)
240  matrix_info->length);
241  }
242  if (matrix_info->elements == (unsigned short *) NULL)
243  RelinquishMagickResource(MemoryResource,matrix_info->length);
244  }
245  }
246  matrix_info->file=(-1);
247  if (matrix_info->elements == (unsigned short *) NULL)
248  {
249  status=AcquireMagickResource(DiskResource,matrix_info->length);
250  if (status == MagickFalse)
251  {
252  (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
253  "CacheResourcesExhausted","`%s'","matrix cache");
254  return(DestroyMatrixInfo(matrix_info));
255  }
256  matrix_info->type=DiskCache;
257  matrix_info->file=AcquireUniqueFileResource(matrix_info->path);
258  if (matrix_info->file == -1)
259  return(DestroyMatrixInfo(matrix_info));
260  status=AcquireMagickResource(MapResource,matrix_info->length);
261  if (status != MagickFalse)
262  {
263  status=SetMatrixExtent(matrix_info,matrix_info->length);
264  if (status != MagickFalse)
265  matrix_info->elements=(void *) MapBlob(matrix_info->file,IOMode,0,
266  (size_t) matrix_info->length);
267  if (matrix_info->elements != NULL)
268  matrix_info->type=MapCache;
269  else
270  RelinquishMagickResource(MapResource,matrix_info->length);
271  }
272  }
273  return(matrix_info);
274 }
275 ␌
276 /*
277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
278 % %
279 % %
280 % %
281 % A c q u i r e M a g i c k M a t r i x %
282 % %
283 % %
284 % %
285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286 %
287 % AcquireMagickMatrix() allocates and returns a matrix in the form of an
288 % array of pointers to an array of doubles, with all values pre-set to zero.
289 %
290 % This used to generate the two dimensional matrix, and vectors required
291 % for the GaussJordanElimination() method below, solving some system of
292 % simultaneous equations.
293 %
294 % The format of the AcquireMagickMatrix method is:
295 %
296 % double **AcquireMagickMatrix(const size_t number_rows,
297 % const size_t size)
298 %
299 % A description of each parameter follows:
300 %
301 % o number_rows: the number pointers for the array of pointers
302 % (first dimension).
303 %
304 % o size: the size of the array of doubles each pointer points to
305 % (second dimension).
306 %
307 */
308 MagickExport double **AcquireMagickMatrix(const size_t number_rows,
309  const size_t size)
310 {
311  double
312  **matrix;
313 
314  ssize_t
315  i,
316  j;
317 
318  matrix=(double **) AcquireQuantumMemory(number_rows,sizeof(*matrix));
319  if (matrix == (double **) NULL)
320  return((double **) NULL);
321  for (i=0; i < (ssize_t) number_rows; i++)
322  {
323  matrix[i]=(double *) AcquireQuantumMemory(size,sizeof(*matrix[i]));
324  if (matrix[i] == (double *) NULL)
325  {
326  for (j=0; j < i; j++)
327  matrix[j]=(double *) RelinquishMagickMemory(matrix[j]);
328  matrix=(double **) RelinquishMagickMemory(matrix);
329  return((double **) NULL);
330  }
331  for (j=0; j < (ssize_t) size; j++)
332  matrix[i][j]=0.0;
333  }
334  return(matrix);
335 }
336 ␌
337 /*
338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
339 % %
340 % %
341 % %
342 % D e s t r o y M a t r i x I n f o %
343 % %
344 % %
345 % %
346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347 %
348 % DestroyMatrixInfo() dereferences a matrix, deallocating memory associated
349 % with the matrix.
350 %
351 % The format of the DestroyImage method is:
352 %
353 % MatrixInfo *DestroyMatrixInfo(MatrixInfo *matrix_info)
354 %
355 % A description of each parameter follows:
356 %
357 % o matrix_info: the matrix.
358 %
359 */
360 MagickExport MatrixInfo *DestroyMatrixInfo(MatrixInfo *matrix_info)
361 {
362  assert(matrix_info != (MatrixInfo *) NULL);
363  assert(matrix_info->signature == MagickCoreSignature);
364  LockSemaphoreInfo(matrix_info->semaphore);
365  switch (matrix_info->type)
366  {
367  case MemoryCache:
368  {
369  if (matrix_info->mapped == MagickFalse)
370  matrix_info->elements=RelinquishAlignedMemory(matrix_info->elements);
371  else
372  {
373  (void) UnmapBlob(matrix_info->elements,(size_t) matrix_info->length);
374  matrix_info->elements=(unsigned short *) NULL;
375  }
376  RelinquishMagickResource(MemoryResource,matrix_info->length);
377  break;
378  }
379  case MapCache:
380  {
381  (void) UnmapBlob(matrix_info->elements,(size_t) matrix_info->length);
382  matrix_info->elements=NULL;
383  RelinquishMagickResource(MapResource,matrix_info->length);
384  magick_fallthrough;
385  }
386  case DiskCache:
387  {
388  if (matrix_info->file != -1)
389  (void) close_utf8(matrix_info->file);
390  (void) RelinquishUniqueFileResource(matrix_info->path);
391  RelinquishMagickResource(DiskResource,matrix_info->length);
392  break;
393  }
394  default:
395  break;
396  }
397  UnlockSemaphoreInfo(matrix_info->semaphore);
398  RelinquishSemaphoreInfo(&matrix_info->semaphore);
399  return((MatrixInfo *) RelinquishMagickMemory(matrix_info));
400 }
401 ␌
402 /*
403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
404 % %
405 % %
406 % %
407 % G e t M a t r i x C o l u m n s %
408 % %
409 % %
410 % %
411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
412 %
413 % GetMatrixColumns() returns the number of columns in the matrix.
414 %
415 % The format of the GetMatrixColumns method is:
416 %
417 % size_t GetMatrixColumns(const MatrixInfo *matrix_info)
418 %
419 % A description of each parameter follows:
420 %
421 % o matrix_info: the matrix.
422 %
423 */
424 MagickExport size_t GetMatrixColumns(const MatrixInfo *matrix_info)
425 {
426  assert(matrix_info != (MatrixInfo *) NULL);
427  assert(matrix_info->signature == MagickCoreSignature);
428  return(matrix_info->columns);
429 }
430 ␌
431 /*
432 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
433 % %
434 % %
435 % %
436 % G e t M a t r i x E l e m e n t %
437 % %
438 % %
439 % %
440 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
441 %
442 % GetMatrixElement() returns the specified element in the matrix.
443 %
444 % The format of the GetMatrixElement method is:
445 %
446 % MagickBooleanType GetMatrixElement(const MatrixInfo *matrix_info,
447 % const ssize_t x,const ssize_t y,void *value)
448 %
449 % A description of each parameter follows:
450 %
451 % o matrix_info: the matrix columns.
452 %
453 % o x: the matrix x-offset.
454 %
455 % o y: the matrix y-offset.
456 %
457 % o value: return the matrix element in this buffer.
458 %
459 */
460 
461 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
462 {
463  if (x < 0L)
464  return(0L);
465  if (x >= (ssize_t) columns)
466  return((ssize_t) (columns-1));
467  return(x);
468 }
469 
470 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
471 {
472  if (y < 0L)
473  return(0L);
474  if (y >= (ssize_t) rows)
475  return((ssize_t) (rows-1));
476  return(y);
477 }
478 
479 static inline MagickOffsetType ReadMatrixElements(
480  const MatrixInfo *magick_restrict matrix_info,const MagickOffsetType offset,
481  const MagickSizeType length,unsigned char *magick_restrict buffer)
482 {
483  MagickOffsetType
484  i;
485 
486  ssize_t
487  count;
488 
489  LockSemaphoreInfo(matrix_info->semaphore);
490  if (lseek(matrix_info->file,offset,SEEK_SET) < 0)
491  {
492  UnlockSemaphoreInfo(matrix_info->semaphore);
493  return((MagickOffsetType) -1);
494  }
495  count=0;
496  for (i=0; i < (MagickOffsetType) length; i+=count)
497  {
498  count=MagickRead(matrix_info->file,buffer+i,(size_t) MagickMin(length-i,
499  (MagickSizeType) MagickMaxBufferExtent));
500  if (count <= 0)
501  break;
502  }
503  UnlockSemaphoreInfo(matrix_info->semaphore);
504  return(i);
505 }
506 
507 MagickExport MagickBooleanType GetMatrixElement(const MatrixInfo *matrix_info,
508  const ssize_t x,const ssize_t y,void *value)
509 {
510  MagickOffsetType
511  count,
512  i;
513 
514  assert(matrix_info != (const MatrixInfo *) NULL);
515  assert(matrix_info->signature == MagickCoreSignature);
516  i=EdgeY(y,matrix_info->rows)*(MagickOffsetType) matrix_info->columns+
517  EdgeX(x,matrix_info->columns);
518  if (matrix_info->type != DiskCache)
519  {
520  (void) memcpy(value,(unsigned char *) matrix_info->elements+i*
521  (MagickOffsetType) matrix_info->stride,matrix_info->stride);
522  return(MagickTrue);
523  }
524  count=ReadMatrixElements(matrix_info,i*(MagickOffsetType) matrix_info->stride,
525  matrix_info->stride,(unsigned char *) value);
526  if (count != (MagickOffsetType) matrix_info->stride)
527  return(MagickFalse);
528  return(MagickTrue);
529 }
530 ␌
531 /*
532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
533 % %
534 % %
535 % %
536 % G e t M a t r i x R o w s %
537 % %
538 % %
539 % %
540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
541 %
542 % GetMatrixRows() returns the number of rows in the matrix.
543 %
544 % The format of the GetMatrixRows method is:
545 %
546 % size_t GetMatrixRows(const MatrixInfo *matrix_info)
547 %
548 % A description of each parameter follows:
549 %
550 % o matrix_info: the matrix.
551 %
552 */
553 MagickExport size_t GetMatrixRows(const MatrixInfo *matrix_info)
554 {
555  assert(matrix_info != (const MatrixInfo *) NULL);
556  assert(matrix_info->signature == MagickCoreSignature);
557  return(matrix_info->rows);
558 }
559 ␌
560 /*
561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
562 % %
563 % %
564 % %
565 + L e a s t S q u a r e s A d d T e r m s %
566 % %
567 % %
568 % %
569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
570 %
571 % LeastSquaresAddTerms() adds one set of terms and associate results to the
572 % given matrix and vectors for solving using least-squares function fitting.
573 %
574 % The format of the AcquireMagickMatrix method is:
575 %
576 % void LeastSquaresAddTerms(double **matrix,double **vectors,
577 % const double *terms,const double *results,const size_t rank,
578 % const size_t number_vectors);
579 %
580 % A description of each parameter follows:
581 %
582 % o matrix: the square matrix to add given terms/results to.
583 %
584 % o vectors: the result vectors to add terms/results to.
585 %
586 % o terms: the pre-calculated terms (without the unknown coefficient
587 % weights) that forms the equation being added.
588 %
589 % o results: the result(s) that should be generated from the given terms
590 % weighted by the yet-to-be-solved coefficients.
591 %
592 % o rank: the rank or size of the dimensions of the square matrix.
593 % Also the length of vectors, and number of terms being added.
594 %
595 % o number_vectors: Number of result vectors, and number or results being
596 % added. Also represents the number of separable systems of equations
597 % that is being solved.
598 %
599 % Example of use...
600 %
601 % 2 dimensional Affine Equations (which are separable)
602 % c0*x + c2*y + c4*1 => u
603 % c1*x + c3*y + c5*1 => v
604 %
605 % double **matrix = AcquireMagickMatrix(3UL,3UL);
606 % double **vectors = AcquireMagickMatrix(2UL,3UL);
607 % double terms[3], results[2];
608 % ...
609 % for each given x,y -> u,v
610 % terms[0] = x;
611 % terms[1] = y;
612 % terms[2] = 1;
613 % results[0] = u;
614 % results[1] = v;
615 % LeastSquaresAddTerms(matrix,vectors,terms,results,3UL,2UL);
616 % ...
617 % if ( GaussJordanElimination(matrix,vectors,3UL,2UL) ) {
618 % c0 = vectors[0][0];
619 % c2 = vectors[0][1];
620 % c4 = vectors[0][2];
621 % c1 = vectors[1][0];
622 % c3 = vectors[1][1];
623 % c5 = vectors[1][2];
624 % }
625 % else
626 % printf("Matrix unsolvable\n");
627 % RelinquishMagickMatrix(matrix,3UL);
628 % RelinquishMagickMatrix(vectors,2UL);
629 %
630 */
631 MagickPrivate void LeastSquaresAddTerms(double **matrix,double **vectors,
632  const double *terms,const double *results,const size_t rank,
633  const size_t number_vectors)
634 {
635  ssize_t
636  i,
637  j;
638 
639  for (j=0; j < (ssize_t) rank; j++)
640  {
641  for (i=0; i < (ssize_t) rank; i++)
642  matrix[i][j]+=terms[i]*terms[j];
643  for (i=0; i < (ssize_t) number_vectors; i++)
644  vectors[i][j]+=results[i]*terms[j];
645  }
646 }
647 ␌
648 /*
649 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
650 % %
651 % %
652 % %
653 + G a u s s J o r d a n E l i m n a t i o n %
654 % %
655 % %
656 % %
657 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
658 %
659 % GaussJordanElimination() returns a matrix in reduced row echelon form,
660 % while simultaneously reducing and thus solving the augmented results
661 % matrix.
662 %
663 % The format of the GaussJordanElimination method is:
664 %
665 % MagickBooleanType GaussJordanElimination(double **matrix,
666 % double **vectors,const size_t rank,const size_t number_vectors)
667 %
668 % A description of each parameter follows:
669 %
670 % o matrix: the matrix to be reduced, as an 'array of row pointers'.
671 %
672 % o vectors: the additional matrix argumenting the matrix for row reduction.
673 % Producing an 'array of column vectors'.
674 %
675 % o rank: The size of the matrix (both rows and columns).
676 % Also represents the number terms that need to be solved.
677 %
678 % o number_vectors: Number of vectors columns, argumenting the above matrix.
679 % Usually 1, but can be more for more complex equation solving.
680 %
681 % Note that the 'matrix' is given as a 'array of row pointers' of rank size.
682 % That is values can be assigned as matrix[row][column] where 'row' is
683 % typically the equation, and 'column' is the term of the equation.
684 % That is the matrix is in the form of a 'row first array'.
685 %
686 % However 'vectors' is a 'array of column pointers' which can have any number
687 % of columns, with each column array the same 'rank' size as 'matrix'.
688 %
689 % This allows for simpler handling of the results, especially is only one
690 % column 'vector' is all that is required to produce the desired solution.
691 %
692 % For example, the 'vectors' can consist of a pointer to a simple array of
693 % doubles. when only one set of simultaneous equations is to be solved from
694 % the given set of coefficient weighted terms.
695 %
696 % double **matrix = AcquireMagickMatrix(8UL,8UL);
697 % double coefficients[8];
698 % ...
699 % GaussJordanElimination(matrix,&coefficients,8UL,1UL);
700 %
701 % However by specifying more 'columns' (as an 'array of vector columns', you
702 % can use this function to solve a set of 'separable' equations.
703 %
704 % For example a distortion function where u = U(x,y) v = V(x,y)
705 % And the functions U() and V() have separate coefficients, but are being
706 % generated from a common x,y->u,v data set.
707 %
708 % Another example is generation of a color gradient from a set of colors at
709 % specific coordinates, such as a list x,y -> r,g,b,a.
710 %
711 % You can also use the 'vectors' to generate an inverse of the given 'matrix'
712 % though as a 'column first array' rather than a 'row first array'. For
713 % details see http://en.wikipedia.org/wiki/Gauss-Jordan_elimination
714 %
715 */
716 MagickPrivate MagickBooleanType GaussJordanElimination(double **matrix,
717  double **vectors,const size_t rank,const size_t number_vectors)
718 {
719 #define GaussJordanSwap(x,y) \
720 { \
721  double temp = (x); \
722  (x)=(y); \
723  (y)=temp; \
724 }
725 #define GaussJordanSwapLD(x,y) \
726 { \
727  long double temp = (x); \
728  (x)=(y); \
729  (y)=temp; \
730 }
731 #define ThrowGaussJordanException() \
732 { \
733  for (i=0; i < (ssize_t) rank; i++) \
734  hp_matrix[i]=(long double *) RelinquishMagickMemory(hp_matrix[i]); \
735  hp_matrix=(long double **) RelinquishMagickMemory(hp_matrix); \
736  if (pivots != (ssize_t *) NULL) \
737  pivots=(ssize_t *) RelinquishMagickMemory(pivots); \
738  if (rows != (ssize_t *) NULL) \
739  rows=(ssize_t *) RelinquishMagickMemory(rows); \
740  if (columns != (ssize_t *) NULL) \
741  columns=(ssize_t *) RelinquishMagickMemory(columns); \
742  return(MagickFalse); \
743 }
744 
745  long double
746  **hp_matrix = (long double **) NULL,
747  scale;
748 
749  ssize_t
750  column,
751  *columns = (ssize_t *) NULL,
752  i,
753  j,
754  *pivots = (ssize_t *) NULL,
755  row,
756  *rows = (ssize_t *) NULL;
757 
758  /*
759  Allocate high precision matrix.
760  */
761  hp_matrix=(long double **) AcquireQuantumMemory(rank,sizeof(*hp_matrix));
762  if (hp_matrix == (long double **) NULL)
763  return(MagickFalse);
764  for (i=0; i < (ssize_t) rank; i++)
765  {
766  hp_matrix[i]=(long double *) AcquireQuantumMemory(rank,
767  sizeof(*hp_matrix[i]));
768  if (hp_matrix[i] == (long double *) NULL)
769  ThrowGaussJordanException();
770  for (j=0; j < (ssize_t) rank; j++)
771  hp_matrix[i][j]=(long double)matrix[i][j];
772  }
773  columns=(ssize_t *) AcquireQuantumMemory(rank,sizeof(*columns));
774  rows=(ssize_t *) AcquireQuantumMemory(rank,sizeof(*rows));
775  pivots=(ssize_t *) AcquireQuantumMemory(rank,sizeof(*pivots));
776  if ((columns == (ssize_t *) NULL) || (rows == (ssize_t *) NULL) ||
777  (pivots == (ssize_t *) NULL))
778  ThrowGaussJordanException();
779  (void) memset(columns,0,rank*sizeof(*columns));
780  (void) memset(rows,0,rank*sizeof(*rows));
781  (void) memset(pivots,0,rank*sizeof(*pivots));
782  for (i=0; i < (ssize_t) rank; i++)
783  {
784  long double
785  max = 0.0;
786 
787  ssize_t
788  k;
789 
790  /*
791  Partial pivoting: find the largest absolute value in the unreduced
792  submatrix.
793  */
794  column=(-1);
795  row=(-1);
796  for (j=0; j < (ssize_t) rank; j++)
797  if (pivots[j] != 1)
798  for (k=0; k < (ssize_t) rank; k++)
799  if ((pivots[k] == 0) && (fabsl(hp_matrix[j][k]) > max))
800  {
801  max=fabsl(hp_matrix[j][k]);
802  row=j;
803  column=k;
804  }
805  if ((column == -1) || (row == -1) || (fabsl(max) < LDBL_MIN))
806  ThrowGaussJordanException(); /* Singular or nearly singular matrix */
807  pivots[column]++;
808  if (row != column)
809  {
810  for (k=0; k < (ssize_t) rank; k++)
811  GaussJordanSwapLD(hp_matrix[row][k],hp_matrix[column][k]);
812  for (k=0; k < (ssize_t) number_vectors; k++)
813  GaussJordanSwap(vectors[k][row],vectors[k][column]);
814  }
815  rows[i]=row;
816  columns[i]=column;
817  if (fabsl(hp_matrix[column][column]) < LDBL_MIN)
818  ThrowGaussJordanException(); /* Singular matrix */
819  scale=1.0L/hp_matrix[column][column];
820  hp_matrix[column][column]=1.0;
821  for (j=0; j < (ssize_t) rank; j++)
822  hp_matrix[column][j]*=scale;
823  for (j=0; j < (ssize_t) number_vectors; j++)
824  vectors[j][column]*=(double) scale;
825  for (j=0; j < (ssize_t) rank; j++)
826  if (j != column)
827  {
828  scale=hp_matrix[j][column];
829  hp_matrix[j][column]=0.0;
830  for (k=0; k < (ssize_t) rank; k++)
831  hp_matrix[j][k]-=scale*hp_matrix[column][k];
832  for (k=0; k < (ssize_t) number_vectors; k++)
833  vectors[k][j]-=(double)(scale*(long double) vectors[k][column]);
834  }
835  }
836  for (j=(ssize_t) rank-1; j >= 0; j--)
837  if (columns[j] != rows[j])
838  for (i=0; i < (ssize_t) rank; i++)
839  GaussJordanSwapLD(hp_matrix[i][columns[j]],hp_matrix[i][rows[j]]);
840  /*
841  Copy back the result to the original matrix.
842  */
843  for (i=0; i < (ssize_t) rank; i++)
844  for (j=0; j < (ssize_t) rank; j++)
845  matrix[i][j]=(double)hp_matrix[i][j];
846  /*
847  Free resources.
848  */
849  for (i=0; i < (ssize_t) rank; i++)
850  hp_matrix[i]=(long double *) RelinquishMagickMemory(hp_matrix[i]);
851  hp_matrix=(long double **) RelinquishMagickMemory(hp_matrix);
852  pivots=(ssize_t *) RelinquishMagickMemory(pivots);
853  rows=(ssize_t *) RelinquishMagickMemory(rows);
854  columns=(ssize_t *) RelinquishMagickMemory(columns);
855  return(MagickTrue);
856 }
857 ␌
858 /*
859 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
860 % %
861 % %
862 % %
863 % M a t r i x T o I m a g e %
864 % %
865 % %
866 % %
867 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
868 %
869 % MatrixToImage() returns a matrix as an image. The matrix elements must be
870 % of type double otherwise nonsense is returned.
871 %
872 % The format of the MatrixToImage method is:
873 %
874 % Image *MatrixToImage(const MatrixInfo *matrix_info,
875 % ExceptionInfo *exception)
876 %
877 % A description of each parameter follows:
878 %
879 % o matrix_info: the matrix.
880 %
881 % o exception: return any errors or warnings in this structure.
882 %
883 */
884 MagickExport Image *MatrixToImage(const MatrixInfo *matrix_info,
885  ExceptionInfo *exception)
886 {
887  CacheView
888  *image_view;
889 
890  double
891  max_value,
892  min_value,
893  scale_factor;
894 
895  Image
896  *image;
897 
898  MagickBooleanType
899  status;
900 
901  ssize_t
902  y;
903 
904  assert(matrix_info != (const MatrixInfo *) NULL);
905  assert(matrix_info->signature == MagickCoreSignature);
906  assert(exception != (ExceptionInfo *) NULL);
907  assert(exception->signature == MagickCoreSignature);
908  if (matrix_info->stride < sizeof(double))
909  return((Image *) NULL);
910  /*
911  Determine range of matrix.
912  */
913  (void) GetMatrixElement(matrix_info,0,0,&min_value);
914  max_value=min_value;
915  for (y=0; y < (ssize_t) matrix_info->rows; y++)
916  {
917  ssize_t
918  x;
919 
920  for (x=0; x < (ssize_t) matrix_info->columns; x++)
921  {
922  double
923  value;
924 
925  if (GetMatrixElement(matrix_info,x,y,&value) == MagickFalse)
926  continue;
927  if (value < min_value)
928  min_value=value;
929  else
930  if (value > max_value)
931  max_value=value;
932  }
933  }
934  if ((min_value == 0.0) && (max_value == 0.0))
935  scale_factor=0;
936  else
937  if (min_value == max_value)
938  {
939  scale_factor=(double) QuantumRange/min_value;
940  min_value=0;
941  }
942  else
943  scale_factor=(double) QuantumRange/(max_value-min_value);
944  /*
945  Convert matrix to image.
946  */
947  image=AcquireImage((ImageInfo *) NULL,exception);
948  image->columns=matrix_info->columns;
949  image->rows=matrix_info->rows;
950  image->colorspace=GRAYColorspace;
951  status=MagickTrue;
952  image_view=AcquireAuthenticCacheView(image,exception);
953 #if defined(MAGICKCORE_OPENMP_SUPPORT)
954  #pragma omp parallel for schedule(static) shared(status) \
955  magick_number_threads(image,image,image->rows,2)
956 #endif
957  for (y=0; y < (ssize_t) image->rows; y++)
958  {
959  double
960  value;
961 
962  Quantum
963  *q;
964 
965  ssize_t
966  x;
967 
968  if (status == MagickFalse)
969  continue;
970  q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
971  if (q == (Quantum *) NULL)
972  {
973  status=MagickFalse;
974  continue;
975  }
976  for (x=0; x < (ssize_t) image->columns; x++)
977  {
978  if (GetMatrixElement(matrix_info,x,y,&value) == MagickFalse)
979  continue;
980  value=scale_factor*(value-min_value);
981  *q=ClampToQuantum(value);
982  q+=(ptrdiff_t) GetPixelChannels(image);
983  }
984  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
985  status=MagickFalse;
986  }
987  image_view=DestroyCacheView(image_view);
988  if (status == MagickFalse)
989  image=DestroyImage(image);
990  return(image);
991 }
992 ␌
993 /*
994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
995 % %
996 % %
997 % %
998 % N u l l M a t r i x %
999 % %
1000 % %
1001 % %
1002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1003 %
1004 % NullMatrix() sets all elements of the matrix to zero.
1005 %
1006 % The format of the memset method is:
1007 %
1008 % MagickBooleanType *NullMatrix(MatrixInfo *matrix_info)
1009 %
1010 % A description of each parameter follows:
1011 %
1012 % o matrix_info: the matrix.
1013 %
1014 */
1015 MagickExport MagickBooleanType NullMatrix(MatrixInfo *matrix_info)
1016 {
1017  ssize_t
1018  x;
1019 
1020  ssize_t
1021  count,
1022  y;
1023 
1024  unsigned char
1025  value;
1026 
1027  assert(matrix_info != (const MatrixInfo *) NULL);
1028  assert(matrix_info->signature == MagickCoreSignature);
1029  if (matrix_info->type != DiskCache)
1030  {
1031  (void) memset(matrix_info->elements,0,(size_t)
1032  matrix_info->length);
1033  return(MagickTrue);
1034  }
1035  value=0;
1036  (void) lseek(matrix_info->file,0,SEEK_SET);
1037  for (y=0; y < (ssize_t) matrix_info->rows; y++)
1038  {
1039  for (x=0; x < (ssize_t) matrix_info->length; x++)
1040  {
1041  count=MagickWrite(matrix_info->file,&value,sizeof(value));
1042  if (count != (ssize_t) sizeof(value))
1043  break;
1044  }
1045  if (x < (ssize_t) matrix_info->length)
1046  break;
1047  }
1048  return(y < (ssize_t) matrix_info->rows ? MagickFalse : MagickTrue);
1049 }
1050 ␌
1051 /*
1052 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1053 % %
1054 % %
1055 % %
1056 % R e l i n q u i s h M a g i c k M a t r i x %
1057 % %
1058 % %
1059 % %
1060 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1061 %
1062 % RelinquishMagickMatrix() frees the previously acquired matrix (array of
1063 % pointers to arrays of doubles).
1064 %
1065 % The format of the RelinquishMagickMatrix method is:
1066 %
1067 % double **RelinquishMagickMatrix(double **matrix,
1068 % const size_t number_rows)
1069 %
1070 % A description of each parameter follows:
1071 %
1072 % o matrix: the matrix to relinquish
1073 %
1074 % o number_rows: the first dimension of the acquired matrix (number of
1075 % pointers)
1076 %
1077 */
1078 MagickExport double **RelinquishMagickMatrix(double **matrix,
1079  const size_t number_rows)
1080 {
1081  ssize_t
1082  i;
1083 
1084  if (matrix == (double **) NULL )
1085  return(matrix);
1086  for (i=0; i < (ssize_t) number_rows; i++)
1087  matrix[i]=(double *) RelinquishMagickMemory(matrix[i]);
1088  matrix=(double **) RelinquishMagickMemory(matrix);
1089  return(matrix);
1090 }
1091 ␌
1092 /*
1093 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1094 % %
1095 % %
1096 % %
1097 % S e t M a t r i x E l e m e n t %
1098 % %
1099 % %
1100 % %
1101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1102 %
1103 % SetMatrixElement() sets the specified element in the matrix.
1104 %
1105 % The format of the SetMatrixElement method is:
1106 %
1107 % MagickBooleanType SetMatrixElement(const MatrixInfo *matrix_info,
1108 % const ssize_t x,const ssize_t y,void *value)
1109 %
1110 % A description of each parameter follows:
1111 %
1112 % o matrix_info: the matrix columns.
1113 %
1114 % o x: the matrix x-offset.
1115 %
1116 % o y: the matrix y-offset.
1117 %
1118 % o value: set the matrix element to this value.
1119 %
1120 */
1121 
1122 MagickExport MagickBooleanType SetMatrixElement(const MatrixInfo *matrix_info,
1123  const ssize_t x,const ssize_t y,const void *value)
1124 {
1125  MagickOffsetType
1126  count,
1127  i;
1128 
1129  assert(matrix_info != (const MatrixInfo *) NULL);
1130  assert(matrix_info->signature == MagickCoreSignature);
1131  i=y*(MagickOffsetType) matrix_info->columns+x;
1132  if ((i < 0) ||
1133  (((MagickSizeType) i*matrix_info->stride) >= matrix_info->length))
1134  return(MagickFalse);
1135  if (matrix_info->type != DiskCache)
1136  {
1137  (void) memcpy((unsigned char *) matrix_info->elements+i*
1138  (MagickOffsetType) matrix_info->stride,value,matrix_info->stride);
1139  return(MagickTrue);
1140  }
1141  count=WriteMatrixElements(matrix_info,i*(MagickOffsetType)
1142  matrix_info->stride,matrix_info->stride,(unsigned char *) value);
1143  if (count != (MagickOffsetType) matrix_info->stride)
1144  return(MagickFalse);
1145  return(MagickTrue);
1146 }
Definition: image.h:132