about summary refs log tree commit diff
path: root/converter/other/fiasco/codec/approx.c
diff options
context:
space:
mode:
Diffstat (limited to 'converter/other/fiasco/codec/approx.c')
-rw-r--r--converter/other/fiasco/codec/approx.c702
1 files changed, 702 insertions, 0 deletions
diff --git a/converter/other/fiasco/codec/approx.c b/converter/other/fiasco/codec/approx.c
new file mode 100644
index 00000000..72e38cbf
--- /dev/null
+++ b/converter/other/fiasco/codec/approx.c
@@ -0,0 +1,702 @@
+/*
+ *  approx.c:		Approximation of range images with matching pursuit
+ *
+ *  Written by:		Ullrich Hafner
+ *		
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include <math.h>
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "cwfa.h"
+#include "ip.h"
+#include "rpf.h"
+#include "domain-pool.h"
+#include "misc.h"
+#include "list.h"
+#include "approx.h"
+#include "coeff.h"
+#include "wfalib.h"
+
+/*****************************************************************************
+
+			     local variables
+  
+*****************************************************************************/
+
+typedef struct mp
+{
+   word_t exclude [MAXEDGES];
+   word_t indices [MAXEDGES + 1];
+   word_t into [MAXEDGES + 1];
+   real_t weight [MAXEDGES];
+   real_t matrix_bits;
+   real_t weights_bits;
+   real_t err;
+   real_t costs;
+} mp_t;
+
+/*****************************************************************************
+
+			     prototypes
+  
+*****************************************************************************/
+
+static void
+orthogonalize (unsigned index, unsigned n, unsigned level, real_t min_norm,
+	       const word_t *domain_blocks, const coding_t *c);
+static void 
+matching_pursuit (mp_t *mp, bool_t full_search, real_t price,
+		  unsigned max_edges, int y_state, const range_t *range,
+		  const domain_pool_t *domain_pool, const coeff_t *coeff,
+		  const wfa_t *wfa, const coding_t *c);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+real_t 
+approximate_range (real_t max_costs, real_t price, int max_edges,
+		   int y_state, range_t *range, domain_pool_t *domain_pool,
+		   coeff_t *coeff, const wfa_t *wfa, const coding_t *c)
+/*
+ *  Approximate image block 'range' by matching pursuit. This functions
+ *  calls the matching pursuit algorithm several times (with different
+ *  parameters) in order to find the best approximation. Refer to function
+ *  'matching_pursuit()' for more details about parameters.
+ *
+ *  Return value:
+ *	approximation costs
+ */
+{
+   mp_t	  mp;
+   bool_t success = NO;
+
+   /*
+    *  First approximation attempt: default matching pursuit algorithm.
+    */
+   mp.exclude [0] = NO_EDGE;
+   matching_pursuit (&mp, c->options.full_search, price, max_edges,
+		     y_state, range, domain_pool, coeff, wfa, c);
+
+   /*
+    *  Next approximation attempt: remove domain block mp->indices [0]
+    *  from domain pool (vector with smallest costs) and run the
+    *  matching pursuit again.
+    */
+   if (c->options.second_domain_block)
+   {
+      mp_t tmp_mp = mp;
+      
+      tmp_mp.exclude [0] = tmp_mp.indices [0];
+      tmp_mp.exclude [1] = NO_EDGE;
+	    
+      matching_pursuit (&tmp_mp, c->options.full_search, price, max_edges,
+			y_state, range, domain_pool, coeff, wfa, c);
+      if (tmp_mp.costs < mp.costs)	/* success */
+      {
+	 success = YES;
+	 mp      = tmp_mp;
+      }
+   }
+
+   /*
+    *  Next approximation attempt: check whether some coefficients have
+    *  been quantized to zero. Vectors causing the underflow are
+    *  removed from the domain pool and then the matching pursuit
+    *  algorithm is run again (until underflow doesn't occur anymore).
+    */
+   if (c->options.check_for_underflow)
+   {
+      int  iteration = -1;
+      mp_t tmp_mp    = mp;
+      
+      do
+      {
+	 int i;
+ 
+	 iteration++;
+	 tmp_mp.exclude [iteration] = NO_EDGE;
+	 
+	 for (i = 0; isdomain (tmp_mp.indices [i]); i++)
+	    if (tmp_mp.weight [i] == 0)
+	    {
+	       tmp_mp.exclude [iteration] = tmp_mp.indices [i];
+	       break;
+	    }
+      
+	 if (isdomain (tmp_mp.exclude [iteration])) /* try again */
+	 {
+	    tmp_mp.exclude [iteration + 1] = NO_EDGE;
+	    
+	    matching_pursuit (&tmp_mp, c->options.full_search, price,
+			      max_edges, y_state, range, domain_pool,
+			      coeff, wfa, c);
+	    if (tmp_mp.costs < mp.costs)	/* success */
+	    {
+	       success = YES;
+	       mp      = tmp_mp;
+	    }
+	 }
+      } while (isdomain (tmp_mp.exclude [iteration])
+	       && iteration < MAXEDGES - 1);
+   }
+
+   /*
+    *  Next approximation attempt: check whether some coefficients have
+    *  been quantized to +/- max-value. Vectors causing the overflow are
+    *  removed from the domain pool and then the matching pursuit
+    *  algorithm is run again (until overflow doesn't occur anymore).
+    */
+   if (c->options.check_for_overflow)
+   {
+      int  iteration = -1;
+      mp_t tmp_mp    = mp;
+      
+      do
+      {
+	 int i;
+ 
+	 iteration++;
+	 tmp_mp.exclude [iteration] = NO_EDGE;
+	 
+	 for (i = 0; isdomain (tmp_mp.indices [i]); i++)
+	 {
+	    rpf_t *rpf = tmp_mp.indices [i] ? coeff->rpf : coeff->dc_rpf;
+	    
+	    if (tmp_mp.weight [i] == btor (rtob (200, rpf), rpf)
+		|| tmp_mp.weight [i] == btor (rtob (-200, rpf), rpf))
+	    {
+	       tmp_mp.exclude [iteration] = tmp_mp.indices [i];
+	       break;
+	    }
+	 }
+      
+	 if (isdomain (tmp_mp.exclude [iteration])) /* try again */
+	 {
+	    tmp_mp.exclude [iteration + 1] = NO_EDGE;
+	    
+	    matching_pursuit (&tmp_mp, c->options.full_search, price,
+			      max_edges, y_state, range, domain_pool,
+			      coeff, wfa, c);
+	    if (tmp_mp.costs < mp.costs)	/* success */
+	    {
+	       success = YES;
+	       mp      = tmp_mp;
+	    }
+	 }
+      } while (isdomain (tmp_mp.exclude [iteration])
+	       && iteration < MAXEDGES - 1);
+   }
+
+   /*
+    *  Finally, check whether the best approximation has costs
+    *  smaller than 'max_costs'.
+    */
+   if (mp.costs < max_costs) 
+   {
+      int    edge;
+      bool_t overflow  = NO;
+      bool_t underflow = NO;
+      int    new_index, old_index;
+
+      new_index = 0;
+      for (old_index = 0; isdomain (mp.indices [old_index]); old_index++)
+	 if (mp.weight [old_index] != 0)
+	 {
+	    rpf_t *rpf = mp.indices [old_index] ? coeff->rpf : coeff->dc_rpf;
+	    
+	    if (mp.weight [old_index] == btor (rtob (200, rpf), rpf)
+		|| mp.weight [old_index] == btor (rtob (-200, rpf), rpf))
+	       overflow = YES;
+	    
+	    mp.indices [new_index] = mp.indices [old_index];
+	    mp.into [new_index]    = mp.into [old_index];
+	    mp.weight [new_index]  = mp.weight [old_index];
+	    new_index++;
+	 }
+	 else
+	    underflow = YES;
+      
+      mp.indices [new_index] = NO_EDGE;
+      mp.into  [new_index]   = NO_EDGE;
+
+      /*
+       *  Update of probability models
+       */
+      {
+	 word_t *domain_blocks = domain_pool->generate (range->level, y_state,
+							wfa,
+							domain_pool->model);
+	 domain_pool->update (domain_blocks, mp.indices,
+			      range->level, y_state, wfa, domain_pool->model);
+	 coeff->update (mp.weight, mp.into, range->level, coeff);
+	 
+	 Free (domain_blocks);
+      }
+      
+      for (edge = 0; isedge (mp.indices [edge]); edge++)
+      {
+	 range->into [edge]   = mp.into [edge];
+	 range->weight [edge] = mp.weight [edge];
+      }
+      range->into [edge]  = NO_EDGE;
+      range->matrix_bits  = mp.matrix_bits;
+      range->weights_bits = mp.weights_bits;
+      range->err          = mp.err;
+   }
+   else
+   {
+      range->into [0] = NO_EDGE;
+      mp.costs	      = MAXCOSTS;
+   }
+   
+   return mp.costs;
+}
+
+/*****************************************************************************
+
+			     local variables
+  
+*****************************************************************************/
+
+static real_t norm_ortho_vector [MAXSTATES];     
+/*
+ *  Square-norm of the i-th vector of the orthogonal basis (OB)
+ *  ||o_i||^2; i = 0, ... ,n
+ */
+static real_t ip_image_ortho_vector [MAXEDGES];
+/* 
+ *  Inner product between the i-th vector of the OB and the given range: 
+ *  <b, o_i>; i = 0, ... ,n 
+ */
+static real_t ip_domain_ortho_vector [MAXSTATES][MAXEDGES];
+/* 
+ *  Inner product between the i-th vector of the OB and the image of domain j: 
+ *  <s_j, o_i>; j = 0, ... , wfa->states; i = 0, ... ,n, 
+ */
+static real_t rem_denominator [MAXSTATES];     
+static real_t rem_numerator [MAXSTATES];
+/*
+ *  At step n of the orthogonalization the comparitive value
+ *  (numerator_i / denominator_i):= <b, o_n>^2 / ||o_n|| ,
+ *  is computed for every domain i,
+ *  where o_n := s_i - \sum(k = 0, ... , n-1) {(<s_i, o_k> / ||o_k||^2) o_k}
+ *  To avoid computing the same values over and over again,
+ *  the constant (remaining) parts of every domain are
+ *  stored in 'rem_numerator' and 'rem_denominator' separately
+ */
+static bool_t used [MAXSTATES];    
+/*
+ *  Shows whether a domain image was already used in a
+ *  linear combination (YES) or not (NO)
+ */
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static void 
+matching_pursuit (mp_t *mp, bool_t full_search, real_t price,
+		  unsigned max_edges, int y_state, const range_t *range,
+		  const domain_pool_t *domain_pool, const coeff_t *coeff,
+		  const wfa_t *wfa, const coding_t *c)
+/*
+ *  Find an approximation of the current 'range' with a linear
+ *  combination of vectors of the 'domain_pool'. The linear
+ *  combination is generated step by step with the matching pursuit
+ *  algorithm.  If flag 'full_search' is set then compute complete set
+ *  of linear combinations with n = {0, ..., 'max_edges'} vectors and
+ *  return the best one. Otherwise abort the computation as soon as
+ *  costs (LC (n + 1)) exceed costs ( LC (n)) and return the
+ *  sub-optimal solution.  'price' is the langrange multiplier
+ *  weighting rate and distortion.  'band' is the current color band
+ *  and 'y_state' the corresponding state in the Y component at same
+ *  pixel position.  'domain_pool' gives the set of available vectors,
+ *  and 'coeff' the model for the linear factors. The number of
+ *  elements in the linear combination is limited by 'max_edges'. In
+ *  'mp', vectors may be specified which should be excluded during the
+ *  approximation.
+ *  
+ *  No return value.
+ *
+ *  Side effects:
+ *	vectors, factors, rate, distortion and costs are stored in 'mp'
+ */
+{
+   unsigned	 n;			/* current vector of the OB */
+   int		 index;			/* best fitting domain image */
+   unsigned	 domain;		/* counter */
+   real_t	 norm;			/* norm of range image */
+   real_t	 additional_bits;	/* bits for mc, nd, and tree */
+   word_t	*domain_blocks;		/* current set of domain images */
+   const real_t  min_norm = 2e-3;	/* lower bound of norm */
+   unsigned 	 best_n   = 0;
+   unsigned	 size 	  = size_of_level (range->level);
+ 
+   /*
+    *  Initialize domain pool and inner product arrays
+    */
+   domain_blocks = domain_pool->generate (range->level, y_state, wfa,
+					  domain_pool->model);
+   for (domain = 0; domain_blocks [domain] >= 0; domain++)
+   {
+      used [domain] = NO;
+      rem_denominator [domain]		/* norm of domain */
+	 = get_ip_state_state (domain_blocks [domain], domain_blocks [domain],
+			       range->level, c);
+      if (rem_denominator [domain] / size < min_norm)
+	 used [domain] = YES;		/* don't use domains with small norm */
+      else
+	 rem_numerator [domain]		/* inner product <s_domain, b> */
+	    = get_ip_image_state (range->image, range->address,
+				  range->level, domain_blocks [domain], c);
+      if (!used [domain] && fabs (rem_numerator [domain]) < min_norm)
+	 used [domain] = YES;
+   }
+
+   /*
+    *  Exclude all domain blocks given in array 'mp->exclude'
+    */
+   for (n = 0; isdomain (mp->exclude [n]); n++)
+      used [mp->exclude [n]] = YES;
+
+   /*
+    *  Compute the approximation costs if 'range' is approximated with
+    *  no linear combination, i.e. the error is equal to the square
+    *  of the image norm and the size of the automaton is determined by
+    *  storing only zero elements in the current matrix row
+    */
+   for (norm = 0, n = 0; n < size; n++)
+      norm += square (c->pixels [range->address * size + n]);
+
+   additional_bits = range->tree_bits + range->mv_tree_bits
+		     + range->mv_coord_bits + range->nd_tree_bits
+		     + range->nd_weights_bits;
+
+   mp->err          = norm;
+   mp->weights_bits = 0;
+   mp->matrix_bits  = domain_pool->bits (domain_blocks, NULL, range->level,
+					 y_state, wfa, domain_pool->model);
+   mp->costs        = (mp->matrix_bits + mp->weights_bits
+		       + additional_bits) * price + mp->err;
+
+   n = 0;
+   do 
+   {
+      /*
+       *  Current approximation is: b = d_0 o_0 + ... + d_(n-1) o_(n-1)
+       *  with corresponding costs 'range->err + range->bits * p'.
+       *  For all remaining state images s_i (used[s_i] == NO) set
+       *  o_n :	= s_i - \sum(k = 0, ... , n-1) {(<s_i, o_k> / ||o_k||^2) o_k}
+       *  and try to beat current costs.
+       *  Choose that vector for the next orthogonalization step,
+       *  which has minimal costs: s_index.
+       *  (No progress is indicated by index == -1)
+       */
+      
+      real_t min_matrix_bits  = 0;
+      real_t min_weights_bits = 0;
+      real_t min_error 	      = 0;
+      real_t min_weight [MAXEDGES];
+      real_t min_costs = full_search ? MAXCOSTS : mp->costs;
+      
+      for (index = -1, domain = 0; domain_blocks [domain] >= 0; domain++) 
+	 if (!used [domain]) 
+	 {
+	    real_t    matrix_bits, weights_bits;
+	    /*
+	     *  To speed up the search through the domain images,
+	     *  the costs of using domain image 'domain' as next vector
+	     *  can be approximated in a first step:
+	     *  improvement of image quality
+	     *	  <= square (rem_numerator[domain]) / rem_denominator[domain]
+	     */
+	    {
+		  word_t   vectors [MAXEDGES + 1];
+		  word_t   states [MAXEDGES + 1];
+		  real_t   weights [MAXEDGES + 1];
+		  unsigned i, k;
+		  
+		  for (i = 0, k = 0; k < n; k++)
+		     if (mp->weight [k] != 0)
+		     {
+			vectors [i] = mp->indices [k];
+			states [i]  = domain_blocks [vectors [i]];
+			weights [i] = mp->weight [k];
+			i++;
+		     }
+		  vectors [i] 	  = domain;
+		  states [i]  	  = domain_blocks [domain];
+		  weights [i] 	  = 0.5;
+		  vectors [i + 1] = -1;
+		  states [i + 1]  = -1;
+
+		  weights_bits = coeff->bits (weights, states, range->level,
+					      coeff);
+		  matrix_bits = domain_pool->bits (domain_blocks, vectors,
+						   range->level, y_state,
+						   wfa, domain_pool->model);
+	    }
+	    if (((matrix_bits + weights_bits + additional_bits) * price +
+		 mp->err -
+		 square (rem_numerator [domain]) / rem_denominator [domain])
+		< min_costs)
+	    {
+	       /*
+		*  1.) Compute the weights (linear factors) c_i of the
+		*  linear combination
+		*  b = c_0 v_0 + ... + c_(n-1) v_(n-1) + c_n v_'domain'
+		*  Use backward substitution to obtain c_i from the linear
+		*  factors of the lin. comb. b = d_0 o_0 + ... + d_n o_n
+		*  of the corresponding orthogonal vectors {o_0, ..., o_n}.
+		*  Vector o_n of the orthogonal basis is obtained by using
+		*  vector 'v_domain' in step n of the Gram Schmidt
+		*  orthogonalization (see above for definition of o_n).
+		*  Recursive formula for the coefficients c_i:
+		*  c_n := <b, o_n> / ||o_n||^2
+		*  for i = n - 1, ... , 0:
+		*  c_i := <b, o_i> / ||o_i||^2 +
+		*          \sum (k = i + 1, ... , n){ c_k <v_k, o_i>
+		*					/ ||o_i||^2 }
+		*  2.) Because linear factors are stored with reduced precision
+		*  factor c_i is rounded with the given precision in step i
+		*  of the recursive formula. 
+		*/
+
+	       unsigned k;		/* counter */
+	       int    	l;		/* counter */
+	       real_t 	m_bits;		/* number of matrix bits to store */
+	       real_t 	w_bits;		/* number of weights bits to store */
+	       real_t 	r [MAXEDGES];	/* rounded linear factors */
+	       real_t 	f [MAXEDGES];	/* linear factors */
+	       int    	v [MAXEDGES];	/* mapping of domains to vectors */
+	       real_t 	costs;		/* current approximation costs */
+	       real_t 	m_err;		/* current approximation error */
+
+	       f [n] = rem_numerator [domain] / rem_denominator [domain];
+	       v [n] = domain;		/* corresponding mapping */
+	       for (k = 0; k < n; k++)
+	       {
+		  f [k] = ip_image_ortho_vector [k] / norm_ortho_vector [k];
+		  v [k] = mp->indices [k];
+	       }
+	    
+	       for (l = n; l >= 0; l--) 
+	       {
+		  rpf_t *rpf = domain_blocks [v [l]]
+			       ? coeff->rpf : coeff->dc_rpf;
+
+		  r [l] = f [l] = btor (rtob (f [l], rpf), rpf);
+		     
+		  for (k = 0; k < (unsigned) l; k++)
+		     f [k] -= f [l] * ip_domain_ortho_vector [v [l]][k]
+			      / norm_ortho_vector [k] ;
+	       } 
+
+	       /*
+		*  Compute the number of output bits of the linear combination
+		*  and store the weights with reduced precision. The
+		*  resulting linear combination is
+		*  b = r_0 v_0 + ... + r_(n-1) v_(n-1) + r_n v_'domain'
+		*/
+	       {
+		  word_t vectors [MAXEDGES + 1];
+		  word_t states [MAXEDGES + 1];
+		  real_t weights [MAXEDGES + 1];
+		  int	 i;
+		  
+		  for (i = 0, k = 0; k <= n; k++)
+		     if (f [k] != 0)
+		     {
+			vectors [i] = v [k];
+			states [i]  = domain_blocks [v [k]];
+			weights [i] = f [k];
+			i++;
+		     }
+		  vectors [i] = -1;
+		  states [i]  = -1;
+
+		  w_bits = coeff->bits (weights, states, range->level, coeff);
+		  m_bits = domain_pool->bits (domain_blocks, vectors,
+					      range->level, y_state,
+					      wfa, domain_pool->model);
+	       }
+	       
+	       /*
+		*  To compute the approximation error, the corresponding
+		*  linear factors of the linear combination 
+		*  b = r_0 o_0 + ... + r_(n-1) o_(n-1) + r_n o_'domain'
+		*  with orthogonal vectors must be computed with following
+		*  formula:
+		*  r_i := r_i +
+		*          \sum (k = i + 1, ... , n) { r_k <v_k, o_i>
+		*					/ ||o_i||^2 }
+		*/
+	       for (l = 0; (unsigned) l <= n; l++)
+	       {
+		  /*
+		   *  compute <v_n, o_n>
+		   */
+		  real_t a;
+
+		  a = get_ip_state_state (domain_blocks [v [l]],
+					  domain_blocks [domain],
+					  range->level, c);
+		  for (k = 0; k < n; k++) 
+		     a -= ip_domain_ortho_vector [v [l]][k]
+			  / norm_ortho_vector [k]
+			  * ip_domain_ortho_vector [domain][k];
+		  ip_domain_ortho_vector [v [l]][n] = a;
+	       }
+	       norm_ortho_vector [n]     = rem_denominator [domain];
+	       ip_image_ortho_vector [n] = rem_numerator [domain];
+ 	    
+	       for (k = 0; k <= n; k++)
+		  for (l = k + 1; (unsigned) l <= n; l++)
+		     r [k] += ip_domain_ortho_vector [v [l]][k] * r [l]
+			      / norm_ortho_vector [k];
+	       /*
+		*  Compute approximation error:
+		*  error := ||b||^2 +
+		*  \sum (k = 0, ... , n){r_k^2 ||o_k||^2 - 2 r_k <b, o_k>}
+		*/
+	       m_err = norm;
+	       for (k = 0; k <= n; k++)
+		  m_err += square (r [k]) * norm_ortho_vector [k]
+			 - 2 * r [k] * ip_image_ortho_vector [k];
+	       if (m_err < 0)		/* TODO: return MAXCOSTS */
+		  warning ("Negative image norm: %f"
+			   " (current domain: %d, level = %d)",
+			   (double) m_err, domain, range->level);
+
+	       costs = (m_bits + w_bits + additional_bits) * price + m_err;
+	       if (costs < min_costs)	/* found a better approximation */
+	       {
+		  index            = domain;
+		  min_costs        = costs;
+		  min_matrix_bits  = m_bits;
+		  min_weights_bits = w_bits;
+		  min_error        = m_err;
+		  for (k = 0; k <= n; k++)
+		     min_weight [k] = f [k];
+	       }
+	    }
+	 }
+      
+      if (index >= 0)			/* found a better approximation */
+      {
+	 if (min_costs < mp->costs)
+	 {
+	    unsigned k;
+	    
+	    mp->costs        = min_costs;
+	    mp->err          = min_error;
+	    mp->matrix_bits  = min_matrix_bits;
+	    mp->weights_bits = min_weights_bits;
+	    
+	    for (k = 0; k <= n; k++)
+	       mp->weight [k] = min_weight [k];
+
+	    best_n = n + 1;
+	 }
+	 
+	 mp->indices [n] = index;
+	 mp->into [n]    = domain_blocks [index];
+
+	 used [index] = YES;
+
+	 /* 
+	  *  Gram-Schmidt orthogonalization step n 
+	  */
+	 orthogonalize (index, n, range->level, min_norm, domain_blocks, c);
+	 n++;
+      }	
+   } 
+   while (n < max_edges && index >= 0);
+
+   mp->indices [best_n] = NO_EDGE;
+   
+   mp->costs = (mp->matrix_bits + mp->weights_bits + additional_bits) * price
+	       + mp->err;
+
+   Free (domain_blocks);
+}
+
+static void
+orthogonalize (unsigned index, unsigned n, unsigned level, real_t min_norm,
+	       const word_t *domain_blocks, const coding_t *c)
+/*
+ *  Step 'n' of the Gram-Schmidt orthogonalization procedure:
+ *  vector 'index' is orthogonalized with respect to the set
+ *  {u_[0], ... , u_['n' - 1]}. The size of the image blocks is given by
+ *  'level'. If the denominator gets smaller than 'min_norm' then
+ *  the corresponding domain is excluded from the list of available
+ *  domain blocks.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	The remainder values (numerator and denominator) of
+ *	all 'domain_blocks' are updated. 
+ */
+{
+   unsigned domain;
+   
+   ip_image_ortho_vector [n] = rem_numerator [index];
+   norm_ortho_vector [n]     = rem_denominator [index];
+
+   /*
+    *  Compute inner products between all domain images and 
+    *  vector n of the orthogonal basis:
+    *  for (i = 0, ... , wfa->states)  
+    *  <s_i, o_n> := <s_i, v_n> -
+    *      \sum (k = 0, ... , n - 1){ <v_n, o_k> <s_i, o_k> / ||o_k||^2}
+    *  Moreover the denominator and numerator parts of the comparitive
+    *  value are updated.
+    */
+   for (domain = 0; domain_blocks [domain] >= 0; domain++) 
+      if (!used [domain]) 
+      {
+	 unsigned k;
+	 real_t   tmp = get_ip_state_state (domain_blocks [index],
+					    domain_blocks [domain], level, c);
+	 
+	 for (k = 0; k < n; k++) 
+	    tmp -= ip_domain_ortho_vector [domain][k] / norm_ortho_vector [k]
+		   * ip_domain_ortho_vector [index][k];
+	 ip_domain_ortho_vector [domain][n] = tmp;
+	 rem_denominator [domain] -= square (tmp) / norm_ortho_vector [n];
+	 rem_numerator [domain]   -= ip_image_ortho_vector [n]
+				     / norm_ortho_vector [n]
+				     * ip_domain_ortho_vector [domain][n] ;
+
+	 /*
+	  *  Exclude vectors with small denominator
+	  */
+	 if (!used [domain]) 
+	    if (rem_denominator [domain] / size_of_level (level) < min_norm) 
+	       used [domain] = YES;
+      }
+}
+
+
+