gnuastro-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnuastro-commits] master e1638dc: Table: Column arithmetic now possible


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master e1638dc: Table: Column arithmetic now possible
Date: Fri, 31 May 2019 15:05:30 -0400 (EDT)

branch: master
commit e1638dc772fc2d6d76509d3db69bd97630c3012c
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    Table: Column arithmetic now possible
    
    With this commit, Table now has a new feature to do arithmetic operations
    on various input columns. It is activated by starting the requested column
    with `arith ' and can do almost all the operations in the Arithmetic
    program, along with some other operators for coordinate conversion.
    
    To use the same infra-structure as the Arithmetic program, some
    generalizations were necessary in the Arithmetic library and programs also,
    but now, along with Table, there is a much more clear and robust
    implementation.
---
 NEWS                        |  23 +-
 bin/arithmetic/arithmetic.c | 487 +++++++++++++-------------------
 bin/table/Makefile.am       |   4 +-
 bin/table/arithmetic.c      | 672 ++++++++++++++++++++++++++++++++++++++++++++
 bin/table/arithmetic.h      |  60 ++++
 bin/table/main.h            |  23 +-
 bin/table/table.c           | 136 +--------
 bin/table/ui.c              | 298 +++++++++++---------
 configure.ac                |   4 +
 doc/gnuastro.texi           | 315 ++++++++++++++-------
 lib/arithmetic.c            | 147 +++++++++-
 lib/gnuastro/arithmetic.h   |   4 +
 lib/gnuastro/blank.h        |   8 +
 lib/gnuastro/list.h         |  24 ++
 lib/list.c                  | 133 +++++++++
 15 files changed, 1679 insertions(+), 659 deletions(-)

diff --git a/NEWS b/NEWS
index b8dcd39..53b8eda 100644
--- a/NEWS
+++ b/NEWS
@@ -32,11 +32,16 @@ See the end of the file for license conditions.
      the book under `--sigclip-median' for a nice use case.
 
   Table:
-   - As part of printing output columns, Table can now convert Image to WCS
-     coordinates and vice-versa. For example if the input catalog has
-     atleast an `ID' column and two `RA' and `DEC' columns the set of
-     options below will produce 5 columns where the last two columns are
-     the image coordinates based on the WCS in `a.fits':
+   - Column arithmetic. It is now possible to apply many operations on the
+     input table columns before printing them in the output. Similar to
+     Arithmetic, but on table columns. The operators and notation is just
+     like the Arithmetic program. See the "Column Arithmetic" section of
+     the book for a detailed discussion and several examples.
+   - WCS to Image coordinate conversion with `wcstoimg' and `imgtowcs'. For
+     example if the input catalog has atleast an `ID' column and two `RA'
+     and `DEC' columns, the set of options below will produce 5 columns
+     where the last two columns are the image coordinates for each row
+     based on the WCS in `a.fits':
            `-cID,RA,DEC -c"arith RA DEC wcstoimg" --wcsfile=a.fits'
    --head: Only output the given number of rows from the top of columns.
    --tail: Only output the given number of rows from the botoom of columns.
@@ -45,6 +50,14 @@ See the end of the file for license conditions.
    - New `speclines.h' library functions and macros related to spectral
      lines. It has many macros with line wavelengths, and several functions
      for using them in combination with their names.
+   - list.h: Functions to return the last element in linked lists. For
+     example `gal_list_sizet_last' or `gal_list_data_last'.
+   - gal_list_data_to_array_ptr: Make an array of pointers from the list.
+   - GAL_BLANK_INT: Blank value for `int' (can be 16-bit or 32-bit).
+   - GAL_BLANK_UINT: Blank value for unsigned `int' (can be 16-bit or 32-bit).
+   - gal_arithmetic_operator_string: Return operator string from code.
+   - gal_arithmetic_set_operator: Return operator code from string.
+
 
 ** Removed features
 
diff --git a/bin/arithmetic/arithmetic.c b/bin/arithmetic/arithmetic.c
index dc74502..7c85a94 100644
--- a/bin/arithmetic/arithmetic.c
+++ b/bin/arithmetic/arithmetic.c
@@ -949,6 +949,184 @@ arithmetic_unique(struct arithmeticparams *p, char 
*token, int operator)
 /***************************************************************/
 /*************      Reverse Polish algorithm       *************/
 /***************************************************************/
+static int
+arithmetic_set_operator(char *string, size_t *num_operands)
+{
+  /* Use the library's main function for its own operators. */
+  int op = gal_arithmetic_set_operator(string, num_operands);
+
+  /* If its not a library operator, check if its an internal operator. */
+  if(op==GAL_ARITHMETIC_OP_INVALID)
+    {
+      /* Non-library operators. */
+      if      (!strcmp(string, "filter-mean"))
+        { op=ARITHMETIC_OP_FILTER_MEAN;           *num_operands=0; }
+      else if (!strcmp(string, "filter-median"))
+        { op=ARITHMETIC_OP_FILTER_MEDIAN;         *num_operands=0; }
+      else if (!strcmp(string, "filter-sigclip-mean"))
+        { op=ARITHMETIC_OP_FILTER_SIGCLIP_MEAN;   *num_operands=0; }
+      else if (!strcmp(string, "filter-sigclip-median"))
+        { op=ARITHMETIC_OP_FILTER_SIGCLIP_MEDIAN; *num_operands=0; }
+      else if (!strcmp(string, "erode"))
+        { op=ARITHMETIC_OP_ERODE;                 *num_operands=0; }
+      else if (!strcmp(string, "dilate"))
+        { op=ARITHMETIC_OP_DILATE;                *num_operands=0; }
+      else if (!strcmp(string, "connected-components"))
+        { op=ARITHMETIC_OP_CONNECTED_COMPONENTS;  *num_operands=0; }
+      else if (!strcmp(string, "fill-holes"))
+        { op=ARITHMETIC_OP_FILL_HOLES;            *num_operands=0; }
+      else if (!strcmp(string, "invert"))
+        { op=ARITHMETIC_OP_INVERT;                *num_operands=0; }
+      else if (!strcmp(string, "interpolate-medianngb"))
+        { op=ARITHMETIC_OP_INTERPOLATE_MEDIANNGB; *num_operands=0; }
+      else if (!strcmp(string, "collapse-sum"))
+        { op=ARITHMETIC_OP_COLLAPSE_SUM;          *num_operands=0; }
+      else if (!strcmp(string, "collapse-min"))
+        { op=ARITHMETIC_OP_COLLAPSE_MIN;          *num_operands=0; }
+      else if (!strcmp(string, "collapse-max"))
+        { op=ARITHMETIC_OP_COLLAPSE_MAX;          *num_operands=0; }
+      else if (!strcmp(string, "collapse-mean"))
+        { op=ARITHMETIC_OP_COLLAPSE_MEAN;         *num_operands=0; }
+      else if (!strcmp(string, "collapse-number"))
+        { op=ARITHMETIC_OP_COLLAPSE_NUMBER;       *num_operands=0; }
+      else if (!strcmp(string, "unique"))
+        { op=ARITHMETIC_OP_UNIQUE;                *num_operands=0; }
+      else
+        error(EXIT_FAILURE, 0, "the argument \"%s\" could not be "
+              "interpretted as a file name, named dataset, number, "
+              "or operator", string);
+    }
+
+  /* Return the operator code. */
+  return op;
+}
+
+
+
+
+
+static void
+arithmetic_operator_run(struct arithmeticparams *p, int operator,
+                        char *operator_string, size_t num_operands)
+{
+  size_t i;
+  unsigned int numop;
+  gal_data_t *d1=NULL, *d2=NULL, *d3=NULL;
+  int flags = ( GAL_ARITHMETIC_INPLACE | GAL_ARITHMETIC_FREE
+                | GAL_ARITHMETIC_NUMOK );
+
+  /* When `num_operands!=0', the operator is in the library. */
+  if(num_operands)
+    {
+      /* Pop the necessary number of operators. Note that the
+         operators are poped from a linked list (which is
+         last-in-first-out). So for the operators which need a
+         specific order, the first poped operand is actally the
+         last (right most, in in-fix notation) input operand.*/
+      switch(num_operands)
+        {
+        case 1:
+          d1=operands_pop(p, operator_string);
+          break;
+
+        case 2:
+          d2=operands_pop(p, operator_string);
+          d1=operands_pop(p, operator_string);
+          break;
+
+        case 3:
+          d3=operands_pop(p, operator_string);
+          d2=operands_pop(p, operator_string);
+          d1=operands_pop(p, operator_string);
+          break;
+
+        case -1:
+          /* This case is when the number of operands is itself an
+             operand. So except for sigma-clipping (that has other
+             parameters), the first popped operand must be an
+             integer number, we will use that to construct a linked
+             list of any number of operands within the single `d1'
+             pointer. */
+          numop=pop_number_of_operands(p, operator, operator_string, &d2);
+          for(i=0;i<numop;++i)
+            gal_list_data_add(&d1, operands_pop(p, operator_string));
+          break;
+
+        default:
+          error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix "
+                "the problem. `%zu' is not recognized as an operand "
+                "counter (with `%s')", __func__, PACKAGE_BUGREPORT,
+                num_operands, operator_string);
+        }
+
+      /* Run the arithmetic operation. Note that `gal_arithmetic'
+         is a variable argument function (like printf). So the
+         number of arguments it uses depend on the operator. So
+         when the operator doesn't need three operands, the extra
+         arguments will be ignored. */
+      operands_add(p, NULL, gal_arithmetic(operator, p->cp.numthreads,
+                                           flags, d1, d2, d3));
+    }
+
+  /* No need to call the arithmetic library, call the proper
+     wrappers directly. */
+  else
+    {
+      switch(operator)
+        {
+        case ARITHMETIC_OP_FILTER_MEAN:
+        case ARITHMETIC_OP_FILTER_MEDIAN:
+        case ARITHMETIC_OP_FILTER_SIGCLIP_MEAN:
+        case ARITHMETIC_OP_FILTER_SIGCLIP_MEDIAN:
+          wrapper_for_filter(p, operator_string, operator);
+          break;
+
+        case ARITHMETIC_OP_ERODE:
+        case ARITHMETIC_OP_DILATE:
+          arithmetic_erode_dilate(p, operator_string, operator);
+          break;
+
+        case ARITHMETIC_OP_CONNECTED_COMPONENTS:
+          arithmetic_connected_components(p, operator_string);
+          break;
+
+        case ARITHMETIC_OP_FILL_HOLES:
+          arithmetic_fill_holes(p, operator_string);
+          break;
+
+        case ARITHMETIC_OP_INVERT:
+          arithmetic_invert(p, operator_string);
+          break;
+
+        case ARITHMETIC_OP_INTERPOLATE_MEDIANNGB:
+          arithmetic_interpolate(p, operator_string);
+          break;
+
+        case ARITHMETIC_OP_COLLAPSE_SUM:
+        case ARITHMETIC_OP_COLLAPSE_MIN:
+        case ARITHMETIC_OP_COLLAPSE_MAX:
+        case ARITHMETIC_OP_COLLAPSE_MEAN:
+        case ARITHMETIC_OP_COLLAPSE_NUMBER:
+          arithmetic_collapse(p, operator_string, operator);
+          break;
+
+        case ARITHMETIC_OP_UNIQUE:
+          arithmetic_unique(p, operator_string, operator);
+          break;
+
+        default:
+          error(EXIT_FAILURE, 0, "%s: a bug! please contact us at "
+                "%s to fix the problem. The code %d is not "
+                "recognized for `op'", __func__, PACKAGE_BUGREPORT,
+                operator);
+        }
+    }
+}
+
+
+
+
+
 /* This function implements the reverse polish algorithm as explained
    in the Wikipedia page.
 
@@ -957,13 +1135,11 @@ arithmetic_unique(struct arithmeticparams *p, char 
*token, int operator)
 void
 reversepolish(struct arithmeticparams *p)
 {
-  int op=0, nop=0;
-  unsigned int numop, i;
+  gal_data_t *data;
+  size_t num_operands=0;
   gal_list_str_t *token;
-  gal_data_t *d1, *d2, *d3;
   char *hdu, *filename, *printnum;
-  int flags = ( GAL_ARITHMETIC_INPLACE | GAL_ARITHMETIC_FREE
-                | GAL_ARITHMETIC_NUMOK );
+  int operator=GAL_ARITHMETIC_OP_INVALID;
 
 
   /* Prepare the processing: */
@@ -979,6 +1155,7 @@ reversepolish(struct arithmeticparams *p)
          for a filename. If we have a name or number, then add it to the
          operands linked list. Otherwise, pull out two members and do the
          specified operation on them. */
+      operator=GAL_ARITHMETIC_OP_INVALID;
       if( !strncmp(OPERATOR_PREFIX_TOFILE, token->v,
                    OPERATOR_PREFIX_LENGTH_TOFILE) )
         arithmetic_tofile(p, token->v, 0);
@@ -991,280 +1168,14 @@ reversepolish(struct arithmeticparams *p)
       else if( gal_array_name_recognized(token->v)
           || operands_is_name(p, token->v) )
         operands_add(p, token->v, NULL);
-      else if( (d1=gal_data_copy_string_to_number(token->v)) )
-        operands_add(p, NULL, d1);
+      else if( (data=gal_data_copy_string_to_number(token->v)) )
+        operands_add(p, NULL, data);
+      /* Last option is an operator: the program will abort if the token
+         isn't an operator. */
       else
         {
-          /* Order is the same as in the manual. */
-          /* Simple arithmetic operators. */
-          if      (!strcmp(token->v, "+" ))
-            { op=GAL_ARITHMETIC_OP_PLUS;              nop=2;  }
-          else if (!strcmp(token->v, "-" ))
-            { op=GAL_ARITHMETIC_OP_MINUS;             nop=2;  }
-          else if (!strcmp(token->v, "x" ))
-            { op=GAL_ARITHMETIC_OP_MULTIPLY;          nop=2;  }
-          else if (!strcmp(token->v, "/" ))
-            { op=GAL_ARITHMETIC_OP_DIVIDE;            nop=2;  }
-          else if (!strcmp(token->v, "%" ))
-            { op=GAL_ARITHMETIC_OP_MODULO;            nop=2;  }
-
-          /* Mathematical Operators. */
-          else if (!strcmp(token->v, "abs"))
-            { op=GAL_ARITHMETIC_OP_ABS;               nop=1;  }
-          else if (!strcmp(token->v, "pow"))
-            { op=GAL_ARITHMETIC_OP_POW;               nop=2;  }
-          else if (!strcmp(token->v, "sqrt"))
-            { op=GAL_ARITHMETIC_OP_SQRT;              nop=1;  }
-          else if (!strcmp(token->v, "log"))
-            { op=GAL_ARITHMETIC_OP_LOG;               nop=1;  }
-          else if (!strcmp(token->v, "log10"))
-            { op=GAL_ARITHMETIC_OP_LOG10;             nop=1;  }
-
-          /* Statistical/higher-level operators. */
-          else if (!strcmp(token->v, "minvalue"))
-            { op=GAL_ARITHMETIC_OP_MINVAL;            nop=1;  }
-          else if (!strcmp(token->v, "maxvalue"))
-            { op=GAL_ARITHMETIC_OP_MAXVAL;            nop=1;  }
-          else if (!strcmp(token->v, "numbervalue"))
-            { op=GAL_ARITHMETIC_OP_NUMBERVAL;         nop=1;  }
-          else if (!strcmp(token->v, "sumvalue"))
-            { op=GAL_ARITHMETIC_OP_SUMVAL;            nop=1;  }
-          else if (!strcmp(token->v, "meanvalue"))
-            { op=GAL_ARITHMETIC_OP_MEANVAL;           nop=1;  }
-          else if (!strcmp(token->v, "stdvalue"))
-            { op=GAL_ARITHMETIC_OP_STDVAL;            nop=1;  }
-          else if (!strcmp(token->v, "medianvalue"))
-            { op=GAL_ARITHMETIC_OP_MEDIANVAL;         nop=1;  }
-          else if (!strcmp(token->v, "min"))
-            { op=GAL_ARITHMETIC_OP_MIN;               nop=-1; }
-          else if (!strcmp(token->v, "max"))
-            { op=GAL_ARITHMETIC_OP_MAX;               nop=-1; }
-          else if (!strcmp(token->v, "number"))
-            { op=GAL_ARITHMETIC_OP_NUMBER;            nop=-1; }
-          else if (!strcmp(token->v, "sum"))
-            { op=GAL_ARITHMETIC_OP_SUM;               nop=-1; }
-          else if (!strcmp(token->v, "mean"))
-            { op=GAL_ARITHMETIC_OP_MEAN;              nop=-1; }
-          else if (!strcmp(token->v, "std"))
-            { op=GAL_ARITHMETIC_OP_STD;               nop=-1; }
-          else if (!strcmp(token->v, "median"))
-            { op=GAL_ARITHMETIC_OP_MEDIAN;            nop=-1; }
-          else if (!strcmp(token->v, "sigclip-number"))
-            { op=GAL_ARITHMETIC_OP_SIGCLIP_NUMBER;    nop=-1; }
-          else if (!strcmp(token->v, "sigclip-mean"))
-            { op=GAL_ARITHMETIC_OP_SIGCLIP_MEAN;      nop=-1; }
-          else if (!strcmp(token->v, "sigclip-median"))
-            { op=GAL_ARITHMETIC_OP_SIGCLIP_MEDIAN;    nop=-1; }
-          else if (!strcmp(token->v, "sigclip-std"))
-            { op=GAL_ARITHMETIC_OP_SIGCLIP_STD;       nop=-1; }
-
-          /* Conditional operators. */
-          else if (!strcmp(token->v, "lt" ))
-            { op=GAL_ARITHMETIC_OP_LT;                nop=2;  }
-          else if (!strcmp(token->v, "le"))
-            { op=GAL_ARITHMETIC_OP_LE;                nop=2;  }
-          else if (!strcmp(token->v, "gt" ))
-            { op=GAL_ARITHMETIC_OP_GT;                nop=2;  }
-          else if (!strcmp(token->v, "ge"))
-            { op=GAL_ARITHMETIC_OP_GE;                nop=2;  }
-          else if (!strcmp(token->v, "eq"))
-            { op=GAL_ARITHMETIC_OP_EQ;                nop=2;  }
-          else if (!strcmp(token->v, "ne"))
-            { op=GAL_ARITHMETIC_OP_NE;                nop=2;  }
-          else if (!strcmp(token->v, "and"))
-            { op=GAL_ARITHMETIC_OP_AND;               nop=2;  }
-          else if (!strcmp(token->v, "or"))
-            { op=GAL_ARITHMETIC_OP_OR;                nop=2;  }
-          else if (!strcmp(token->v, "not"))
-            { op=GAL_ARITHMETIC_OP_NOT;               nop=1;  }
-          else if (!strcmp(token->v, "isblank"))
-            { op=GAL_ARITHMETIC_OP_ISBLANK;           nop=1;  }
-          else if (!strcmp(token->v, "where"))
-            { op=GAL_ARITHMETIC_OP_WHERE;             nop=3;  }
-
-          /* Bitwise operators. */
-          else if (!strcmp(token->v, "bitand"))
-            { op=GAL_ARITHMETIC_OP_BITAND;            nop=2;  }
-          else if (!strcmp(token->v, "bitor"))
-            { op=GAL_ARITHMETIC_OP_BITOR;             nop=2;  }
-          else if (!strcmp(token->v, "bitxor"))
-            { op=GAL_ARITHMETIC_OP_BITXOR;            nop=2;  }
-          else if (!strcmp(token->v, "lshift"))
-            { op=GAL_ARITHMETIC_OP_BITLSH;            nop=2;  }
-          else if (!strcmp(token->v, "rshift"))
-            { op=GAL_ARITHMETIC_OP_BITRSH;            nop=2;  }
-          else if (!strcmp(token->v, "bitnot"))
-            { op=GAL_ARITHMETIC_OP_BITNOT;            nop=1;  }
-
-          /* Type conversion. */
-          else if (!strcmp(token->v, "uint8"))
-            { op=GAL_ARITHMETIC_OP_TO_UINT8;          nop=1;  }
-          else if (!strcmp(token->v, "int8"))
-            { op=GAL_ARITHMETIC_OP_TO_INT8;           nop=1;  }
-          else if (!strcmp(token->v, "uint16"))
-            { op=GAL_ARITHMETIC_OP_TO_UINT16;         nop=1;  }
-          else if (!strcmp(token->v, "int16"))
-            { op=GAL_ARITHMETIC_OP_TO_INT16;          nop=1;  }
-          else if (!strcmp(token->v, "uint32"))
-            { op=GAL_ARITHMETIC_OP_TO_UINT32;         nop=1;  }
-          else if (!strcmp(token->v, "int32"))
-            { op=GAL_ARITHMETIC_OP_TO_INT32;          nop=1;  }
-          else if (!strcmp(token->v, "uint64"))
-            { op=GAL_ARITHMETIC_OP_TO_UINT64;         nop=1;  }
-          else if (!strcmp(token->v, "int64"))
-            { op=GAL_ARITHMETIC_OP_TO_INT64;          nop=1;  }
-          else if (!strcmp(token->v, "float32"))
-            { op=GAL_ARITHMETIC_OP_TO_FLOAT32;        nop=1;  }
-          else if (!strcmp(token->v, "float64"))
-            { op=GAL_ARITHMETIC_OP_TO_FLOAT64;        nop=1;  }
-
-          /* Library wrappers. */
-          else if (!strcmp(token->v, "filter-mean"))
-            { op=ARITHMETIC_OP_FILTER_MEAN;           nop=0;  }
-          else if (!strcmp(token->v, "filter-median"))
-            { op=ARITHMETIC_OP_FILTER_MEDIAN;         nop=0;  }
-          else if (!strcmp(token->v, "filter-sigclip-mean"))
-            { op=ARITHMETIC_OP_FILTER_SIGCLIP_MEAN;   nop=0;  }
-          else if (!strcmp(token->v, "filter-sigclip-median"))
-            { op=ARITHMETIC_OP_FILTER_SIGCLIP_MEDIAN; nop=0;  }
-          else if (!strcmp(token->v, "erode"))
-            { op=ARITHMETIC_OP_ERODE;                 nop=0;  }
-          else if (!strcmp(token->v, "dilate"))
-            { op=ARITHMETIC_OP_DILATE;                nop=0;  }
-          else if (!strcmp(token->v, "connected-components"))
-            { op=ARITHMETIC_OP_CONNECTED_COMPONENTS;  nop=0;  }
-          else if (!strcmp(token->v, "fill-holes"))
-            { op=ARITHMETIC_OP_FILL_HOLES;            nop=0;  }
-          else if (!strcmp(token->v, "invert"))
-            { op=ARITHMETIC_OP_INVERT;                nop=0;  }
-          else if (!strcmp(token->v, "interpolate-medianngb"))
-            { op=ARITHMETIC_OP_INTERPOLATE_MEDIANNGB; nop=0;  }
-          else if (!strcmp(token->v, "collapse-sum"))
-            { op=ARITHMETIC_OP_COLLAPSE_SUM;          nop=0; }
-          else if (!strcmp(token->v, "collapse-min"))
-            { op=ARITHMETIC_OP_COLLAPSE_MIN;          nop=0; }
-          else if (!strcmp(token->v, "collapse-max"))
-            { op=ARITHMETIC_OP_COLLAPSE_MAX;          nop=0; }
-          else if (!strcmp(token->v, "collapse-mean"))
-            { op=ARITHMETIC_OP_COLLAPSE_MEAN;         nop=0; }
-          else if (!strcmp(token->v, "collapse-number"))
-            { op=ARITHMETIC_OP_COLLAPSE_NUMBER;       nop=0; }
-          else if (!strcmp(token->v, "unique"))
-            { op=ARITHMETIC_OP_UNIQUE;                nop=0; }
-          else
-            error(EXIT_FAILURE, 0, "the argument \"%s\" could not be "
-                  "interpretted as a file name, named dataset, number, or "
-                  "operator", token->v);
-
-          /* Initialize all the operand pointers (they may be remaining
-             from previous operators and we don't want them to cause
-             confusion. */
-          d1 = d2 = d3 = NULL;
-
-          /* See if the arithmetic library must be called or not. */
-          if(nop)
-            {
-              /* Pop the necessary number of operators. Note that the
-                 operators are poped from a linked list (which is
-                 last-in-first-out). So for the operators which need a
-                 specific order, the first poped operand is actally the
-                 last (right most, in in-fix notation) input operand.*/
-              switch(nop)
-                {
-                case 1:
-                  d1=operands_pop(p, token->v);
-                  break;
-
-                case 2:
-                  d2=operands_pop(p, token->v);
-                  d1=operands_pop(p, token->v);
-                  break;
-
-                case 3:
-                  d3=operands_pop(p, token->v);
-                  d2=operands_pop(p, token->v);
-                  d1=operands_pop(p, token->v);
-                  break;
-
-                case -1:
-                  /* This case is when the number of operands is itself an
-                     operand. So except for sigma-clipping (that has other
-                     parameters), the first popped operand must be an
-                     integer number, we will use that to construct a linked
-                     list of any number of operands within the single `d1'
-                     pointer. */
-                  numop=pop_number_of_operands(p, op, token->v, &d2);
-                  for(i=0;i<numop;++i)
-                    gal_list_data_add(&d1, operands_pop(p, token->v));
-                  break;
-
-                default:
-                  error(EXIT_FAILURE, 0, "no operators, `%s' needs %d "
-                        "operand(s)", token->v, nop);
-                }
-
-              /* Run the arithmetic operation. Note that `gal_arithmetic'
-                 is a variable argument function (like printf). So the
-                 number of arguments it uses depend on the operator. So
-                 when the operator doesn't need three operands, the extra
-                 arguments will be ignored. */
-              operands_add(p, NULL, gal_arithmetic(op, p->cp.numthreads,
-                                                   flags, d1, d2, d3));
-            }
-
-          /* No need to call the arithmetic library, call the proper
-             wrappers directly. */
-          else
-            {
-              switch(op)
-                {
-                case ARITHMETIC_OP_FILTER_MEAN:
-                case ARITHMETIC_OP_FILTER_MEDIAN:
-                case ARITHMETIC_OP_FILTER_SIGCLIP_MEAN:
-                case ARITHMETIC_OP_FILTER_SIGCLIP_MEDIAN:
-                  wrapper_for_filter(p, token->v, op);
-                  break;
-
-                case ARITHMETIC_OP_ERODE:
-                case ARITHMETIC_OP_DILATE:
-                  arithmetic_erode_dilate(p, token->v, op);
-                  break;
-
-                case ARITHMETIC_OP_CONNECTED_COMPONENTS:
-                  arithmetic_connected_components(p, token->v);
-                  break;
-
-                case ARITHMETIC_OP_FILL_HOLES:
-                  arithmetic_fill_holes(p, token->v);
-                  break;
-
-                case ARITHMETIC_OP_INVERT:
-                  arithmetic_invert(p, token->v);
-                  break;
-
-                case ARITHMETIC_OP_INTERPOLATE_MEDIANNGB:
-                  arithmetic_interpolate(p, token->v);
-                  break;
-
-                case ARITHMETIC_OP_COLLAPSE_SUM:
-                case ARITHMETIC_OP_COLLAPSE_MIN:
-                case ARITHMETIC_OP_COLLAPSE_MAX:
-                case ARITHMETIC_OP_COLLAPSE_MEAN:
-                case ARITHMETIC_OP_COLLAPSE_NUMBER:
-                  arithmetic_collapse(p, token->v, op);
-                  break;
-
-                case ARITHMETIC_OP_UNIQUE:
-                  arithmetic_unique(p, token->v, op);
-                  break;
-
-                default:
-                  error(EXIT_FAILURE, 0, "%s: a bug! please contact us at "
-                        "%s to fix the problem. The code %d is not "
-                        "recognized for `op'", __func__, PACKAGE_BUGREPORT,
-                        op);
-                }
-            }
+          operator=arithmetic_set_operator(token->v, &num_operands);
+          arithmetic_operator_run(p, operator, token->v, num_operands);
         }
 
       /* Increment the token counter. */
@@ -1312,38 +1223,38 @@ reversepolish(struct arithmeticparams *p)
 
   /* If the final data structure has more than one element, write it as a
      FITS file. Otherwise, print it in the standard output. */
-  d1=p->operands->data;
-  if(d1->size==1)
+  data=p->operands->data;
+  if(data->size==1)
     {
       /* Make the string to print the number. */
-      printnum=gal_type_to_string(d1->array, d1->type, 0);
+      printnum=gal_type_to_string(data->array, data->type, 0);
       printf("%s\n", printnum);
 
       /* Clean up. */
       free(printnum);
-      if(d2!=d1) gal_data_free(d2);
     }
   else
     {
       /* Put a copy of the WCS structure from the reference image, it
-         will be freed while freeing d1. */
-      d1->wcs=p->refdata.wcs;
-      if(d1->ndim==1 && p->onedasimage==0)
-        gal_table_write(d1, NULL, p->cp.tableformat, p->cp.output,
+         will be freed while freeing `data'. */
+      data->wcs=p->refdata.wcs;
+      if(data->ndim==1 && p->onedasimage==0)
+        gal_table_write(data, NULL, p->cp.tableformat, p->cp.output,
                         "ARITHMETIC", 0);
       else
-        gal_fits_img_write(d1, p->cp.output, NULL, PROGRAM_NAME);
+        gal_fits_img_write(data, p->cp.output, NULL, PROGRAM_NAME);
       if(!p->cp.quiet)
         printf(" - Write (final): %s\n", p->cp.output);
     }
 
 
   /* Clean up, note that above, we copied the pointer to `refdata->wcs'
-     into `d1', so it is freed when freeing d1. */
-  gal_data_free(d1);
+     into `data', so it is freed when freeing `data'. */
+  gal_data_free(data);
   free(p->refdata.dsize);
   gal_list_data_free(p->named);
 
+
   /* Clean up. Note that the tokens were taken from the command-line
      arguments, so the string within each token linked list must not be
      freed. */
diff --git a/bin/table/Makefile.am b/bin/table/Makefile.am
index f3313a2..244830a 100644
--- a/bin/table/Makefile.am
+++ b/bin/table/Makefile.am
@@ -31,9 +31,9 @@ bin_PROGRAMS = asttable
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
 asttable_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
 
-asttable_SOURCES = main.c ui.c table.c
+asttable_SOURCES = main.c ui.c arithmetic.c table.c
 
-EXTRA_DIST = main.h authors-cite.h args.h ui.h table.h
+EXTRA_DIST = main.h authors-cite.h args.h ui.h arithmetic.h table.h
 
 
 
diff --git a/bin/table/arithmetic.c b/bin/table/arithmetic.c
new file mode 100644
index 0000000..9b74e0a
--- /dev/null
+++ b/bin/table/arithmetic.c
@@ -0,0 +1,672 @@
+/*********************************************************************
+Table - View and manipulate a FITS table structures.
+Table is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+     Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2019, Free Software Foundation, Inc.
+
+Gnuastro 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 3 of the License, or (at your
+option) any later version.
+
+Gnuastro 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 Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#include <config.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <error.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <gnuastro/wcs.h>
+
+#include <gnuastro-internal/checkset.h>
+
+#include "main.h"
+#include "arithmetic.h"
+
+
+
+
+/*********************************************************************/
+/********************       List operations      *********************/
+/*********************************************************************/
+static struct arithmetic_token *
+arithmetic_add_new_to_end(struct arithmetic_token **list)
+{
+  struct arithmetic_token *tmp, *node;
+
+  /* Allocate a new node. */
+  errno=0;
+  node=malloc(sizeof *node);
+  if(node==NULL)
+    error(EXIT_FAILURE, errno, "%s: couldn't allocate new node (%zu bytes)",
+          __func__, sizeof *node);
+
+  /* Initialize its elements. */
+  node->next=NULL;
+  node->constant=NULL;
+  node->index=GAL_BLANK_SIZE_T;
+  node->operator=GAL_ARITHMETIC_OP_INVALID;
+
+  /* If the list already has elements, go to the last node in the list and
+     add this node. */
+  if(*list)
+    {
+      for(tmp=*list;tmp->next!=NULL;tmp=tmp->next) {}
+      tmp->next=node;
+    }
+  else
+    *list=node;
+
+  /* Return a pointer to this node (to use temporarily). */
+  return node;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*********************************************************************/
+/********************       User-interface       *********************/
+/*********************************************************************/
+static char *
+arithmetic_operator_name(int operator)
+{
+  char *out=gal_arithmetic_operator_string(operator);
+
+  /* If the operator wasn't in the library, see if it was defined here. */
+  if(out==NULL)
+    switch(operator)
+      {
+      case ARITHMETIC_TABLE_OP_WCSTOIMG: out="wcstoimg"; break;
+      case ARITHMETIC_TABLE_OP_IMGTOWCS: out="imgtowcs"; break;
+      default:
+        error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix "
+              "the problem. %d is not a recognized operator code", __func__,
+              PACKAGE_BUGREPORT, operator);
+      }
+
+  return out;
+}
+
+
+
+
+
+static void
+arithmetic_init_wcs(struct tableparams *p, char *operator)
+{
+  /* If a WCS hasn't been read yet, read it.*/
+  if(p->wcs==NULL)
+    {
+      /* A small sanity check. */
+      if(p->wcsfile==NULL || p->wcshdu==NULL)
+        error(EXIT_FAILURE, 0, "`--wcsfile' and `--wcshdu' are necessary "
+              "for the `%s' operator", operator);
+
+      /* Read the WCS. */
+      p->wcs=gal_wcs_read(p->wcsfile, p->wcshdu, 0, 0, &p->nwcs);
+      if(p->wcs==NULL)
+        error(EXIT_FAILURE, 0, "%s (hdu: %s): no WCS could be read by "
+              "WCSLIB", p->wcsfile, p->wcshdu);
+    }
+}
+
+
+
+
+
+/* Set the operator code from the given string. */
+static int
+arithmetic_set_operator(struct tableparams *p, char *string,
+                        size_t *num_operands)
+{
+  int op=gal_arithmetic_set_operator(string, num_operands);;
+
+  /* Set the operator and number of operands. */
+  if( op==GAL_ARITHMETIC_OP_INVALID )
+    {
+      if(      !strncmp(string, "wcstoimg", 8))
+        { op=ARITHMETIC_TABLE_OP_WCSTOIMG;   *num_operands=0; }
+      else if (!strncmp(string, "imgtowcs", 8))
+        { op=ARITHMETIC_TABLE_OP_IMGTOWCS;   *num_operands=0; }
+      else
+        { op=GAL_ARITHMETIC_OP_INVALID; *num_operands=GAL_BLANK_INT; }
+    }
+
+  /* Operator specific operations. */
+  switch(op)
+    {
+    case ARITHMETIC_TABLE_OP_WCSTOIMG:
+    case ARITHMETIC_TABLE_OP_IMGTOWCS:
+      arithmetic_init_wcs(p, string);
+      break;
+    }
+
+  /* Return the operator. */
+  return op;
+}
+
+
+
+
+
+/* Initialize each column from an arithmetic operation. */
+void
+arithmetic_init(struct tableparams *p, struct arithmetic_token **arith,
+                gal_list_str_t **toread, size_t *totcalled, char *expression)
+{
+  void *num;
+  size_t one=1;
+  uint8_t ntype;
+  char *str, *delimiter=" \t";
+  struct arithmetic_token *node=NULL;
+  char *token=NULL, *lasttoken, *saveptr;
+
+  /* Parse all the given tokens. */
+  token=strtok_r(expression, delimiter, &saveptr);
+  while(token!=NULL)
+    {
+      /* Allocate and initialize this arithmetic token. */
+      lasttoken=token;
+      node=arithmetic_add_new_to_end(arith);
+
+      /* See if the token is an operator, if not check other cases.  */
+      node->operator=arithmetic_set_operator(p, token, &node->num_operands);
+      if(node->operator==GAL_ARITHMETIC_OP_INVALID)
+        {
+          /* Token is a single number.*/
+          if( (num=gal_type_string_to_number(token, &ntype)) )
+            node->constant=gal_data_alloc(num, ntype, 1, &one, NULL, 0, -1,
+                                          NULL, NULL, NULL);
+
+          /* Token is a column operand (column number or name). */
+          else
+            {
+              str = ( (token[0]=='c' && isdigit(token[1]))
+                      ? &token[1]   /* Column number (starting with `c'). */
+                      : token );    /* Column name, just add it.          */
+              gal_list_str_add(toread, str, 1);
+              node->index=*totcalled;
+              *totcalled+=1;
+            }
+        }
+
+      /* Go to the next token. */
+      token=strtok_r(NULL, delimiter, &saveptr);
+    }
+
+  /* A small sanity check: the last added token must be an operator. */
+  if( node==NULL || node->operator==GAL_ARITHMETIC_OP_INVALID )
+    error(EXIT_FAILURE, 0, "last token in arithmetic column (`%s') is not a "
+          "recognized operator", lasttoken);
+}
+
+
+
+
+
+/* Set the final index of each package of columns (possibly containing
+   processing columns that will change in number and contents).  */
+void
+arithmetic_indexs_final(struct tableparams *p, size_t *colmatch)
+{
+  size_t startind;
+  size_t i, numcols;
+  struct column_pack *tmp;
+  struct arithmetic_token *atmp;
+
+  /* Set the column array that will allow removal of some read columns
+     (where operations will be done). */
+  p->colarray=gal_list_data_to_array_ptr(p->table, &p->numcolarray);
+
+  /* go over each package of columns. */
+  for(tmp=p->outcols;tmp!=NULL;tmp=tmp->next)
+    {
+      /* If we are on an arithmetic operation. */
+      if(tmp->tokens)
+        {
+          for(atmp=tmp->tokens;atmp!=NULL;atmp=atmp->next)
+            if(atmp->index!=GAL_BLANK_SIZE_T)
+              {
+                /* Small sanity check. */
+                if(colmatch[i]!=1)
+                  error(EXIT_FAILURE, 0, "arithmetic operands can only "
+                        "correspond to a single column");
+
+                /* Update the index in the full list of read columns. */
+                numcols=0; for(i=0;i<atmp->index;++i) numcols+=colmatch[i];
+                atmp->index=numcols;
+              }
+        }
+      /* A simple column. */
+      else
+        {
+          /* See where the starting column for this patch of simple columns
+             is. */
+          startind=0;
+          for(i=0;i<tmp->start;++i) startind+=colmatch[i];
+
+          /* How many of the read columns are associated with the this
+             patch of columns. */
+          numcols=0;
+          for(i=0;i<tmp->numsimple;++i) numcols+=colmatch[tmp->start+i];
+
+          /* Update the values. */
+          tmp->start=startind;
+          tmp->numsimple=numcols;
+        }
+
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*********************************************************************/
+/********************       Low-level tools      *********************/
+/*********************************************************************/
+static gal_data_t *
+arithmetic_stack_pop(gal_data_t **stack, int operator)
+{
+  gal_data_t *out=*stack;
+
+  /* Update the stack. */
+  if(*stack)
+    *stack=(*stack)->next;
+  else
+    error(EXIT_FAILURE, 0, "not enough operands for `%s'",
+          arithmetic_operator_name(operator));
+
+  /* Remove the `next' element to break from the stack and return. */
+  out->next=NULL;
+  return out;
+}
+
+
+
+
+
+/* Set the converted column metadata. */
+static void
+arithmetic_update_metadata(gal_data_t *col, char *name, char *unit,
+                           char *comment)
+{
+  if(col)
+    {
+      if(col->name)    free(col->name);
+      if(col->unit)    free(col->unit);
+      if(col->comment) free(col->comment);
+      gal_checkset_allocate_copy(name, &col->name);
+      gal_checkset_allocate_copy(unit, &col->unit);
+      gal_checkset_allocate_copy(comment, &col->comment);
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*********************************************************************/
+/********************          Operations        *********************/
+/*********************************************************************/
+static void
+arithmetic_wcs(struct tableparams *p, gal_data_t **stack, int operator)
+{
+  gal_data_t *tmp;
+  struct wcsprm *wcs=p->wcs;
+  size_t i, ndim=p->wcs->naxis;
+  gal_data_t *coord[3]={NULL, NULL, NULL};
+
+  /* Pop all the necessary datasets and make sure they are
+     double-precision. NOTE: the top dataset on the stack is the
+     highest-dimensional dataset. */
+  for(i=0;i<ndim;++i)
+    {
+      tmp=arithmetic_stack_pop(stack, operator);
+      tmp=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_FLOAT64);
+      coord[ndim-i-1]=tmp;
+    }
+
+  /* Define the list of coordinates. */
+  if(coord[1]) coord[0]->next=coord[1];
+  if(coord[2]) coord[1]->next=coord[2];
+
+
+  /* Final preparations. */
+  if(operator==ARITHMETIC_TABLE_OP_WCSTOIMG)
+    {
+      /* Do the conversion. */
+      gal_wcs_world_to_img(coord[0], wcs, 1);
+
+      /* For image coordinates, we don't need much precision. */
+      for(i=0;i<ndim;++i)
+        coord[i]=gal_data_copy_to_new_type_free(coord[i], GAL_TYPE_FLOAT32);
+
+      /* Set the names, units and comments for each dataset. */
+      arithmetic_update_metadata(coord[0],"X","pixel","Converted from WCS");
+      arithmetic_update_metadata(coord[1],"Y","pixel","Converted from WCS");
+      arithmetic_update_metadata(coord[2],"Z","pixel","Converted from WCS");
+    }
+  else
+    {
+      gal_wcs_img_to_world(coord[0], wcs, 1);
+      arithmetic_update_metadata(coord[0], wcs->ctype[0], wcs->cunit[0],
+                                 "Converted from pixel coordinates");
+      arithmetic_update_metadata(coord[1], coord[1]?wcs->ctype[1]:NULL,
+                                 coord[1]?wcs->cunit[1]:NULL,
+                                 "Converted from pixel coordinates");
+      arithmetic_update_metadata(coord[2], coord[2]?wcs->ctype[2]:NULL,
+                                 coord[2]?wcs->cunit[2]:NULL,
+                                 "Converted from pixel coordinates");
+    }
+
+  /* Reverse the column orders and put them on the stack. */
+  for(i=0;i<ndim;++i)
+    {
+      coord[i]->next=NULL;
+      gal_list_data_add(stack, coord[i]);
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*********************************************************************/
+/********************          Operations        *********************/
+/*********************************************************************/
+static void
+arithmetic_placeholder_name(gal_data_t *col)
+{
+  static size_t counter=0;
+
+  /* Increment counter next time this function is called. */
+  ++counter;
+
+  /* Free any possibly existing metadata. */
+  if(col->name)    free(col->name);
+  if(col->unit)    free(col->unit);
+  if(col->comment) free(col->comment);
+
+  /* Set the new meta-data. */
+  errno=0;
+  if( asprintf(&col->name, "ARITH_%zu", counter)==-1 )
+    error(EXIT_FAILURE, errno, "%s: asprintf error for name", __func__);
+  if( asprintf(&col->unit, "arith_unit_%zu", counter)==-1)
+    error(EXIT_FAILURE, errno, "%s: asprintf error for unit", __func__);
+  if( asprintf(&col->comment, "Column from arithmetic operation %zu",
+               counter)==-1 )
+    error(EXIT_FAILURE, errno, "%s: asprintf error for comment", __func__);
+}
+
+
+
+
+
+static void
+arithmetic_operator_run(struct tableparams *p, gal_data_t **stack,
+                        int operator, size_t num_operands)
+{
+  gal_data_t *d1=NULL, *d2=NULL, *d3=NULL;
+  int flags = ( GAL_ARITHMETIC_INPLACE | GAL_ARITHMETIC_FREE
+                | GAL_ARITHMETIC_NUMOK );
+
+  /* When `num_operands!=0', the operator is in the library. */
+  if(num_operands)
+    {
+      /* Pop the necessary number of operators. Note that the
+         operators are poped from a linked list (which is
+         last-in-first-out). So for the operators which need a
+         specific order, the first poped operand is actally the
+         last (right most, in in-fix notation) input operand.*/
+      switch(num_operands)
+        {
+        case 1:
+          d1=arithmetic_stack_pop(stack, operator);
+          break;
+
+        case 2:
+          d2=arithmetic_stack_pop(stack, operator);
+          d1=arithmetic_stack_pop(stack, operator);
+          break;
+
+        case 3:
+          d3=arithmetic_stack_pop(stack, operator);
+          d2=arithmetic_stack_pop(stack, operator);
+          d1=arithmetic_stack_pop(stack, operator);
+          break;
+
+        case -1:
+          error(EXIT_FAILURE, 0, "operators with a variable number of "
+                "operands are not yet implemented. Please contact us at "
+                "%s to include them", PACKAGE_BUGREPORT);
+          break;
+
+        default:
+          error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix "
+                "the problem. `%zu' is not recognized as an operand "
+                "counter (with `%s')", __func__, PACKAGE_BUGREPORT,
+                num_operands, arithmetic_operator_name(operator));
+        }
+
+      /* Run the arithmetic operation. Note that `gal_arithmetic' is a
+         variable argument function (like printf). So the number of
+         arguments it uses depend on the operator. In other words, when the
+         operator doesn't need three operands, the extra arguments will be
+         ignored. */
+      gal_list_data_add(stack, gal_arithmetic(operator, p->cp.numthreads,
+                                              flags, d1, d2, d3));
+
+      /* Reset the meta-data for the element that was just put on the
+         stack. */
+      arithmetic_placeholder_name(*stack);
+    }
+
+  /* This operator is specific to this program (Table). */
+  else
+    {
+      switch(operator)
+        {
+        case ARITHMETIC_TABLE_OP_WCSTOIMG:
+        case ARITHMETIC_TABLE_OP_IMGTOWCS:
+          arithmetic_wcs(p, stack, operator);
+          break;
+
+        default:
+          error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to "
+                "fix the problem. The operator code %d is not recognized",
+                __func__, PACKAGE_BUGREPORT, operator);
+        }
+    }
+}
+
+
+
+
+
+/* Apply reverse polish mechanism for this column. */
+static void
+arithmetic_reverse_polish(struct tableparams *p, struct column_pack *outpack)
+{
+  gal_data_t *single, *stack=NULL;
+  struct arithmetic_token *token;
+
+  /* Go through all the tokens given to this element. */
+  for(token=outpack->tokens;token!=NULL;token=token->next)
+    {
+      /* We are on an operator. */
+      if(token->operator!=GAL_ARITHMETIC_OP_INVALID)
+        arithmetic_operator_run(p, &stack, token->operator,
+                                token->num_operands);
+
+      /* Constant number: just put it ontop of the stack. */
+      else if(token->constant)
+        {
+          gal_list_data_add(&stack, token->constant);
+          token->constant=NULL;
+        }
+
+      /* A column from the table. */
+      else if(token->index!=GAL_BLANK_SIZE_T)
+        gal_list_data_add(&stack, p->colarray[token->index]);
+
+      /* Un-recognized situation. */
+      else
+        error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to "
+              "fix the problem. The token can't be identified as an "
+              "operator, constant or column", __func__, PACKAGE_BUGREPORT);
+    }
+
+  /* Put everything that remains in the stack (reversed) into the final
+     table. Just note that `gal_list_data_add' behaves differently for
+     lists, so we'll add have to manually set the `next' element to NULL
+     before adding the column to the final table. */
+  gal_list_data_reverse(&stack);
+  while(stack!=NULL)
+    {
+      /* Keep the top element in `single' and move `stack' to the next
+         element. */
+      single=stack;
+      stack=stack->next;
+
+      /* A small sanity check. */
+      if(single->size==1 && p->table && single->size!=p->table->size)
+        error(EXIT_FAILURE, 0, "the arithmetic operation resulted in a "
+              "a single value, but other columns have also been requested "
+              "which have more elements/rows");
+
+      /* Set `single->next' to NULL so it isn't treated as a list and
+         remove all metadata */
+      single->next=NULL;
+      gal_list_data_add(&p->table, single);
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*********************************************************************/
+/********************         High-level         *********************/
+/*********************************************************************/
+void
+arithmetic_operate(struct tableparams *p)
+{
+  size_t i;
+  struct column_pack *outpack;
+
+
+  /* From now on, we will be looking for columns from the index in
+     `colarray', so to keep things clean, we'll set all the `next' elements
+     to NULL. */
+  for(i=0;i<p->numcolarray;++i) p->colarray[i]->next=NULL;
+
+  /* We'll also reset the output table pointer, to fill it in as we
+     progress. */
+  p->table=NULL;
+
+  /* Go over each package of columns. */
+  for(outpack=p->outcols;outpack!=NULL;outpack=outpack->next)
+    {
+      if(outpack->tokens)
+        arithmetic_reverse_polish(p, outpack);
+      else
+        {
+          for(i=0;i<outpack->numsimple;++i)
+            gal_list_data_add(&p->table, p->colarray[outpack->start+i]);
+        }
+    }
+
+  /* Reverse the final output to be in the proper order. Note that all the
+     column contents have either been moved into the new table, or have
+     already been freed. */
+  gal_list_data_reverse(&p->table);
+}
diff --git a/bin/table/arithmetic.h b/bin/table/arithmetic.h
new file mode 100644
index 0000000..dc75d61
--- /dev/null
+++ b/bin/table/arithmetic.h
@@ -0,0 +1,60 @@
+/*********************************************************************
+Table - View and manipulate a FITS table structures.
+Table is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+     Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2019, Free Software Foundation, Inc.
+
+Gnuastro 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 3 of the License, or (at your
+option) any later version.
+
+Gnuastro 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 Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#ifndef ARITHMETIC_H
+#define ARITHMETIC_H
+
+
+#include <gnuastro/arithmetic.h>
+
+
+/* Basic constants. */
+#define ARITHMETIC_CALL "arith "
+#define ARITHMETIC_CALL_LENGTH strlen(ARITHMETIC_CALL)
+
+
+/* Operators used for arithmetic on columns. */
+enum arithmetic_operators
+{
+ ARITHMETIC_TABLE_OP_WCSTOIMG = GAL_ARITHMETIC_OP_LAST_CODE,
+ ARITHMETIC_TABLE_OP_IMGTOWCS,
+};
+
+
+
+
+
+
+
+/* Functions */
+void
+arithmetic_init(struct tableparams *p, struct arithmetic_token **arith,
+                gal_list_str_t **toread, size_t *totcalled, char *expression);
+
+void
+arithmetic_indexs_final(struct tableparams *p, size_t *colmatch);
+
+void
+arithmetic_operate(struct tableparams *p);
+
+
+#endif
diff --git a/bin/table/main.h b/bin/table/main.h
index 8c8750d..44694f6 100644
--- a/bin/table/main.h
+++ b/bin/table/main.h
@@ -36,13 +36,31 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 
-
+/* Basic structure. */
 struct list_range
 {
   gal_data_t           *v;
   struct list_range *next;
 };
 
+struct arithmetic_token
+{
+  /* First layer elements. */
+  int            operator;  /* OPERATOR: Code of operator.                */
+  size_t     num_operands;  /* OPERATOR: Number of required operands.     */
+  size_t            index;  /* OPERAND: Index in requested columns.       */
+  gal_data_t    *constant;  /* OPERAND: a constant/single number.         */
+  struct arithmetic_token *next;  /* Pointer to next token.               */
+};
+
+struct column_pack
+{
+  size_t                    start; /* Starting ind. in requested columns. */
+  size_t                numsimple; /* Number of simple columns.           */
+  struct arithmetic_token *tokens; /* Arithmetic tokens to use.           */
+  struct column_pack        *next; /* Next output column.                 */
+};
+
 
 
 
@@ -65,6 +83,7 @@ struct tableparams
   size_t                 tail;  /* Output only the no. of bottom rows.  */
 
   /* Internal. */
+  struct column_pack *outcols;  /* Output column packages.              */
   gal_data_t           *table;  /* Linked list of output table columns. */
   struct wcsprm          *wcs;  /* WCS structure for conversion.        */
   int                    nwcs;  /* Number of WCS structures.            */
@@ -75,6 +94,8 @@ struct tableparams
   uint8_t          *freerange;  /* If the range column should be freed. */
   uint8_t              sortin;  /* If the sort column is in the output. */
   time_t              rawtime;  /* Starting time of the program.        */
+  gal_data_t       **colarray;  /* Array of columns, with arithmetic.   */
+  size_t          numcolarray;  /* Number of elements in `colarray'.    */
 
   /* For arithmetic operators. */
   gal_list_str_t  *wcstoimg_p;  /* Pointer to the node.                 */
diff --git a/bin/table/table.c b/bin/table/table.c
index b2914e4..97bd560 100644
--- a/bin/table/table.c
+++ b/bin/table/table.c
@@ -43,7 +43,9 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <gnuastro-internal/checkset.h>
 
 #include "main.h"
+
 #include "ui.h"
+#include "arithmetic.h"
 
 
 
@@ -324,134 +326,6 @@ table_head_tail(struct tableparams *p)
 
 
 
-/* Set the converted column metadata. */
-static void
-table_unit_update_metadata(gal_data_t *col, char *name, char *unit,
-                           char *comment)
-{
-  if(col)
-    {
-      if(col->name)    free(col->name);
-      if(col->unit)    free(col->unit);
-      if(col->comment) free(col->comment);
-      gal_checkset_allocate_copy(name, &col->name);
-      gal_checkset_allocate_copy(unit, &col->unit);
-      gal_checkset_allocate_copy(comment, &col->comment);
-    }
-}
-
-
-
-
-
-static void
-table_unit_conversion(struct tableparams *p, int w0i1)
-{
-  int isfirstcol;
-  struct wcsprm *wcs=p->wcs;
-  gal_data_t *tmp, *before, *after=NULL, *t1=NULL, *t2=NULL, *t3=NULL;
-  size_t i, j, ndim=wcs->naxis, startcol = w0i1 ? p->imgtowcs : p->wcstoimg;
-
-  /* Go to the column that we need to convert. */
-  i=0;
-  before=p->table;
-  for(tmp=p->table; tmp!=NULL; tmp=tmp->next)
-    {
-      if( i++ == startcol )
-        {
-          j=1;
-          for(after=tmp->next;j<ndim;after=after->next)
-            ++j;
-          break;
-        }
-      before=tmp;
-    }
-  isfirstcol=before==p->table;
-
-  /* Make sure the types are double-precision floating point. NOTE that
-     since we are freeing afterwards, the second column needs to be
-     read first.*/
-  if(ndim==3)
-    t3=gal_data_copy_to_new_type_free(tmp->next->next, GAL_TYPE_FLOAT64);
-  if(ndim>=2)
-    t2=gal_data_copy_to_new_type_free(tmp->next, GAL_TYPE_FLOAT64);
-  t1=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_FLOAT64);
-
-  /* Define the list of coordinates and do the conversion. */
-  t1->next=t2;
-  if(t2) t2->next=t3;
-  if(t3) t3->next=NULL;
-  if(w0i1) gal_wcs_img_to_world(t1, p->wcs, 1);
-  else     gal_wcs_world_to_img(t1, p->wcs, 1);
-
-  /* In image mode, double-precision floating point is too much. */
-  if(w0i1==0)
-    {
-      /* Convert them to 32-bit floating point. */
-      t1=gal_data_copy_to_new_type_free(t1, GAL_TYPE_FLOAT32);
-      if(t2)
-        {
-          t2=gal_data_copy_to_new_type_free(t2, GAL_TYPE_FLOAT32);
-          t1->next=t2;
-        }
-      if(t3)
-        {
-          t3=gal_data_copy_to_new_type_free(t3, GAL_TYPE_FLOAT32);
-          t2->next=t3;
-        }
-
-      /* Set the names, units and comments for each dataset. */
-      table_unit_update_metadata(t1, "X", "pixel", "Converted from WCS");
-      table_unit_update_metadata(t2, "Y", "pixel", "Converted from WCS");
-      table_unit_update_metadata(t3, "Z", "pixel", "Converted from WCS");
-    }
-  else
-    {
-      table_unit_update_metadata(t1, wcs->ctype[0], wcs->cunit[0],
-                                 "Converted from pixel coordinates");
-      table_unit_update_metadata(t2, t2?wcs->ctype[1]:NULL,
-                                 t2?wcs->cunit[1]:NULL,
-                                 "Converted from pixel coordinates");
-      table_unit_update_metadata(t3, t3?wcs->ctype[2]:NULL,
-                                 t3?wcs->cunit[2]:NULL,
-                                 "Converted from pixel coordinates");
-    }
-
-  /* Put them back into the output table. */
-  switch(ndim)
-    {
-    case 1: t1->next=after; break;
-    case 2: t2->next=after; break;
-    case 3: t3->next=after; break;
-    default:
-      error(EXIT_FAILURE, 0, "a bug! Please contact us at `%s' to fix the "
-            "problem. This program is not set for `%zu' dimensions",
-            PACKAGE_BUGREPORT, ndim);
-    }
-
-  /* If the desired columns were at the start, we'll need to fix it. */
-  if(isfirstcol) p->table=t1; else before->next=t1;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 /**************************************************************/
 /***************       Top function         *******************/
 /**************************************************************/
@@ -468,9 +342,9 @@ table(struct tableparams *p)
   if(p->head!=GAL_BLANK_SIZE_T || p->tail!=GAL_BLANK_SIZE_T)
     table_head_tail(p);
 
-  /* If unit conversion is requested, do it. */
-  if(p->wcstoimg!=GAL_BLANK_SIZE_T) table_unit_conversion(p, 0);
-  if(p->imgtowcs!=GAL_BLANK_SIZE_T) table_unit_conversion(p, 1);
+  /* If any operations are needed, do them. */
+  if(p->outcols)
+    arithmetic_operate(p);
 
   /* Write the output. */
   gal_table_write(p->table, NULL, p->cp.tableformat, p->cp.output,
diff --git a/bin/table/ui.c b/bin/table/ui.c
index 02674ac..2259c5b 100644
--- a/bin/table/ui.c
+++ b/bin/table/ui.c
@@ -42,6 +42,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include "main.h"
 
 #include "ui.h"
+#include "arithmetic.h"
 #include "authors-cite.h"
 
 
@@ -119,8 +120,6 @@ ui_initialize_options(struct tableparams *p,
   /* Program-specific initialization. */
   p->head                = GAL_BLANK_SIZE_T;
   p->tail                = GAL_BLANK_SIZE_T;
-  p->wcstoimg            = GAL_BLANK_SIZE_T;
-  p->imgtowcs            = GAL_BLANK_SIZE_T;
 
   /* Modify common options. */
   for(i=0; !gal_options_is_last(&cp->coptions[i]); ++i)
@@ -385,6 +384,81 @@ ui_list_range_free(struct list_range *list, int freevalue)
 
 
 
+
+
+/**************************************************************/
+/***************      Packaged columns      *******************/
+/**************************************************************/
+/* Return the last outcols element. */
+static struct column_pack *
+ui_outcols_last(struct column_pack *list)
+{
+  if(list)
+    {
+      while(list->next!=NULL) list=list->next;
+      return list;
+    }
+  else return NULL;
+}
+
+
+
+
+
+/* Allocate a clean `out_columns' structure and put it at the top of the
+   list. */
+static struct column_pack *
+ui_outcols_add_new_to_end(struct column_pack **list)
+{
+  struct column_pack *last, *node;
+
+  /* Allocate a new node. */
+  errno=0;
+  node=malloc(sizeof *node);
+  if(node==NULL)
+    error(EXIT_FAILURE, errno, "%s: couldn't allocate new node (%zu bytes)",
+          __func__, sizeof *node);
+
+  /* Initialize its elements. */
+  node->next=NULL;
+  node->numsimple=0;
+  node->tokens=NULL;
+  node->start=GAL_BLANK_SIZE_T;
+
+  /* If the list already has elements, go to the last node in the list and
+     add this node. */
+  if(*list)
+    {
+      last=ui_outcols_last(*list);
+      last->next=node;
+    }
+  else
+    *list=node;
+
+  /* Return a pointer to this node (to use temporarily). */
+  return node;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 /**************************************************************/
 /***************       Preparations         *******************/
 /**************************************************************/
@@ -435,106 +509,18 @@ ui_print_info_exit(struct tableparams *p)
 
 
 
-static int
-ui_columns_wcs(struct tableparams *p, char *operator, size_t counter)
-{
-  char *opname;
-  gal_list_str_t **ptr;
-  int fromwcs=!strncmp("wcstoimg", operator, 8);
-
-  /* Set the basic properties. */
-  opname = fromwcs ? "wcstoimg"       : "imgtowcs";
-  ptr    = fromwcs ? (&p->wcstoimg_p) : (&p->imgtowcs_p);
-
-  /* If a WCS hasn't been read yet, read it.*/
-  if(p->wcs==NULL)
-    {
-      /* A small sanity check. */
-      if(p->wcsfile==NULL || p->wcshdu==NULL)
-        error(EXIT_FAILURE, 0, "`--wcsfile' and `--wcshdu' are necessary "
-              "for the `%s' conversion", opname);
-
-      /* Read the WCS. */
-      p->wcs=gal_wcs_read(p->wcsfile, p->wcshdu, 0, 0, &p->nwcs);
-      if(p->wcs==NULL)
-        error(EXIT_FAILURE, 0, "%s (hdu: %s): no WCS could be read by "
-              "WCSLIB", p->wcsfile, p->wcshdu);
-
-      /* Make sure it doesn't have more than 3 axises. */
-      if(p->wcs->naxis>3)
-        error(EXIT_FAILURE, 0, "%s (hdu %s): the WCS has %d dimensions. "
-              "So far, only up to three dimensions are supported",
-              p->wcsfile, p->wcshdu, p->wcs->naxis);
-    }
-
-  /* Some basic sanity checks. */
-  if(counter!=p->wcs->naxis)
-    error(EXIT_FAILURE, 0, "%s (%s): WCS has %d dimensions but only %zu "
-          "columns were given to the `%s' operator", p->wcsfile, p->wcshdu,
-          p->wcs->naxis, counter, opname);
-  if(*ptr)
-    error(EXIT_FAILURE, 0, "`%s' can only be called once.", opname);
-
-  /* Return the type of operator. */
-  return fromwcs;
-}
-
-
-
-
-
-/* When arithmetic operations are requested. */
-static void
-ui_columns_arith(struct tableparams *p, char *expression,
-                 gal_list_str_t **new)
-{
-  int fromwcs;
-  size_t counter=0;
-  char *token=NULL, *saveptr;
-  char *str, *delimiter=" \t";
-
-  token=strtok_r(expression, delimiter, &saveptr);
-  while(token!=NULL)
-    {
-      /* Check the token value and take the proper action. */
-      if(!strncmp("wcstoimg", token, 8) || !strncmp("imgtowcs", token, 8))
-        {
-          /* Set the WCS-conversion parameters, then break out of the loop
-             (so far, no more operators are defined). */
-          fromwcs=ui_columns_wcs(p, token, counter);
-          if(fromwcs) p->wcstoimg_p = (*new)->next;
-          else        p->imgtowcs_p = (*new)->next;
-          break;
-        }
-      else
-        {
-          str = ( (token[0]=='c' && isdigit(token[1]))
-                  ? &token[1]
-                  : token );
-          gal_list_str_add(new, str, 1);
-          ++counter;
-        }
-
-      /* Go to the next token. */
-      token=strtok_r(NULL, delimiter, &saveptr);
-    }
-}
-
-
-
-
-
 /* The columns can be given as comma-separated values to one option or
    multiple calls to the column option. Here, we'll check if the input list
    has comma-separated values. If they do then the list will be updated to
    be fully separate. */
 static void
-ui_columns_prepare(struct tableparams *p, size_t *wcstoimg, size_t *imgtowcs)
+ui_columns_prepare(struct tableparams *p)
 {
   char **strarr;
-  size_t i, ncols;
   gal_data_t *strs;
-  gal_list_str_t *tmp, *new=NULL;
+  size_t i, totcalled=0;
+  struct column_pack *node, *last;
+  gal_list_str_t *tmp, *toread=NULL;
 
   /* Go over the whole original list (where each node may have more than
      one value separated by a comma. */
@@ -548,13 +534,62 @@ ui_columns_prepare(struct tableparams *p, size_t 
*wcstoimg, size_t *imgtowcs)
       /* Go over all the given colum names/numbers. */
       for(i=0;i<strs->size;++i)
         {
-          if(!strncmp(strarr[i], "arith ", 6))
+          /* See if this is an arithmetic column to be processed, or the
+             contents should just be printed. */
+          if(!strncmp(strarr[i], ARITHMETIC_CALL, ARITHMETIC_CALL_LENGTH))
             {
-              ui_columns_arith(p, strarr[i]+6, &new);
+              /* If this is the first arithmetic operation and the user has
+                 already asked for some columns, we'll need to put all
+                 previously requested simply-printed columns into an
+                 `outcols' structure, then add this arithmetic operation's
+                 `outcols'. */
+              if(p->outcols==NULL && toread)
+                {
+                  /* Allocate an empty structure and set the necessary
+                     pointers. */
+                  node=ui_outcols_add_new_to_end(&p->outcols);
+                  node->start=0;
+                  node->numsimple=gal_list_str_number(toread);
+                  totcalled=node->numsimple;
+                }
+
+              /* Add a new column pack, then read all the tokens (while
+                 specifying which columns it needs). */
+              node=ui_outcols_add_new_to_end(&p->outcols);
+              arithmetic_init(p, &node->tokens, &toread, &totcalled,
+                              strarr[i]+ARITHMETIC_CALL_LENGTH);
               free(strarr[i]);
             }
+          /* This is a simple column (no change in values). */
           else
-            gal_list_str_add(&new, strarr[i], 0);
+            {
+              /* Add this column to the list of columns to read. */
+              gal_list_str_add(&toread, strarr[i], 0);
+
+              /* See if we have packaged the output columns. */
+              if(p->outcols)
+                {
+                  /* If the previous column package was an arithmetic
+                     operation, allocate a new node. */
+                  last=ui_outcols_last(p->outcols);
+                  if(last->tokens)
+                    {
+                      node=ui_outcols_add_new_to_end(&p->outcols);
+                      node->start=totcalled;
+                      node->numsimple=1;
+                    }
+
+                  /* The previous package of columns are simple (we don't
+                     need to change their value), so we can just increment
+                     the number of columns there and don't need to allocate
+                     a new one. */
+                  else
+                    last->numsimple+=1;
+                }
+
+              /* Increment the total number of called columns. */
+              totcalled+=1;
+            }
 
           /* The pointer allocated string is either being used (and later
              freed) else, or has already been freed. So its necessary to
@@ -566,26 +601,39 @@ ui_columns_prepare(struct tableparams *p, size_t 
*wcstoimg, size_t *imgtowcs)
       gal_data_free(strs);
     }
 
-  /* If conversion is necessary, set the final column number. */
-  i=0;
-  if(p->wcstoimg_p || p->imgtowcs_p)
+  /* For a check
+  if(p->outcols)
     {
-      ncols=gal_list_str_number(new);
-      for(tmp=new;tmp!=NULL;tmp=tmp->next)
+      struct column_pack *tmp;
+      struct arithmetic_token *atmp;
+      for(tmp=p->outcols;tmp!=NULL;tmp=tmp->next)
         {
-          /* Note that we are going to reverse the list after this, so we
-             need to reset the counter. */
-          if(p->wcstoimg_p==tmp) *wcstoimg=ncols - i - (p->wcs->naxis-1);
-          if(p->imgtowcs_p==tmp) *imgtowcs=ncols - i - (p->wcs->naxis-1);
-          ++i;
+          if(tmp->tokens)
+            for(atmp=tmp->tokens;atmp!=NULL;atmp=atmp->next)
+              {
+                printf("Arithmetic: ");
+                if(atmp->constant) printf("Constant number\n");
+                else if(atmp->index) printf("Called column: %zu\n",
+                                            atmp->index);
+                else if(atmp->operator!=ARITHMETIC_TABLE_OP_INVALID)
+                  printf("Operator: %d\n", atmp->operator);
+                else
+                  error(EXIT_FAILURE, 0, "%s: UNKNOWN SITUATION!",
+                        __func__);
+              }
+          else
+            printf("Simple: start: %zu, num: %zu\n", tmp->start,
+                   tmp->numsimple);
         }
     }
+  */
 
-  /* Delete the old list, then reverse the new list, and put it into
+
+  /* Delete the old list, then reverse the `toread' list, and put it into
      `p->columns'. */
   gal_list_str_free(p->columns, 1);
-  gal_list_str_reverse(&new);
-  p->columns=new;
+  gal_list_str_reverse(&toread);
+  p->columns=toread;
 }
 
 
@@ -884,12 +932,11 @@ ui_check_range_sort_after(struct tableparams *p, size_t 
nrange,
 static void
 ui_preparations(struct tableparams *p)
 {
+  size_t *colmatch;
   gal_list_str_t *lines;
-  size_t i, ncolnames, *colmatch;
   size_t nrange=0, origoutncols=0;
   struct gal_options_common_params *cp=&p->cp;
   size_t sortindout=GAL_BLANK_SIZE_T, *rangeindout=NULL;
-  size_t wcstoimg=GAL_BLANK_SIZE_T, imgtowcs=GAL_BLANK_SIZE_T;
 
   /* If there were no columns specified or the user has asked for
      information on the columns, we want the full set of columns. */
@@ -898,7 +945,7 @@ ui_preparations(struct tableparams *p)
 
 
   /* Prepare the column names. */
-  ui_columns_prepare(p, &wcstoimg, &imgtowcs);
+  ui_columns_prepare(p);
 
 
   /* If the input is from stdin, save it as `lines'. */
@@ -911,13 +958,13 @@ ui_preparations(struct tableparams *p)
                                &rangeindout);
 
 
-  /* If any conversions must be done, we need to know how many matches
-     there were for each column. */
-  ncolnames=gal_list_str_number(p->columns);
-  colmatch = ( (wcstoimg!=GAL_BLANK_SIZE_T || imgtowcs!=GAL_BLANK_SIZE_T)
-               ? gal_pointer_allocate(GAL_TYPE_SIZE_T, ncolnames, 1,
+  /* If we have any arithmetic operations, we need to make sure how many
+     columns match every given column name. */
+  colmatch = ( p->outcols
+               ? gal_pointer_allocate(GAL_TYPE_SIZE_T,
+                                      gal_list_str_number(p->columns), 1,
                                       __func__, "colmatch")
-               : NULL );
+               : NULL);
 
 
   /* Read the necessary columns. */
@@ -928,13 +975,6 @@ ui_preparations(struct tableparams *p)
   gal_list_str_free(lines, 1);
 
 
-  /* If we have a unit conversion, find the proper column to use. */
-  if(wcstoimg!=GAL_BLANK_SIZE_T)
-    { p->wcstoimg=0; for(i=0;i<wcstoimg;++i) p->wcstoimg += colmatch[i]; }
-  if(imgtowcs!=GAL_BLANK_SIZE_T)
-    { p->imgtowcs=0; for(i=0;i<imgtowcs;++i) p->imgtowcs += colmatch[i]; }
-
-
   /* If the range and sort options are requested, keep them as separate
      datasets. */
   if(p->range || p->sort)
@@ -949,6 +989,11 @@ ui_preparations(struct tableparams *p)
           "non-blank lines)", p->filename);
 
 
+  /* Set the final indexs. */
+  if(p->outcols)
+    arithmetic_indexs_final(p, colmatch);
+
+
   /* Now that the data columns are ready, we can free the string linked
      list. */
   gal_list_str_free(p->columns, 1);
@@ -1079,4 +1124,5 @@ ui_free_report(struct tableparams *p)
   free(p->cp.hdu);
   free(p->cp.output);
   gal_list_data_free(p->table);
+  if(p->colarray) free(p->colarray);
 }
diff --git a/configure.ac b/configure.ac
index adccad8..f1a99c3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -193,6 +193,10 @@ AC_CHECK_SIZEOF([long])
 AC_SUBST(SIZEOF_LONG, [$ac_cv_sizeof_long])
 AC_DEFINE_UNQUOTED([GAL_CONFIG_SIZEOF_LONG], [$ac_cv_sizeof_long],
                    [On 32bit will be 4, on 64 bit, will be 8])
+AC_CHECK_SIZEOF([int])
+AC_SUBST(SIZEOF_INT, [$ac_cv_sizeof_int])
+AC_DEFINE_UNQUOTED([GAL_CONFIG_SIZEOF_INT], [$ac_cv_sizeof_int],
+                   [It may be 16bit or 32bit])
 
 
 
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 2995b9f..49b4033 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -377,6 +377,7 @@ ConvertType
 
 Table
 
+* Column arithmetic::           How to do operations on table columns.
 * Invoking asttable::           Options and arguments to Table.
 
 Data manipulation
@@ -11606,10 +11607,108 @@ higher-level processing, see the examples in 
@ref{Invoking asttable} for
 some simple examples.
 
 @menu
+* Column arithmetic::           How to do operations on table columns.
 * Invoking asttable::           Options and arguments to Table.
 @end menu
 
address@hidden Invoking asttable,  , Table, Table
address@hidden Column arithmetic, Invoking asttable, Table, Table
address@hidden Column arithmetic
+
+After reading the requested columns from the input table, you can also do
+operations/arithmetic on the columns and save the resulting values as new
+column(s) in the output table (possibly in between other requested
+columns). To enable column arithmetic, the first 6 characters of the value
+to @option{--column} (@code{-c}) should be the arithmetic activation word
address@hidden }' (note the space character in the end, after
address@hidden').
+
+After the activation word, you can use the reverse polish notation to
+identify the operators and their operands, see @ref{Reverse polish
+notation}. Just note that white-space characters are used between the
+tokens of the arithmetic expression and that they are meaningful to the
+command-line environment. Therefore the whole expression (including the
+activation word) has to be quoted on the command-line or in a shell script
+(see the examples below).
+
+To identify a column you can directly use its name, or specify its number
+(counting from one, see @ref{Selecting table columns}). When you are giving
+a column number, it is necessary to prefix it with a @code{c} (otherwise it
+is not distinguisable from a constant number to use in the arithmetic
+operation).
+
+For example with the command below, the first two columns of
address@hidden will be printed along with a third column that is the
+result of multiplying the first column with @mymath{10^{10}} (for example
+to convert wavelength from Meters to Angstroms). Note how without the
address@hidden', it is not possible to distinguish between @key{1} as a
+column-counter, or as a constant number to use in the arithmetic operation.
+
address@hidden
+$ asttable table.fits -c1,2 -c"arith c1 1e10 x"
address@hidden example
+
+Alternatively, if the columns have meta-data and the first two are
+respectively called @code{AWAV} and @code{SPECTRUM}, the command above is
+equivalent to the command below. Note that the @key{c} is no longer
+necessary in this scenario.
+
address@hidden
+$ asttable table.fits -cAWAV,SPECTRUM -c"arith AWAV 1e10 x"
address@hidden example
+
+Comparison of the two commands above clearly shows why it is recommended to
+use column names instead of numbers. When the columns have clear names, the
+command/script actually becomes much more readable, describing the intent
+of the operation. It is also independent of the low-level table structure:
+for the second command, the position of the @code{AWAV} and @code{SPECTRUM}
+columns in @file{table.fits} is irrelevant.
+
+Finally, since the arithmetic expressions are a value to @option{--column},
+it doesn't necessarily have to be a separate option, so the commands above
+are also identical to the command below (note that this only has one
address@hidden option). Just be very careful with the quoting!
+
address@hidden
+$ asttable table.fits -cAWAV,SPECTRUM,"arith AWAV 1e10 x"
address@hidden example
+
+Almost all the arithmetic operators of @ref{Arithmetic operators} are also
+supported for column arithmetic in Table. In particular, the few that are
+not present in the Gnuastro library aren't yet supported. For a list of the
+Gnuastro library arithmetic operators, please see the macros starting with
address@hidden and ending with the operator name in
address@hidden on datasets}. Besides the operators in @ref{Arithmetic
+operators}, several operators are only available in Table to use on table
+columns.
+
address@hidden WCS: World Coordinate System
address@hidden World Coordinate System (WCS)
address@hidden @code
address@hidden wcstoimg
+Convert the given WCS positions to image/dataset coordinates based on the
+number of dimensions in the WCS structure of @option{--wcshdu}
+extension/HDU in @option{--wcsfile}. It will output the same number of
+columns. The first poppoed operand is the last FITS dimension.
+
+For example the two commands below (which have the same output) will
+produce 5 columns. The first three columns are the input table's ID, RA and
+Dec columns. The fourth and fifth columns will be the pixel positions in
address@hidden that correspond to each RA and Dec.
+
address@hidden
+$ asttable table.fits -cID,RA,DEC,"arith RA DEC wcstoimg" \
+           --wcsfile=image.fits
+$ asttable table.fits -cID,RA -cDEC \
+           -c"arith RA DEC wcstoimg" --wcsfile=image.fits
address@hidden example
+
address@hidden imgtowcs
+Similar to @code{wcstoimg}, except that image/dataset coordinates are
+converted to WCS coordinates.
address@hidden table
+
+
address@hidden Invoking asttable,  , Column arithmetic, Table
 @subsection Invoking Table
 
 Table will read/write, select, convert, or show the information of the
@@ -11643,26 +11742,19 @@ $ asttable bintab.fits -cRA,DEC,/^MAG_/ --sort=Z_PHOT
 ## redshift between 2 and 3.
 $ asttable bintab.fits -cRA,DEC,/^MAG_/ --range=Z_PHOT,2:3
 
-## Similar to above, but writes the columns to a file (with metadata)
-## instead of the command-line.
-$ asttable bintab.fits -cRA,DEC,/^MAG_/ --output=out.txt
-
-## Only print the 2nd column, and the third column multiplied by 5:
-$ asttable bintab.fits -c2,5 | awk '@{print $1, address@hidden'
-
 ## Only print rows with a value in the 10th column above 100000:
-$ asttable bintab.fits | awk '$10>10e5 @address@hidden'
+$ asttable bintab.fits --range=10,10e5,inf
 
-## Sort the output columns by the third column, save output:
-$ asttable bintab.fits | 'sort -nk3 > output.txt
+## Only print the 2nd column, and the third column multiplied by 5,
+## Save the resulting two columns in `table.txt'
+$ asttable bintab.fits -c2,"arith c2 5 x" -otable.fits
 
-## Subtract the first column from the second in `cat.txt' and keep the
-## third and fourth columns. Feed the columns to Table to write as a
-## FITS table.
-$ awk '!/^#/@{print $2-$1, $3, address@hidden' cat.txt | asttable -ocat.fits
+## Sort the output columns by the third column, save output:
+$ asttable bintab.fits --sort=3 -ooutput.txt
 
-## Convert a plain text table to a binary FITS table:
-$ asttable plaintext.txt --output=table.fits --tabletype=fits-binary
+## Subtract the first column from the second in `cat.txt' (can also
+## be a FITS table) and keep the third and fourth columns.
+$ awk cat.txt -c"arith c2 c1 -",3,4 -ocat.fits
 @end example
 
 Table's input dataset can be given either as a file or from Standard input
@@ -11715,70 +11807,25 @@ last command with all the previously typed columns 
present, delete
 @cindex GNU AWK
 @item -c STR/INT
 @itemx --column=STR/INT
-Specify the columns to read, see @ref{Selecting table columns} for a
-thorough explanation on how the value to this option is interpreted. There
-are two ways to specify multiple columns: 1) multiple calls to this option,
-2) using a comma between each column specifier in one call to this
-option. These different solutions may be mixed in one call to Table: for
-example, @option{-cRA,DEC -cMAG}, or @option{-cRA -cDEC -cMAG} are both
-equivalent to @option{-cRA -cDEC -cMAG}. The order of the output columns
-will be the same order given to the option or in the configuration files
-(see @ref{Configuration file precedence}).
+Set the output columns either by specifying the column number, or name. For
+more on selecting columns, see @ref{Selecting table columns}. If a value of
+this option starts with address@hidden }', this option will do the requested
+operations/arithmetic on the specified columns and output the result in
+that place (among other requested columns). For more on column arithmetic
+see @ref{Column arithmetic}.
+
+To ask for multiple columns this option can be used in two way: 1) multiple
+calls to this option, 2) using a comma between each column specifier in one
+call to this option. These different solutions may be mixed in one call to
+Table: for example, @option{-cRA,DEC -cMAG}, or @option{-cRA -cDEC -cMAG}
+are both equivalent to @option{-cRA -cDEC -cMAG}. The order of the output
+columns will be the same order given to the option or in the configuration
+files (see @ref{Configuration file precedence}).
 
 This option is not mandatory, if no specific columns are requested, all the
 input table columns are output. When this option is called multiple times,
 it is possible to output one column more than once.
 
-This option can also modify the input values based on certain
-operations. To use this feature, the first 6 characters of the value should
-be address@hidden }' (note the space character in the end, after
address@hidden'). Afterwards, you can use the reverse polish notation to
-identify the operators and their operands, see @ref{Reverse polish
-notation}. Just note that currently the range of operators available here
-is less than @ref{Arithmetic} and listed below. Also note that the
-delimiter between the tokens (value to @option{--column}) is a white-space
-character. Therefore the whole value has to be quoted (see the examples
-below).
-
-To identify a column you can directly use its name, or specify its number
-(counting from one, see @ref{Selecting table columns}). When its a number,
-is necessary to prefix it with a @code{c} (otherwise it is not
-distinguisable from a constant number to use in the processing). For
-example the two commands below (which have the same output) will produce 5
-columns. The first three columns are the input table's ID, RA and Dec
-columns. The fourth and fifth columns will be the pixel positions in
address@hidden that correspond to each RA and Dec.
-
address@hidden
-$ asttable table.fits -cID,RA,DEC,"arith RA DEC wcstoimg" \
-           --wcsfile=image.fits
-$ asttable table.fits -cID,RA -cDEC \
-           -c"arith RA DEC wcstoimg" --wcsfile=image.fits
address@hidden example
-
-If we assume the @code{RA} and @code{DEC} columns are the 2nd and 3rd
-columns, then the commands above can also be written like this:
-
address@hidden
-$ asttable table.fits -cID,2 -c3 \
-           -c"arith c2 c3 wcstoimg" --wcsfile=image.fits
address@hidden example
-
-The current list of operands are:
address@hidden WCS: World Coordinate System
address@hidden World Coordinate System (WCS)
address@hidden @code
address@hidden wcstoimg
-Convert the given WCS positions to image/dataset coordinates based on the
-number of dimensions in the WCS structure of @option{--wcshdu}
-extension/HDU in @option{--wcsfile}. It will output the same number of
-columns. The first poppoed operand is the last FITS dimension.
-
address@hidden imgtowcs
-Similar to @code{wcstoimg}, except that image/dataset coordinates are
-converted to WCS coordinates.
address@hidden table
-
 @item -w STR
 @itemx --wcsfile=STR
 FITS file that contains the WCS to be used in the @code{wcstoimg} and
@@ -12630,14 +12677,15 @@ The most common notation for arithmetic operations is 
the
 @url{https://en.wikipedia.org/wiki/Infix_notation, infix notation} where
 the operator goes between the two operands, for example @mymath{4+5}. While
 the infix notation is the preferred way in most programming languages,
-currently Arithmetic does not use it since it will require parenthesis
-which can complicate the implementation of the code. In the near future we
-do plan to adopt this
+currently the Gnuastro's program (in particular Arithmetic and Table, when
+doing column arithmetic) do not use it. This is because it will require
+parenthesis which can complicate the implementation of the code. In the
+near future we do plan to also allow this
 address@hidden@url{https://savannah.gnu.org/task/index.php?13867}}, but
-for the time being (due to time constraints on the developers), Arithmetic
-uses the post-fix or
+for the time being (due to time constraints on the developers), arithmetic
+operations can only be done in the post-fix notation (also known as
 @url{https://en.wikipedia.org/wiki/Reverse_Polish_notation, reverse polish
-notation}. The Wikipedia article provides some excellent explanation on
+notation}). The Wikipedia article provides some excellent explanation on
 this notation but here we will give a short summary here for
 self-sufficiency.
 
@@ -12645,22 +12693,24 @@ In the post-fix notation, the operator is placed 
after the operands, as we
 will see below this removes the need to define parenthesis for most
 ordinary operators. For example, instead of writing @command{5+6}, we write
 @command{5 6 +}. To easily understand how this notation works, you can
-think of each operand as a node in a first-in-first-out stack. Every time
-an operator is confronted, it pops the number of operands it needs from the
-top of the stack (so they don't exist in the stack any more), does its
-operation and pushes the result back on top of the stack. So if you want
-the average of 5 and 6, you would write: @command{5 6 + 2 /}. The
-operations that are done are:
+think of each operand as a node in a ``last-in-first-out'' stack. Every
+time an operator is confronted, the operator pops the number of operands it
+needs from the top of the stack (so they don't exist in the stack any
+more), does its operation and pushes the result back on top of the
+stack. So if you want the average of 5 and 6, you would write: @command{5 6
++ 2 /}. The operations that are done are:
 
 @enumerate
 @item
address@hidden is an operand, so it is pushed to the top of the stack.
address@hidden is an operand, so it is pushed to the top of the stack (which
+is initially empty).
 @item
 @command{6} is an operand, so it is pushed to the top of the stack.
 @item
address@hidden is a binary operator, so pull the top two elements of the stack
-and perform addition on them (the order is @mymath{5+6} in the example
-above). The result is @command{11}, push it on top of the stack.
address@hidden is a @emph{binary} operator, so it will pop the top two
+elements of the stack out of it, and perform addition on them (the order is
address@hidden in the example above). The result is @command{11} which is
+pushed to the top of the stack.
 @item
 @command{2} is an operand so push it onto the top of the stack.
 @item
@@ -12669,14 +12719,17 @@ the stack (top-most is @command{2}, then 
@command{11}) and divide the
 second one by the first.
 @end enumerate
 
-In the Arithmetic program, the operands can be FITS images or numbers. As
-you can see, very complicated procedures can be created without the need
-for parenthesis or worrying about precedence. Even functions which take an
-arbitrary number of arguments can be defined in this notation. This is a
-very powerful notation and is used in languages like Postscript
+In the Arithmetic program, the operands can be FITS images or numbers (see
address@hidden astarithmetic}). In Table's column arithmetic, they can be
+any column or a number (see @ref{Column arithmetic}).
+
+With this notation, very complicated procedures can be created without the
+need for parenthesis or worrying about precedence. Even functions which
+take an arbitrary number of arguments can be defined in this notation. This
+is a very powerful notation and is used in languages like Postscript
 @footnote{See the EPS and PDF part of @ref{Recognized file formats} for a
-little more on the Postscript language.}  (the programming language in
-Postscript and compiled into PDF files) uses this notation.
+little more on the Postscript language.} which produces PDF files when
+compiled.
 
 
 
@@ -24696,6 +24749,16 @@ Blank value for an unsigned, 64-bit integer.
 Blank value for a signed, 64-bit integer.
 @end deffn
 
address@hidden {Global integer}  GAL_BLANK_INT
+Blank value for @code{int} type (@code{int16_t} or @code{int32_t} depending
+on the system.
address@hidden deffn
+
address@hidden {Global integer}  GAL_BLANK_UINT
+Blank value for @code{int} type (@code{int16_t} or @code{int32_t} depending
+on the system.
address@hidden deffn
+
 @deffn {Global integer}  GAL_BLANK_LONG
 Blank value for @code{long} type (@code{int32_t} or @code{int64_t} in
 32-bit or 64-bit systems).
@@ -25631,6 +25694,10 @@ pointer.
 Return the number of nodes in @code{list}.
 @end deftypefun
 
address@hidden size_t gal_list_str_last (gal_list_str_t @code{*list})
+Return a pointer to the last node in @code{list}.
address@hidden deftypefun
+
 @deftypefun void gal_list_str_print (gal_list_str_t @code{*list})
 Print the strings within each node of @code{*list} on the standard output
 in the same order that they are stored. Each string is printed on one
@@ -25707,6 +25774,10 @@ also change @code{list} to point to the next node in 
the list. If
 Return the number of nodes in @code{list}.
 @end deftypefun
 
address@hidden size_t gal_list_i32_last (gal_list_i32_t @code{*list})
+Return a pointer to the last node in @code{list}.
address@hidden deftypefun
+
 @deftypefun void gal_list_i32_print (gal_list_i32_t @code{*list})
 Print the integers within each node of @code{*list} on the standard output
 in the same order that they are stored. Each integer is printed on one
@@ -25808,6 +25879,10 @@ also change @code{list} to point to the next node in 
the list. If
 Return the number of nodes in @code{list}.
 @end deftypefun
 
address@hidden size_t gal_list_sizet_last (gal_list_sizet_t @code{*list})
+Return a pointer to the last node in @code{list}.
address@hidden deftypefun
+
 @deftypefun void gal_list_sizet_print (gal_list_sizet_t @code{*list})
 Print the values within each node of @code{*list} on the standard output in
 the same order that they are stored. Each integer is printed on one
@@ -25893,6 +25968,10 @@ also change @code{list} to point to the next node in 
the list. If
 Return the number of nodes in @code{list}.
 @end deftypefun
 
address@hidden size_t gal_list_f32_last (gal_list_f32_t @code{*list})
+Return a pointer to the last node in @code{list}.
address@hidden deftypefun
+
 @deftypefun void gal_list_f32_print (gal_list_f32_t @code{*list})
 Print the values within each node of @code{*list} on the standard output in
 the same order that they are stored. Each floating point number is printed
@@ -25981,6 +26060,10 @@ also change @code{list} to point to the next node in 
the list. If
 Return the number of nodes in @code{list}.
 @end deftypefun
 
address@hidden size_t gal_list_f64_last (gal_list_f64_t @code{*list})
+Return a pointer to the last node in @code{list}.
address@hidden deftypefun
+
 @deftypefun void gal_list_f64_print (gal_list_f64_t @code{*list})
 Print the values within each node of @code{*list} on the standard output in
 the same order that they are stored. Each floating point number is printed
@@ -26075,6 +26158,10 @@ also change @code{list} to point to the next node in 
the list. If
 Return the number of nodes in @code{list}.
 @end deftypefun
 
address@hidden size_t gal_list_void_last (gal_list_void_t @code{*list})
+Return a pointer to the last node in @code{list}.
address@hidden deftypefun
+
 @deftypefun void gal_list_void_reverse (gal_list_void_t @code{**list})
 Reverse the order of the list such that the top node in the list before
 calling this function becomes the bottom node after it.
@@ -26260,10 +26347,21 @@ Reverse the order of the list such that the top node 
in the list before
 calling this function becomes the bottom node after it.
 @end deftypefun
 
address@hidden {gal_data_t **} gal_list_data_to_array_ptr (gal_data_t 
@code{*list}, size_t @code{*num})
+Allocate and return an array of @code{gal_data_t *} pointers with the same
+number of elements as the nodes in @code{list}. The pointers will be put in
+the same order that the list is parsed. Hence the N-th element in the array
+will point to the same dataset that the N-th node in the list points to.
address@hidden deftypefun
+
 @deftypefun size_t gal_list_data_number (gal_data_t @code{*list})
 Return the number of nodes in @code{list}.
 @end deftypefun
 
address@hidden size_t gal_list_data_last (gal_data_t @code{*list})
+Return a pointer to the last node in @code{list}.
address@hidden deftypefun
+
 @deftypefun void gal_list_data_free (gal_data_t @code{*list})
 Free all the datasets in @code{list} along with all the allocated spaces in
 each.
@@ -28098,6 +28196,25 @@ necessary arguments to @code{gal_arithmetic}) are 
described above under
 each operator.
 @end deftypefun
 
address@hidden int gal_arithmetic_set_operator (char @code{*string}, size_t 
@code{*num_operands})
+Return the operator macro/code that corresponds to @code{string}. The
+number of operands that it needs are written into the space that
address@hidden points to. If the string couldn't be interpretted as
+an operator, this function will return @code{GAL_ARITHMETIC_OP_INVALID}.
+
+This function will check @code{string} with the fixed human-readable names
+(using @code{strcmp}) for the operators and return the two numbers. Note
+that @code{string} must only contain the single operator name and nothing
+else (not even any extra white space).
address@hidden deftypefun
+
address@hidden {char *} gal_arithmetic_operator_string (int @code{operator})
+Return the human-readable standard string that corresponds to the given
+operator. For example when the input is @code{GAL_ARITHMETIC_OP_PLUS} or
address@hidden, the strings @code{+} or @code{mean} will be
+returned.
address@hidden deftypefun
+
 @node Tessellation library, Bounding box, Arithmetic on datasets, Gnuastro 
library
 @subsection Tessellation library (@file{tile.h})
 
diff --git a/lib/arithmetic.c b/lib/arithmetic.c
index 9250588..0bd8cb8 100644
--- a/lib/arithmetic.c
+++ b/lib/arithmetic.c
@@ -25,6 +25,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <errno.h>
 #include <error.h>
 #include <stdio.h>
+#include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
 
@@ -1556,6 +1557,144 @@ arithmetic_binary_function_flt(int operator, int flags, 
gal_data_t *l,
 /**********************************************************************/
 /****************         High-level functions        *****************/
 /**********************************************************************/
+/* Order is the same as in the manual. */
+int
+gal_arithmetic_set_operator(char *string, size_t *num_operands)
+{
+  int op;
+
+  /* Simple arithmetic operators. */
+  if      (!strcmp(string, "+" ))
+    { op=GAL_ARITHMETIC_OP_PLUS;              *num_operands=2;  }
+  else if (!strcmp(string, "-" ))
+    { op=GAL_ARITHMETIC_OP_MINUS;             *num_operands=2;  }
+  else if (!strcmp(string, "x" ))
+    { op=GAL_ARITHMETIC_OP_MULTIPLY;          *num_operands=2;  }
+  else if (!strcmp(string, "/" ))
+    { op=GAL_ARITHMETIC_OP_DIVIDE;            *num_operands=2;  }
+  else if (!strcmp(string, "%" ))
+    { op=GAL_ARITHMETIC_OP_MODULO;            *num_operands=2;  }
+
+  /* Mathematical Operators. */
+  else if (!strcmp(string, "abs"))
+    { op=GAL_ARITHMETIC_OP_ABS;               *num_operands=1;  }
+  else if (!strcmp(string, "pow"))
+    { op=GAL_ARITHMETIC_OP_POW;               *num_operands=2;  }
+  else if (!strcmp(string, "sqrt"))
+    { op=GAL_ARITHMETIC_OP_SQRT;              *num_operands=1;  }
+  else if (!strcmp(string, "log"))
+    { op=GAL_ARITHMETIC_OP_LOG;               *num_operands=1;  }
+  else if (!strcmp(string, "log10"))
+    { op=GAL_ARITHMETIC_OP_LOG10;             *num_operands=1;  }
+
+  /* Statistical/higher-level operators. */
+  else if (!strcmp(string, "minvalue"))
+    { op=GAL_ARITHMETIC_OP_MINVAL;            *num_operands=1;  }
+  else if (!strcmp(string, "maxvalue"))
+    { op=GAL_ARITHMETIC_OP_MAXVAL;            *num_operands=1;  }
+  else if (!strcmp(string, "numbervalue"))
+    { op=GAL_ARITHMETIC_OP_NUMBERVAL;         *num_operands=1;  }
+  else if (!strcmp(string, "sumvalue"))
+    { op=GAL_ARITHMETIC_OP_SUMVAL;            *num_operands=1;  }
+  else if (!strcmp(string, "meanvalue"))
+    { op=GAL_ARITHMETIC_OP_MEANVAL;           *num_operands=1;  }
+  else if (!strcmp(string, "stdvalue"))
+    { op=GAL_ARITHMETIC_OP_STDVAL;            *num_operands=1;  }
+  else if (!strcmp(string, "medianvalue"))
+    { op=GAL_ARITHMETIC_OP_MEDIANVAL;         *num_operands=1;  }
+  else if (!strcmp(string, "min"))
+    { op=GAL_ARITHMETIC_OP_MIN;               *num_operands=-1; }
+  else if (!strcmp(string, "max"))
+    { op=GAL_ARITHMETIC_OP_MAX;               *num_operands=-1; }
+  else if (!strcmp(string, "number"))
+    { op=GAL_ARITHMETIC_OP_NUMBER;            *num_operands=-1; }
+  else if (!strcmp(string, "sum"))
+    { op=GAL_ARITHMETIC_OP_SUM;               *num_operands=-1; }
+  else if (!strcmp(string, "mean"))
+    { op=GAL_ARITHMETIC_OP_MEAN;              *num_operands=-1; }
+  else if (!strcmp(string, "std"))
+    { op=GAL_ARITHMETIC_OP_STD;               *num_operands=-1; }
+  else if (!strcmp(string, "median"))
+    { op=GAL_ARITHMETIC_OP_MEDIAN;            *num_operands=-1; }
+  else if (!strcmp(string, "sigclip-number"))
+    { op=GAL_ARITHMETIC_OP_SIGCLIP_NUMBER;    *num_operands=-1; }
+  else if (!strcmp(string, "sigclip-mean"))
+    { op=GAL_ARITHMETIC_OP_SIGCLIP_MEAN;      *num_operands=-1; }
+  else if (!strcmp(string, "sigclip-median"))
+    { op=GAL_ARITHMETIC_OP_SIGCLIP_MEDIAN;    *num_operands=-1; }
+  else if (!strcmp(string, "sigclip-std"))
+    { op=GAL_ARITHMETIC_OP_SIGCLIP_STD;       *num_operands=-1; }
+
+  /* Conditional operators. */
+  else if (!strcmp(string, "lt" ))
+    { op=GAL_ARITHMETIC_OP_LT;                *num_operands=2;  }
+  else if (!strcmp(string, "le"))
+    { op=GAL_ARITHMETIC_OP_LE;                *num_operands=2;  }
+  else if (!strcmp(string, "gt" ))
+    { op=GAL_ARITHMETIC_OP_GT;                *num_operands=2;  }
+  else if (!strcmp(string, "ge"))
+    { op=GAL_ARITHMETIC_OP_GE;                *num_operands=2;  }
+  else if (!strcmp(string, "eq"))
+    { op=GAL_ARITHMETIC_OP_EQ;                *num_operands=2;  }
+  else if (!strcmp(string, "ne"))
+    { op=GAL_ARITHMETIC_OP_NE;                *num_operands=2;  }
+  else if (!strcmp(string, "and"))
+    { op=GAL_ARITHMETIC_OP_AND;               *num_operands=2;  }
+  else if (!strcmp(string, "or"))
+    { op=GAL_ARITHMETIC_OP_OR;                *num_operands=2;  }
+  else if (!strcmp(string, "not"))
+    { op=GAL_ARITHMETIC_OP_NOT;               *num_operands=1;  }
+  else if (!strcmp(string, "isblank"))
+    { op=GAL_ARITHMETIC_OP_ISBLANK;           *num_operands=1;  }
+  else if (!strcmp(string, "where"))
+    { op=GAL_ARITHMETIC_OP_WHERE;             *num_operands=3;  }
+
+  /* Bitwise operators. */
+  else if (!strcmp(string, "bitand"))
+    { op=GAL_ARITHMETIC_OP_BITAND;            *num_operands=2;  }
+  else if (!strcmp(string, "bitor"))
+    { op=GAL_ARITHMETIC_OP_BITOR;             *num_operands=2;  }
+  else if (!strcmp(string, "bitxor"))
+    { op=GAL_ARITHMETIC_OP_BITXOR;            *num_operands=2;  }
+  else if (!strcmp(string, "lshift"))
+    { op=GAL_ARITHMETIC_OP_BITLSH;            *num_operands=2;  }
+  else if (!strcmp(string, "rshift"))
+    { op=GAL_ARITHMETIC_OP_BITRSH;            *num_operands=2;  }
+  else if (!strcmp(string, "bitnot"))
+    { op=GAL_ARITHMETIC_OP_BITNOT;            *num_operands=1;  }
+
+  /* Type conversion. */
+  else if (!strcmp(string, "uint8"))
+    { op=GAL_ARITHMETIC_OP_TO_UINT8;          *num_operands=1;  }
+  else if (!strcmp(string, "int8"))
+    { op=GAL_ARITHMETIC_OP_TO_INT8;           *num_operands=1;  }
+  else if (!strcmp(string, "uint16"))
+    { op=GAL_ARITHMETIC_OP_TO_UINT16;         *num_operands=1;  }
+  else if (!strcmp(string, "int16"))
+    { op=GAL_ARITHMETIC_OP_TO_INT16;          *num_operands=1;  }
+  else if (!strcmp(string, "uint32"))
+    { op=GAL_ARITHMETIC_OP_TO_UINT32;         *num_operands=1;  }
+  else if (!strcmp(string, "int32"))
+    { op=GAL_ARITHMETIC_OP_TO_INT32;          *num_operands=1;  }
+  else if (!strcmp(string, "uint64"))
+    { op=GAL_ARITHMETIC_OP_TO_UINT64;         *num_operands=1;  }
+  else if (!strcmp(string, "int64"))
+    { op=GAL_ARITHMETIC_OP_TO_INT64;          *num_operands=1;  }
+  else if (!strcmp(string, "float32"))
+    { op=GAL_ARITHMETIC_OP_TO_FLOAT32;        *num_operands=1;  }
+  else if (!strcmp(string, "float64"))
+    { op=GAL_ARITHMETIC_OP_TO_FLOAT64;        *num_operands=1;  }
+
+  /* Operator not defined. */
+  else
+    { op=GAL_ARITHMETIC_OP_INVALID; *num_operands=GAL_BLANK_INT; }
+  return op;
+}
+
+
+
+
+
 char *
 gal_arithmetic_operator_string(int operator)
 {
@@ -1623,14 +1762,8 @@ gal_arithmetic_operator_string(int operator)
     case GAL_ARITHMETIC_OP_TO_FLOAT32:      return "float32";
     case GAL_ARITHMETIC_OP_TO_FLOAT64:      return "float64";
 
-    default:
-      error(EXIT_FAILURE, 0, "%s: operator code %d not recognized",
-            __func__, operator);
+    default:                                return NULL;
     }
-
-  error(EXIT_FAILURE, 0, "%s: a bug! Please contact us to fix the problem. "
-        "Control has reached the end of this function. This should not have "
-        "happened", __func__);
   return NULL;
 }
 
diff --git a/lib/gnuastro/arithmetic.h b/lib/gnuastro/arithmetic.h
index a1922c8..ce529ff 100644
--- a/lib/gnuastro/arithmetic.h
+++ b/lib/gnuastro/arithmetic.h
@@ -140,7 +140,11 @@ enum gal_arithmetic_operators
   GAL_ARITHMETIC_OP_LAST_CODE,    /* Last code of the library operands.    */
 };
 
+char *
+gal_arithmetic_operator_string(int operator);
 
+int
+gal_arithmetic_set_operator(char *string, size_t *num_operands);
 
 gal_data_t *
 gal_arithmetic(int operator, size_t numthreads, int flags, ...);
diff --git a/lib/gnuastro/blank.h b/lib/gnuastro/blank.h
index 2e2490d..0bb67da 100644
--- a/lib/gnuastro/blank.h
+++ b/lib/gnuastro/blank.h
@@ -89,6 +89,14 @@ __BEGIN_C_DECLS  /* From C++ preparations */
 #define GAL_BLANK_ULONG GAL_BLANK_UINT64
 #endif
 
+#if GAL_CONFIG_SIZEOF_INT == 4
+#define GAL_BLANK_INT  GAL_BLANK_INT32
+#define GAL_BLANK_UINT GAL_BLANK_UINT32
+#elif GAL_CONFIG_SIZEOF_INT == 2
+#define GAL_BLANK_INT  GAL_BLANK_INT16
+#define GAL_BLANK_UINT GAL_BLANK_UINT16
+#endif
+
 
 /* Functions. */
 void
diff --git a/lib/gnuastro/list.h b/lib/gnuastro/list.h
index e0f790e..9a164c9 100644
--- a/lib/gnuastro/list.h
+++ b/lib/gnuastro/list.h
@@ -68,6 +68,9 @@ gal_list_str_pop(gal_list_str_t **list);
 size_t
 gal_list_str_number(gal_list_str_t *list);
 
+gal_list_str_t *
+gal_list_str_last(gal_list_str_t *list);
+
 void
 gal_list_str_print(gal_list_str_t *list);
 
@@ -99,6 +102,9 @@ gal_list_i32_pop(gal_list_i32_t **list);
 size_t
 gal_list_i32_number(gal_list_i32_t *list);
 
+gal_list_i32_t *
+gal_list_i32_last(gal_list_i32_t *list);
+
 void
 gal_list_i32_print(gal_list_i32_t *list);
 
@@ -133,6 +139,9 @@ gal_list_sizet_pop(gal_list_sizet_t **list);
 size_t
 gal_list_sizet_number(gal_list_sizet_t *list);
 
+gal_list_sizet_t *
+gal_list_sizet_last(gal_list_sizet_t *list);
+
 void
 gal_list_sizet_print(gal_list_sizet_t *list);
 
@@ -167,6 +176,9 @@ gal_list_f32_pop(gal_list_f32_t **list);
 size_t
 gal_list_f32_number(gal_list_f32_t *list);
 
+gal_list_f32_t *
+gal_list_f32_last(gal_list_f32_t *list);
+
 void
 gal_list_f32_reverse(gal_list_f32_t **list);
 
@@ -201,6 +213,9 @@ gal_list_f64_pop(gal_list_f64_t **list);
 size_t
 gal_list_f64_number(gal_list_f64_t *list);
 
+gal_list_f64_t *
+gal_list_f64_last(gal_list_f64_t *list);
+
 void
 gal_list_f64_print(gal_list_f64_t *list);
 
@@ -235,6 +250,9 @@ gal_list_void_pop(gal_list_void_t **list);
 size_t
 gal_list_void_number(gal_list_void_t *list);
 
+gal_list_void_t *
+gal_list_void_last(gal_list_void_t *list);
+
 void
 gal_list_void_reverse(gal_list_void_t **list);
 
@@ -322,9 +340,15 @@ gal_list_data_pop(gal_data_t **list);
 void
 gal_list_data_reverse(gal_data_t **list);
 
+gal_data_t **
+gal_list_data_to_array_ptr(gal_data_t *list, size_t *num);
+
 size_t
 gal_list_data_number(gal_data_t *list);
 
+gal_data_t *
+gal_list_data_last(gal_data_t *list);
+
 void
 gal_list_data_free(gal_data_t *list);
 
diff --git a/lib/list.c b/lib/list.c
index 1c84a7c..c28b845 100644
--- a/lib/list.c
+++ b/lib/list.c
@@ -102,6 +102,21 @@ gal_list_str_number(gal_list_str_t *list)
 
 
 
+gal_list_str_t *
+gal_list_str_last(gal_list_str_t *list)
+{
+  if(list)
+    {
+      while(list->next!=NULL) list=list->next;
+      return list;
+    }
+  else return NULL;
+}
+
+
+
+
+
 void
 gal_list_str_print(gal_list_str_t *list)
 {
@@ -225,6 +240,21 @@ gal_list_i32_number(gal_list_i32_t *list)
 
 
 
+gal_list_i32_t *
+gal_list_i32_last(gal_list_i32_t *list)
+{
+  if(list)
+    {
+      while(list->next!=NULL) list=list->next;
+      return list;
+    }
+  else return NULL;
+}
+
+
+
+
+
 void
 gal_list_i32_print(gal_list_i32_t *list)
 {
@@ -374,6 +404,22 @@ gal_list_sizet_number(gal_list_sizet_t *list)
 
 
 
+
+gal_list_sizet_t *
+gal_list_sizet_last(gal_list_sizet_t *list)
+{
+  if(list)
+    {
+      while(list->next!=NULL) list=list->next;
+      return list;
+    }
+  else return NULL;
+}
+
+
+
+
+
 void
 gal_list_sizet_print(gal_list_sizet_t *list)
 {
@@ -524,6 +570,21 @@ gal_list_f32_number(gal_list_f32_t *list)
 
 
 
+gal_list_f32_t *
+gal_list_f32_last(gal_list_f32_t *list)
+{
+  if(list)
+    {
+      while(list->next!=NULL) list=list->next;
+      return list;
+    }
+  else return NULL;
+}
+
+
+
+
+
 void
 gal_list_f32_reverse(gal_list_f32_t **list)
 {
@@ -681,6 +742,21 @@ gal_list_f64_number(gal_list_f64_t *list)
 
 
 
+gal_list_f64_t *
+gal_list_f64_last(gal_list_f64_t *list)
+{
+  if(list)
+    {
+      while(list->next!=NULL) list=list->next;
+      return list;
+    }
+  else return NULL;
+}
+
+
+
+
+
 void
 gal_list_f64_print(gal_list_f64_t *list)
 {
@@ -836,6 +912,22 @@ gal_list_void_number(gal_list_void_t *list)
 
 
 
+
+gal_list_void_t *
+gal_list_void_last(gal_list_void_t *list)
+{
+  if(list)
+    {
+      while(list->next!=NULL) list=list->next;
+      return list;
+    }
+  else return NULL;
+}
+
+
+
+
+
 void
 gal_list_void_reverse(gal_list_void_t **list)
 {
@@ -1273,6 +1365,32 @@ gal_list_data_reverse(gal_data_t **list)
 
 
 
+gal_data_t **
+gal_list_data_to_array_ptr(gal_data_t *list, size_t *num)
+{
+  size_t i, n;
+  gal_data_t *tmp, **out;
+
+  /* Count how many columns are necessary. */
+  n=*num=gal_list_data_number(list);
+
+  /* Allocate space for the array. */
+  errno=0;
+  out=malloc(n * sizeof *out);
+  if(out==NULL)
+    error(EXIT_FAILURE, 0, "%s: couldn't allocate %zu bytes", __func__,
+          n * sizeof *out);
+
+  /* Fill up the array with the pointers and return. */
+  i=0;
+  for(tmp=list;tmp!=NULL;tmp=tmp->next) out[i++]=tmp;
+  return out;
+}
+
+
+
+
+
 size_t
 gal_list_data_number(gal_data_t *list)
 {
@@ -1288,6 +1406,21 @@ gal_list_data_number(gal_data_t *list)
 
 
 
+
+gal_data_t *
+gal_list_data_last(gal_data_t *list)
+{
+  if(list)
+    {
+      while(list->next!=NULL) list=list->next;
+      return list;
+    }
+  else return NULL;
+}
+
+
+
+
 void
 gal_list_data_free(gal_data_t *list)
 {



reply via email to

[Prev in Thread] Current Thread [Next in Thread]