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