function d = ipdm(data1,varargin)
% ipdm: Inter-Point Distance Matrix
% usage: d = ipdm(data1)
% usage: d = ipdm(data1,data2)
% usage: d = ipdm(data1,prop,value)
% usage: d = ipdm(data1,data2,prop,value)
%
% Arguments: (input)
%  data1 - array of data points, each point is one row. p dimensional
%          data will be represented by matrix with p columns.
%          If only data1 is provided, then the distance matrix
%          is computed between all pairs of rows of data1.
%
%          If your data is one dimensional, it MUST form a column
%          vector. A row vector of length n will be interpreted as
%          an n-dimensional data set.
%
%  data2 - second array, supplied only if distances are to be computed
%          between two sets of points.
%
%
% Class support: data1 and data2 are assumed to be either
% single or double precision. I have not tested this code to
% verify its success on integer data of any class.
%
%
% Additional parameters are expected to be property/value pairs.
% Property/value pairs are pairs of arguments, the first of which
% (properties) must always be a character string. These strings
% may be shortened as long as the shortening is unambiguous.
% Capitalization is ignored. Valid properties for ipdm are:
%
%  'Metric', 'Subset', 'Limit', 'Result'
%
%  'Metric' - numeric flag - defines the distance metric used
%          metric = 2 --> (DEFAULT) Euclidean distance = 2-norm
%                         The standard distance metric.
%
%          metric = 1 --> 1-norm = sum of absolute differences
%                         Also sometimes known as the "city block
%                         metric", since this is the sum of the
%                         differences in each dimension.
%
%          metric = inf --> infinity-norm = maximum difference
%                         over all dimensions. The name refers
%                         to the limit of the p-norm, as p
%                         approaches infinity.
%
%          metric = 0 --> minimum difference over all dimensions.
%                         This is not really a useful norm in
%                         practice.
%
%          Note: while other distance metrics exist, IMHO, these
%          seemed to be the common ones.
%
%
%  'Result' - A string variable that denotes the style of returned
%          result. Valid result types are 'Array', 'Structure'.
%          Capitalization is ignored, and the string may be
%          shortened if you wish.
%
%          result = 'Array' --> (DEFAULT) A matrix of all
%                         interpoint distances will be generated.
%                         This array may be large. If this option
%                         is specified along with a minimum or
%                         maximum value, then those elements above
%                         or below the limiting values will be
%                         set as -inf or +inf, as appropriate.
%
%                         When any of 'LargestFew', 'SmallestFew',
%                         or 'NearestNeighbor' are set, then the
%                         resulting array will be a sparse matrix
%                         if 'array' is specified as the result.
%
%          result = 'Structure' --> A list of all computed distances,
%                         defined as a structure. This structure
%                         will have fields named 'rowindex',
%                         'columnindex', and 'distance'.
%
%                         This option will be useful when a subset
%                         criterion for the distances has been
%                         specified, since then the distance matrix
%                         may be very sparsely populated. Distances
%                         for pairs outside of the criterion will
%                         not be returned.
%
%
%  'Subset' - Character string, any of:
%
%          'All', 'Maximum', 'Minimum', 'LargestFew', 'SmallestFew',
%          'NearestNeighbor', 'FarthestNeighbor', or empty
%
%          Like properties, capitalization is ignored here, and
%          any unambiguous shortening of the word is acceptable.
%
%          DEFAULT = 'All'
%
%          Some interpoint distance matrices can be huge. Often
%          these matrices are too large to be fully retained in
%          memory, yet only the pair of points with the largest
%          or smallest distance may be needed. When only some
%          subset of the complete set of distances is of interest,
%          these options allow you to specify which distances will
%          be returned.
%
%          If 'result' is defined to be an array, then a sparse
%          matrix will be returned for the 'LargestFew', 'SmallestFew',
%          'NearestNeighbor', and 'FarthestNeighbor' subset classes.
%          'Minimum' and 'Maximum' will yield full matrices by
%          default. If a structure is specified, then only those
%          elements which have been identified will be returned.
%
%          Where a subset is specified, its limiting value is
%          specified by the 'Limit' property. Call that value k.
%
%
%          'All' -->     (DEFAULT) Return all interpoint distances
%
%          'Minimum' --> Only look for those distances above
%                        the cutoff k. All other distances will
%                        be returned as -inf.
%
%          'Maximum' --> Only look for those distances below
%                        the cutoff k. All other distances will
%                        be returned as +inf.
%
%          'SmallestFew' --> Only return the subset of the k
%                        smallest distances. Where only one data
%                        set is provided, only the upper triangle
%                        of the inter-point distance matrix will
%                        be generated since that matrix is symmetric.
%
%          'LargestFew' --> Only return the subset of the k
%                        largest distances. Where only one data
%                        set is provided, only the upper triangle
%                        of the inter-point distance matrix will
%                        be generated since that matrix is symmetric.
%
%          'NearestNeighbor' --> Only return the single nearest
%                        neighbor in data2 to each point in data1.
%                        No limiting value is required for this
%                        option. If multiple points have the same
%                        nearest distance, then return the first
%                        such point found. With only one input set,
%                        a point will not be its own nearest
%                        neighbor.
%
%                        Note that exact replicates in a single set
%                        will cause problems, since a sparse matrix
%                        is returned by default. Since they will have
%                        a zero distance, they will not show up in
%                        the sparse matrix. A structure return will
%                        show those points as having a zero distance
%                        though.
%
%          'FarthestNeighbor' --> Only return the single farthest
%                        neighbor to each point. No limiting value
%                        is required for this option. If multiple
%                        points have the same farthest distance,
%                        then return the first such point found.
%
%
%  'Limit' - scalar numeric value or []. Used only when some
%           Subset is specified.
%
%          DEFAULT = []
%
%
%  'ChunkSize' - allows a user with lower RAM limits
%          to force the code to only grab smaller chunks of RAM
%          at a time (where possible). This parameter is specified
%          in bytes of RAM. The default is 32 megabytes, or 2^22
%          elements in any piece of the distance matrix. Only some
%          options will break the problem into chunks, thus as long
%          as a full matrix is expected to be returned, there seems
%          no reason to break the problem up into pieces.
%
%          DEFAULT = 2^25
%
%
% Arguments: (output)
%  d     - array of interpoint distances, or a struct wth the
%          fields {'rowindex', 'columnindex', 'distance'}.
%
%          d(i,j) represents the distance between point i
%          (from data1) and point j (from data2).
%
%          If only one (n1 x p) array is supplied, then d will
%          be an array of size == [n1,n1].
%
%          If two arrays (of sizes n1 x p and n2 x p) then d
%          will be an array of size == [n1,n2].
%
%
% Efficiency considerations:
%  Where possible, this code will use bsxfun to compute its
%  distances.
%
%
% Example:
%  Compute the interpoint distances between all pairs of points
%  in a list of 5 points, in 2 dimensions and using Euclidean
%  distance as the distance metric.
%
%  A = randn(5,2);
%  d = ipdm(A,'metric',2)
%  d =
%            0       2.3295       3.2263       2.0263       2.8244
%       2.3295            0       1.1485      0.31798       1.0086
%       3.2263       1.1485            0       1.4318       1.8479
%       2.0263      0.31798       1.4318            0       1.0716
%       2.8244       1.0086       1.8479       1.0716            0
%
% (see the demo file for many other examples)
%
% See also: pdist
%
% Author: John D'Errico
% e-mail: woodchips@rochester.rr.com
% Release: 1.0
% Release date: 2/26/08

% Default property values
params.Metric = 2;
params.Result = 'array';
params.Subset = 'all';
params.Limit = [];
params.ChunkSize = 2^25;

% untangle the arguments
if nargin<1
  % if called with no arguments, then the user probably
  % needs help. Give it to them.
  help ipdm
  return
end

% were two sets of data provided?
pvpairs = {};
if nargin==1
  % only 1 set of data provided
  dataflag = 1;
  data2 = [];
else
  if ischar(varargin{1})
    dataflag = 1;
    data2 = [];
    pvpairs = varargin;
  else
    dataflag = 2;
    data2 = varargin{1};
    if nargin>2
      pvpairs = varargin(2:end);
    end
  end
end

% get data sizes for later
[n1,dim] = size(data1);
if dataflag == 2
  n2 = size(data2,1);
end

% Test the class of the input variables
if ~(isa(data1,'double') || isa(data1,'single')) || ...
    ((dataflag == 2) && ~(isa(data2,'double') || isa(data2,'single')))
  error('data points must be either single or double precision variables.')
end

% do we need to process any property/value pairs?
if nargin>2
  params = parse_pv_pairs(params,pvpairs);

  % check for problems in the properties

  % was a legal Subset provided?
  if ~isempty(params.Subset) && ~ischar(params.Subset)
    error('If provided, ''Subset'' must be character')
  elseif isempty(params.Subset)
    params.Subset = 'all';
  end
  valid = {'all','maximum','minimum','largestfew','smallestfew', ...
    'nearestneighbor','farthestneighbor'};
  ind = find(strncmpi(params.Subset,valid,length(params.Subset)));
  if (length(ind)==1)
    params.Subset = valid{ind};
  else
    error(['Invalid Subset: ',params.Subset])
  end

  % was a limit provided?
  if ~ismember(params.Subset,{'all','nearestneighbor','farthestneighbor'}) && ...
      isempty(params.Limit)
    error('No limit provided, but a Subset that requires a limit value was specified')
  end
  % check the limit values for validity
  if length(params.Limit)>1
    error('Limit must be scalar or empty')
  end

  switch params.Subset
    case {'largestfew', 'smallestfew'}
      % must be at least 1, and an integer
      if (params.Limit<1) || (round(params.Limit)~=params.Limit)
        error('Limit must be a positive integer for LargestFew or NearestFew')
      end
  end

  % was a legal Result provided?
  if isempty(params.Result)
    params.result = 'Array';
  elseif ~ischar(params.Result)
    error('If provided, ''Result'' must be character or empty')
  end
  valid = {'array','structure'};
  ind = find(strncmpi(params.Result,valid,length(params.Result)));
  if (length(ind)==1)
    params.Result = valid{ind};
  else
    error(['Invalid Result: ',params.Subset])
  end

  % check for the metric
  if isempty(params.Metric)
    params.Metric = 2;
  elseif (length(params.Metric)~=1) || ~ismember(params.Metric,[0 1 2 inf])
    error('If supplied, ''Metric'' must be a scalar, and one of [0 1 2 inf]')
  end
end % if nargin>2

% If Metric was given as 2, but the dimension is only 1, then it will
% be slightly faster (and equivalent) to use the 1-norm Metric.
if (dim == 1) && (params.Metric == 2)
  params.Metric = 1;
end

% Can we use bsxfun to compute the interpoint distances?
% Older Matlab releases will not have bsxfun, but if it is
% around, it will ne both faster and less of a memory hog.
params.usebsxfun = (5==exist('bsxfun','builtin'));

% check for dimension mismatch if 2 sets
if (dataflag==2) && (size(data2,2)~=dim)
  error('If 2 point sets provided, then both must have the same number of columns')
end

% Total number of distances to compute, in case I must do it in batches
if dataflag==1
  n2 = n1;
end
ntotal = n1*n2;

% FINALLY!!! Compute inter-point distances
switch params.Subset
  case 'all'
    % The complete set of interpoint distances. There is no need
    % to break this into chunks, since we must return all distances.
    % If that is too much to compute in memory, then it will fail
    % anyway when we try to store the result. bsxfun will at least
    % do the computation efficiently.

    % One set or two?
    if dataflag == 1
      d = distcomp(data1,data1,params);
    else
        d = distcomp(data1,data2,params);
    end

    % Must we return it as a struct?
    if params.Result(1) == 's'
      [rind,cind] = ndgrid(1:size(d,1),1:size(d,2));
      ds.rowindex = rind(:);
      ds.columnindex = cind(:);
      ds.distance = d(:);
      d = ds;
    end

  case {'minimum' 'maximum'}
    % There is no reason to break this into pieces if the result
    % sill be filled in the end with +/- inf. Only break it up
    % if the final result is a struct.
    if ((ntotal*8)<=params.ChunkSize) || (params.Result(1) == 'a')
      % its small enough to do it all at once

      % One set or two?
      if dataflag == 1
        d = distcomp(data1,data1,params);
      else
          d = distcomp(data1,data2,params);
      end

      % Must we return it as a struct?
      if params.Result(1) == 'a'
        % its an array, fill the unwanted distances with +/- inf
        if params.Subset(2) == 'i'
          % minimum
          d(d<=params.Limit) = -inf;
        else
          % maximum
          d(d>=params.Limit) = +inf;
        end
      else
        % a struct will be returned
        if params.Subset(2) == 'i'
          % minimum
          [dist.rowindex,dist.columnindex] = find(d>=params.Limit);
        else
          % maximum
          [dist.rowindex,dist.columnindex] = find(d<=params.Limit);
        end
        dist.distance = d(dist.rowindex + n1*(dist.columnindex-1));
        d = dist;
      end

    else
      % we need to break this into chunks. This branch
      % will always return a struct.

      % this is the number of rows of data1 that we will
      % process at a time.
      bs = floor(params.ChunkSize/(8*n2));
      bs = min(n1,max(1,bs));

      % Accumulate the result into a cell array. Do it this
      % way because we don't know in advance how many elements
      % that we will find satisfying the minimum or maximum
      % limit specified.
      accum = cell(0,1);

      % now loop over the chunks
      batch = 1:bs;
      while ~isempty(batch)

        % One set or two?
        if dataflag == 1
          dist = distcomp(data1(batch,:),data1,params);
        else
          dist = distcomp(data1(batch,:),data2,params);
        end

        % big or small as requested
        if ('i'==params.Subset(2))
          % minimum value specified
          [I,J,V] = find(dist>=params.Limit);
        else
          % maximum limit
          [I,J] = find(dist<=params.Limit);
          I = I(:);
          J = J(:);
          V = dist(I + (J-1)*length(batch));
          I = I + (batch(1)-1);
        end

        % and stuff them into the cell structure
        if ~isempty(V)
          accum{end+1,1} = [I,J,V(:)]; %#ok
        end

        % increment the batch
        batch = batch + bs;
        if batch(end)>n1
          batch(batch>n1) = [];
        end

      end

      % convert the cells into one flat array
      accum = cell2mat(accum);

      if isempty(accum)
        d.rowindex = [];
        d.columnindex = [];
        d.distance = [];
      else
        % we found something

        % sort on the second column, to put them in a reasonable order
        accum = sortrows(accum,[2 1]);

        d.rowindex = accum(:,1);
        d.columnindex = accum(:,2);
        d.distance = accum(:,3);
      end

    end

  case {'smallestfew' 'largestfew'}
    % find the k smallest/largest distances. k is
    % given by params.Limit

    % if only 1 set, params.Limit must be less than n*(n-1)/2
    if dataflag == 1
      params.Limit = min(params.Limit,n1*(n1-1)/2);
    end

    % is this a large problem?
    if ((ntotal*8) <= params.ChunkSize)
      % small potatoes

      % One set or two?
      if dataflag == 1
        dist = distcomp(data1,data1,params);
        % if only one data set, set the diagonal and
        % below that to +/- inf so we don't find it.
        temp = find(tril(ones(n1,n1),0));
        if params.Subset(1) == 's'
          dist(temp) = inf;
        else
          dist(temp) = -inf;
        end
      else
        dist = distcomp(data1,data2,params);
      end

      % sort the distances to find those we need
      if ('s'==params.Subset(1))
        % smallestfew
        [val,tags] = sort(dist(:),'ascend');
      else
        % largestfew
        [val,tags] = sort(dist(:),'descend');
      end
      val = val(1:params.Limit);
      tags = tags(1:params.Limit);

      % recover the row and column index from the linear
      % index returned by sort in tags.
      [d.rowindex,d.columnindex] = ind2sub([n1,size(dist,2)],tags);

      % create the matrix as a sparse one or a struct?
      if params.Result(1)=='a'
        % its an array, so make the array sparse.
        d = sparse(d.rowindex,d.columnindex,val,n1,size(dist,2));
      else
        % a structure
        d.distance = val;
      end

    else
      % chunks

      % this is the number of rows of data1 that we will
      % process at a time.
      bs = floor(params.ChunkSize/(8*n2));
      bs = min(n1,max(1,bs));

      % We need to find the extreme cases. There are two possible
      % algorithms, depending on how many total elements we will
      % search for.
      % 1. Only a very few total elements.
      % 2. A relatively large number of total elements, forming
      %    a significant fraction of the total set.
      %
      % Case #1 would suggest to retain params.Limit numberr of
      % elements from each batch, then at the end, sort them all
      % to find the best few. Case #2 will result in too many
      % elements to retain, so we must distinguish between these
      % alternatives.
      if (8*params.Limit*n1/bs) <= params.ChunkSize
        % params.Limit is small enough to fall into case #1.

        % Accumulate the result into a cell array. Do it this
        % way because we don't know in advance how many elements
        % that we will find satisfying the minimum or maximum
        % limit specified.
        accum = cell(0,1);

        % now loop over the chunks
        batch = (1:bs)';
        while ~isempty(batch)
          % One set or two?
          if dataflag == 1
            dist = distcomp(data1(batch,:),data1,params);
            k = find(tril(ones(length(batch),n2),batch(1)-1));
            if ('s'==params.Subset(1))
              dist(k) = inf;
            else
              dist(k) = -inf;
            end
          else
            dist = distcomp(data1(batch,:),data2,params);
          end

          % big or small as requested, keeping only the best
          % params.Limit number of elements
          if ('s'==params.Subset(1))
            % minimum value specified
            [tags,tags] = sort(dist(:),1,'ascend');
            tags = tags(1:bs);
            [I,J] = ndgrid(batch,1:n2);
            ijv = [I(tags),J(tags),dist(tags)];
          else
            % maximum limit
            [tags,tags] = sort(dist(:),1,'descend');
            tags = tags(1:bs);
            [I,J] = ndgrid(batch,1:n2);
            ijv = [I(tags),J(tags),dist(tags)];
          end
          % and stuff them into the cell structure
          accum{end+1,1} = ijv; %#ok

          % increment the batch
          batch = batch + bs;
          if batch(end)>n1
            batch(batch>n1) = [];
          end
        end

        % convert the cells into one flat array
        accum = cell2mat(accum);

        % keep only the params.Limit best of those singled out
        accum = sortrows(accum,3);
        if ('s'==params.Subset(1))
          % minimum value specified
          accum = accum(1:params.Limit,:);
        else
          % minimum value specified
          accum = accum(end + 1 - (1:params.Limit),:);
        end
        d.rowindex = accum(:,1);
        d.columnindex = accum(:,2);
        d.distance = accum(:,3);

        % create the matrix as a sparse one or a struct?
        if params.Result(1)=='a'
          % its an array, so make the array sparse.
          d = sparse(d.rowindex,d.columnindex,d.distance,n1,size(dist,2));
        end

      else
        % params.Limit forces us into the domain of case #2.
        % Here we cannot retain params.Limit elements from each chunk.
        % so we will grab each chunk and append it to the best elements
        % found so far, then filter out the best after each chunk is
        % done. This may be slower than we want, but its the only way.
        ijv = zeros(0,3);

        % loop over the chunks
        batch = (1:bs)';
        while ~isempty(batch)
          % One set or two?
          if dataflag == 1
            dist = distcomp(data1(batch,:),data1,params);
            k = find(tril(ones(length(batch),n2),batch(1)-1));
            if ('s'==params.Subset(1))
              dist(k) = inf;
            else
              dist(k) = -inf;
            end
          else
            dist = distcomp(data1(batch,:),data2,params);
          end

          [I,J] = ndgrid(batch,1:n2);
          ijv = [ijv;[I(:),J(:),dist(:)]]; %#ok

          % big or small as requested, keeping only the best
          % params.Limit number of elements
          if size(ijv,1) > params.Limit
            if ('s'==params.Subset(1))
              % minimum value specified
              [tags,tags] = sort(ijv(:,3),1,'ascend');
            else
              [tags,tags] = sort(ijv(:,3),1,'ascend');
            end
            ijv = ijv(tags(1:params.Limit),:);
          end

          % increment the batch
          batch = batch + bs;
          if batch(end)>n1
            batch(batch>n1) = [];
          end
        end

        % They are fully trimmed down. stuff a structure
        d.rowindex = ijv(:,1);
        d.columnindex = ijv(:,2);
        d.distance = ijv(:,3);

        % create the matrix as a sparse one or a struct?
        if params.Result(1)=='a'
          % its an array, so make the array sparse.
          d = sparse(d.rowindex,d.columnindex,d.distance,n1,size(dist,2));
        end

      end

    end

  case {'nearestneighbor' 'farthestneighbor'}
    % find the closest/farthest neighbor for every point

    % is this a large problem? Or a 1-d problem?
    if dim == 1
      % its a 1-d nearest/farthest neighbor problem. we can
      % special case these easily enough, and all the distance
      % metric options are the same in 1-d.

      % first split it into the farthest versus nearest cases.
      if params.Subset(1) == 'f'
        % farthest away

        % One set or two?
        if dataflag == 1
          [d2min,minind] = min(data1);
          [d2max,maxind] = max(data1);
        else
          [d2min,minind] = min(data2);
          [d2max,maxind] = max(data2);
        end

        d.rowindex = (1:n1)';
        d.columnindex = repmat(maxind,n1,1);
        d.distance = repmat(d2max,n1,1);

        % which endpoint was further away?
        k = abs((data1 - d2min)) >= abs((data1 - d2max));
        if any(k)
          d.columnindex(k) = minind;
          d.distance(k) = d2min;
        end

      else
        % nearest. this is mainly a sort and some fussing around.
        d.rowindex = (1:n1)';
        d.columnindex = ones(n1,1);
        d.distance = zeros(n1,1);

        % One set or two?
        if dataflag == 1
          % if only one data point, then we are done
          if n1 == 2
            % if exactly two data points, its trivial
            d.columnindex = [2 1];
            d.distance = repmat(abs(diff(data1)),2,1);
          elseif n1>2
            % at least three points. do a sort.
            [sorted_data,tags] = sort(data1);

            % handle the first and last points separately
            d.columnindex(tags(1)) = tags(2);
            d.distance(tags(1)) = sorted_data(2) - sorted_data(1);
            d.columnindex(tags(end)) = tags(end-1);
            d.distance(tags(end)) = sorted_data(end) - sorted_data(end-1);

            ind = (2:(n1-1))';

            d1 = sorted_data(ind) - sorted_data(ind-1);
            d2 = sorted_data(ind+1) - sorted_data(ind);

            k = d1 < d2;
            d.distance(tags(ind(k))) = d1(k);
            d.columnindex(tags(ind(k))) = tags(ind(k)-1);
            k = ~k;
            d.distance(tags(ind(k))) = d2(k);
            d.columnindex(tags(ind(k))) = tags(ind(k)+1);
          end % if n1 == 2
        else
          % Two sets of data. still really a sort and some fuss.
          if n2 == 1
            % there is only one point in data2
            d.distance = abs(data1 - data2);
            % d.columnindex is already set correctly
          else
            % At least two points in data2
            % We need to sort all the data points together, but also
            % know which points from each set went where. ind12 and
            % bool12 will help keep track.
            ind12 = [1:n1,1:n2]';
            bool12 = [zeros(n1,1);ones(n2,1)];
            [sorted_data,tags] = sort([data1;data2]);

            ind12 = ind12(tags);
            bool12 = bool12(tags);

            % where did each point end up after the sort?
            loc1 = find(~bool12);
            loc2 = find(bool12);

            % for each point in data1, what is the (sorted) data2
            % element which appears most nearly to the left of it?
            cs = cumsum(bool12);
            leftelement = cs(loc1);

            % any points which fell below the minimum element in data2
            % will have a zero for the index of the element on their
            % left. fix this.
            leftelement = max(1,leftelement);

            % likewise, any point greater than the max in data2 will
            % have an n2 in left element. this too will be a problem
            % later, so fix it.
            leftelement = min(n2-1,leftelement);

            % distance to the left hand element
            dleft = abs(sorted_data(loc1) - sorted_data(loc2(leftelement)));
            dright = abs(sorted_data(loc1) - sorted_data(loc2(leftelement+1)));

            % find the points which are closer to the left element in data2
            k = (dleft < dright);
            d.distance(ind12(loc1(k))) = dleft(k);
            d.columnindex(ind12(loc1(k))) = ind12(loc2(leftelement(k)));
            k = ~k;
            d.distance(ind12(loc1(k))) = dright(k);
            d.columnindex(ind12(loc1(k))) = ind12(loc2(leftelement(k)+1));

          end % if n2 == 1
        end % if dataflag == 1
      end % if params.Subset(1) == 'f'

      % create the matrix as a sparse one or a struct?
      if params.Result(1)=='a'
        % its an array, so make the array sparse.
        d = sparse(d.rowindex,d.columnindex,d.distance,n1,n2);
      end

    elseif (ntotal>1000) && (((params.Metric == 0) && (params.Subset(1) == 'n')) || ...
        ((params.Metric == inf) && (params.Subset(1) == 'f')))
      % nearest/farthest neighbour in n>1 dimensions, but for an
      % infinity norm metric. Reduce this to a sequence of
      % 1-d problems, each of which will be faster in general.
      % do this only if the problem is moderately large, since
      % we must overcome the extra overhead of the recursive
      % calls to ipdm.

      % do the first dimension
      if dataflag == 1
        d = ipdm(data1(:,1),data1(:,1),'subset',params.Subset,'metric',params.Metric,'result','struct');
      else
        d = ipdm(data1(:,1),data2(:,1),'subset',params.Subset,'metric',params.Metric,'result','struct');
      end

      % its slightly different for nearest versus farthest here
      % now, loop over dimensions
      for i = 2:dim
        if dataflag == 1
          di = ipdm(data1(:,i),data1(:,i),'subset',params.Subset,'metric',params.Metric,'result','struct');
        else
          di = ipdm(data1(:,i),data2(:,i),'subset',params.Subset,'metric',params.Metric,'result','struct');
        end

        % did any of the distances change?
        if params.Metric == 0
          % the 0 norm, with nearest neighbour, so take the
          % smallest distance in any dimension.
          k = d.distance > di.distance;
        else
          % inf norm. so take the largest distance across dimensions
          k = d.distance < di.distance;
        end

        if any(k)
          d.distance(k) = di.distance(k);
          d.columnindex(k) = di.columnindex(k);
        end
      end

      % create the matrix as a sparse one or a struct?
      if params.Result(1)=='a'
        % its an array, so make the array sparse.
        d = sparse(d.rowindex,d.columnindex,d.distance,n1,n2);
      end

    elseif ((ntotal*8) <= params.ChunkSize)
      % None of the other special cases apply, so do it using brute
      % force for the small potatoes problem.

      % One set or two?
      if dataflag == 1
        dist = distcomp(data1,data1,params);
      else
        dist = distcomp(data1,data2,params);
      end

      % if only one data set and if a nearest neighbor
      % problem, set the diagonal to +inf so we don't find it.
      if (dataflag==1) && (n1>1) && ('n'==params.Subset(1))
        diagind = (1:n1) + (0:n1:(n1^2-1));
        dist(diagind) = +inf;
      end

      if ('n'==params.Subset(1))
        % nearest
        [val,j] = min(dist,[],2);
      else
        % farthest
        [val,j] = max(dist,[],2);
      end

      % create the matrix as a sparse one or a struct?
      if params.Result(1)=='a'
        % its an array, so make the array sparse.
        d = sparse((1:n1)',j,val,n1,size(dist,2));
      else
        % a structure
        d.rowindex = (1:n1)';
        d.columnindex = j;
        d.distance = val;
      end

    else

      % break it into chunks
      bs = floor(params.ChunkSize/(8*n2));
      bs = min(n1,max(1,bs));

      % pre-allocate the result
      d.rowindex = (1:n1)';
      d.columnindex = zeros(n1,1);
      d.distance = zeros(n1,1);

      % now loop over the chunks
      batch = 1:bs;
      while ~isempty(batch)

        % One set or two?
        if dataflag == 1
          dist = distcomp(data1(batch,:),data1,params);
        else
          dist = distcomp(data1(batch,:),data2,params);
        end

        % if only one data set and if a nearest neighbor
        % problem, set the diagonal to +inf so we don't find it.
        if (dataflag==1) && (n1>1) && ('n'==params.Subset(1))
          diagind = 1:length(batch);
          diagind = diagind + (diagind-2+batch(1))*length(batch);
          dist(diagind) = +inf;
        end

        % big or small as requested
        if ('n'==params.Subset(1))
          % nearest
          [val,j] = min(dist,[],2);
        else
          % farthest
          [val,j] = max(dist,[],2);
        end

        % and stuff them into the result structure
        d.columnindex(batch) = j;
        d.distance(batch) = val;

        % increment the batch
        batch = batch + bs;
        if batch(end)>n1
          batch(batch>n1) = [];
        end

      end

      % did we need to return a struct or an array?
      if params.Result(1) == 'a'
        % an array. make it a sparse one
        d = sparse(d.rowindex,d.columnindex,d.distance,n1,n2);
      end

    end % if dim == 1

end  % switch params.Subset

% End of mainline

% ======================================================
% begin subfunctions
% ======================================================
function d = distcomp(set1,set2,params)
% Subfunction to compute all distances between two sets of points
dim = size(set1,2);
% can we take advantage of bsxfun?
% Note: in theory, there is no need to loop over the dimensions. We
% could Just let bsxfun do ALL the work, then wrap a sum around the
% outside. In practice, this tends to create large intermediate
% arrays, especially in higher numbers of dimensions. Its also when
% we might gain here by use of a vectorized code. This will only be
% a serious gain when the number of points is relatively small and
% the dimension is large.
if params.usebsxfun
  % its a recent enough version of matlab that we can
  % use bsxfun at all.
  n1 = size(set1,1);
  n2 = size(set2,1);
  if (dim>1) && ((n1*n2*dim)<=params.ChunkSize)
    % its a small enough problem that we might gain by full
    % use of bsxfun
    switch params.Metric
      case 2
        d = sum(bsxfun(@minus,reshape(set1,[n1,1,dim]),reshape(set2,[1,n2,dim])).^2,3);
      case 1
        d = sum(abs(bsxfun(@minus,reshape(set1,[n1,1,dim]),reshape(set2,[1,n2,dim]))),3);
      case inf
        d = max(abs(bsxfun(@minus,reshape(set1,[n1,1,dim]),reshape(set2,[1,n2,dim]))),[],3);
      case 0
        d = min(abs(bsxfun(@minus,reshape(set1,[n1,1,dim]),reshape(set2,[1,n2,dim]))),[],3);
    end
  else
    % too big, so that the ChunkSize will have been exceeded, or just 1-d
    if params.Metric == 2
      d = bsxfun(@minus,set1(:,1),set2(:,1)').^2;
    else
      d = abs(bsxfun(@minus,set1(:,1),set2(:,1)'));
    end
    for i=2:dim
      switch params.Metric
        case 2
          d = d + bsxfun(@minus,set1(:,i),set2(:,i)').^2;
        case 1
          d = d + abs(bsxfun(@minus,set1(:,i),set2(:,i)'));
        case inf
          d = max(d,abs(bsxfun(@minus,set1(:,i),set2(:,i)')));
        case 0
          d = min(d,abs(bsxfun(@minus,set1(:,i),set2(:,i)')));
      end
    end
  end
else
  % Cannot use bsxfun. Sigh. Do things the hard (and slower) way.
  n1 = size(set1,1);
  n2 = size(set2,1);
  if params.Metric == 2
    % Note: While some people might use a different Euclidean
    % norm computation based on expanding the square of the
    % difference of two numbers, that computation is inherantly
    % inaccurate when implemented in floating point arithmetic.
    % While it might be faster, I won't use it here. Sorry.
    d = (repmat(set1(:,1),1,n2) - repmat(set2(:,1)',n1,1)).^2;
  else
    d = abs(repmat(set1(:,1),1,n2) - repmat(set2(:,1)',n1,1));
  end
  for i=2:dim
    switch params.Metric
      case 2
        d = d + (repmat(set1(:,i),1,n2) - repmat(set2(:,i)',n1,1)).^2;
      case 1
        d = d + abs(repmat(set1(:,i),1,n2) - repmat(set2(:,i)',n1,1));
      case inf
        d = max(d,abs(repmat(set1(:,i),1,n2) - repmat(set2(:,i)',n1,1)));
      case 0
        d = min(d,abs(repmat(set1(:,i),1,n2) - repmat(set2(:,i)',n1,1)));
    end
  end
end
% if 2 norm, then we must sqrt at the end
if params.Metric==2
  d = sqrt(d);
end

% ==============================================================
%    end main ipdm
%    begin included function - parse_pv_pairs
% ==============================================================
function params=parse_pv_pairs(params,pv_pairs)
% parse_pv_pairs: parses sets of property value pairs, allows defaults
% usage: params=parse_pv_pairs(default_params,pv_pairs)
%
% arguments: (input)
%  default_params - structure, with one field for every potential
%             property/value pair. Each field will contain the default
%             value for that property. If no default is supplied for a
%             given property, then that field must be empty.
%
%  pv_array - cell array of property/value pairs.
%             Case is ignored when comparing properties to the list
%             of field names. Also, any unambiguous shortening of a
%             field/property name is allowed.
%
% arguments: (output)
%  params   - parameter struct that reflects any updated property/value
%             pairs in the pv_array.
%
% Example usage:
% First, set default values for the parameters. Assume we
% have four parameters that we wish to use optionally in
% the function examplefun.
%
%  - 'viscosity', which will have a default value of 1
%  - 'volume', which will default to 1
%  - 'pie' - which will have default value 3.141592653589793
%  - 'description' - a text field, left empty by default
%
% The first argument to examplefun is one which will always be
% supplied.
%
%   function examplefun(dummyarg1,varargin)
%   params.Viscosity = 1;
%   params.Volume = 1;
%   params.Pie = 3.141592653589793
%
%   params.Description = '';
%   params=parse_pv_pairs(params,varargin);
%   params
%
% Use examplefun, overriding the defaults for 'pie', 'viscosity'
% and 'description'. The 'volume' parameter is left at its default.
%
%   examplefun(rand(10),'vis',10,'pie',3,'Description','Hello world')
%
% params =
%     Viscosity: 10
%        Volume: 1
%           Pie: 3
%   Description: 'Hello world'
%
% Note that capitalization was ignored, and the property 'viscosity'
% was truncated as supplied. Also note that the order the pairs were
% supplied was arbitrary.

npv = length(pv_pairs);
n = npv/2;

if n~=floor(n)
  error 'Property/value pairs must come in PAIRS.'
end
if n<=0
  % just return the defaults
  return
end

if ~isstruct(params)
  error 'No structure for defaults was supplied'
end

% there was at least one pv pair. process any supplied
propnames = fieldnames(params);
lpropnames = lower(propnames);
for i=1:n
  p_i = lower(pv_pairs{2*i-1});
  v_i = pv_pairs{2*i};

  ind = strmatch(p_i,lpropnames,'exact');
  if isempty(ind)
    ind = find(strncmp(p_i,lpropnames,length(p_i)));
    if isempty(ind)
      error(['No matching property found for: ',pv_pairs{2*i-1}])
    elseif length(ind)>1
      error(['Ambiguous property name: ',pv_pairs{2*i-1}])
    end
  end
  p_i = propnames{ind};

  % override the corresponding default in params.
  % Use setfield for comptability issues with older releases.
  params = setfield(params,p_i,v_i); %#ok

end


%% Toolbox differencial calculus - A toolbox to handle differential operators
%
% Copyright (c) 2008 Gabriel Peyre
%

%%
% The toolbox can be downloaded from Matlab Central
% http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=5103&objectType=FILE

%%
% First add to the path additional scripts.
path(path, 'toolbox/');
clear options;

%% Vector Fields
% A vector field |v| is an array of dimension |(n,m,2)|, and |v(:,:,1)| is
% the |x| component of the field, while |v(:,:,2)| is the |y| component

%%
% We can create synthetic fields with sources and vortices.

n = 150; % size of the field
v = load_flow('mixed', n);
% normalize it
v = perform_vf_normalization(v);
% display it
options.subsampling = 5;
clf;
subplot(1,2,1);
options.display_streamlines = 0;
plot_vf( v, [], options );
title('Display with arrows'); axis tight;
subplot(1,2,2);
options.display_streamlines = 1;
plot_vf( v, [], options );
axis xy; axis equal;
title('Display with streamlines'); axis tight;

%%
% One can separate a vector field into a sum of incompressible flow and
% irrotional flow.

% create a random flow
n = 100;
options.bound = 'per';
v = randn(n,n,2);
v = perform_vf_normalization( perform_blurring(v,50) );
% compute the Hodge decomposition
[v1,v2] = compute_hodge_decompositon(v,options);
% display
options.subsampling = 4;
options.display_streamlines = 0;
options.normalize_flow = 1;
options.lgd = { 'Original=Irrot+Incomp' 'Irrotational' 'Incompressible'  };
plot_vf( {v v1 v2}, [], options );

%% Tensor Fields
% A tensor field |T| is an array either of size |(n,m,2,2)|, then
% |T(:,:,i,j)| are the component along axis |i| and |j| of the tensor, or
% an array of size |(n,m,3)|, where we have exploited the fact that the
% tensor is symmetric.

%%
% We can compute the structure tensor of an image, which is derived by
% avergaging the tensor product of the gradient with it self.

%%
% First we load an image.

n = 128;
M = load_image('lena',256);
M = rescale(crop(M,n));

%%
% Then we compute the structure tensor, and display it.
% Each tensor is displayed with a small ellipsoid, whose direction matches
% the direction of the tensor, and color (blue to red) matches its size.

% compute the structure tensor, using an averaging of 8
T = compute_structure_tensor(M,1.5,8);
% we cheat a little for the display, we rescale the tensor field
U = perform_tensor_mapping(T,+1);
U(:,:,1) = perform_histogram_equalization(U(:,:,1), 'linear');
T1 = perform_tensor_mapping(U,-1);
% Display the tensor fields. The color is proportional to the size of the tensor.
clf;
options.sub = 5;
plot_tensor_field(T1, M, options);

%% Image Advection and Fluid Dyamics
% You can compute various things from an image along a vector field.

%%
% Load an image and create a random smooth vector field.

n = 256;
M = load_image('lena',n);
options.bound = 'per';
v = perform_blurring(randn(n,n,2), 40, options);
[tmp,v] = compute_hodge_decompositon(v,options);
v = perform_vf_normalization(v);

%%
% One can perform iterative image advection.

dt = .7; niter = 30;
Ma = M; Msvg = {};
for i=1:niter
    Ma = perform_image_advection(Ma, dt*v, options);
    if mod(i,5)==1
        Msvg{end+1} = Ma;
    end
end
% display
clf;
imageplot(Msvg);

%%
% One can solve the Navier Stockes equations for incompressible fluids
% starting from an image.

n = 128;
M = load_image('lena',256);
M = rescale(crop(M,n));
% initial flow
v = perform_blurring(randn(n,n,2), 40, options);
[tmp,v] = compute_hodge_decompositon(v,options);
v = perform_vf_normalization(v);
% options for the PDE solver
dt = .3;
options.viscosity = 2*dt; % diffusion per frame
options.advspeed = 1*dt; % advection per frame
options.viscosity_texture = .3*dt; % diffusion of the texture
options.texture_histo = 'linear'; % fix the contrast
options.display = 0;
options.niter_fluid = 100;
% solve the PDE
[vlist,A] = perform_fluid_dynamics(v,M,options);
% display
sel = round( linspace(1,size(A,3),6) );
B = mat2cell(A(:,:,sel),n,n,ones(6,1));
clf;
imageplot(B);

%%
% One can perform _Line Integral Convolution_ (LIC), see my image processing toolbox for more
% information.


function unicycle_check ( n, p )

%*****************************************************************************80
%
%% UNICYCLE_CHECK checks that a vector represents a unicycle.
%
%  Discussion:
%
%    A unicycle is a permutation with a single cycle.  This might be called
%    a cyclic permutation, except that that name is used with at least two
%    other meanings.  So, to be clear, a unicycle is a permutation of N
%    objects in which each object is returned to itself precisely after
%    N applications of the permutation.
%
%    This routine verifies that each of the integers from 1
%    to N occurs among the N entries of the permutation.
%
%    Any permutation of the integers 1 to N describes a unicycle.
%    The permutation ( 3, 4, 2, 1 ) indicates that the unicycle
%    sends 3 to 4, 4 to 2, 2 to 1 and 1 to 3.  This is the sequential
%    description of a unicycle.
%
%    The standard sequence "rotates" the permutation so that it begins
%    with 1.  The above sequence becomes a standard sequence when
%    written as ( 1, 3, 4, 2 ).
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    15 June 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the number of entries.
%
%    Input, integer P(N), the unicycle sequence vector.
%
  ierror = 0;

  for iseek = 1 : n

    ierror = iseek;

    for ifind = 1 : n
      if ( p(ifind) == iseek )
        ierror = 0
        break
      end
    end

    if ( ierror ~= 0 )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'UNICYCLE_CHECK - Fatal error!\n' );
      fprintf ( 1, '  The input array does not represent\n' );
      fprintf ( 1, '  a unicycle.  In particular, the\n' );
      fprintf ( 1, '  array is missing the value %d\n', ierror );
      error ( 'UNICYCLE_CHECK - Fatal error!' )
    end

  end

  return
end


function [P, beta] = x2p(X, u, tol)
%X2P Identifies appropriate sigma's to get kk NNs up to some tolerance
%
%   [P, beta] = x2p(xx, kk, tol)
%
% Identifies the required precision (= 1 / variance^2) to obtain a Gaussian
% kernel with a certain uncertainty for every datapoint. The desired
% uncertainty can be specified through the perplexity u (default = 15). The
% desired perplexity is obtained up to some tolerance that can be specified
% by tol (default = 1e-4).
% The function returns the final Gaussian kernel in P, as well as the
% employed precisions per instance in beta.
%

% This file is part of the Matlab Toolbox for Dimensionality Reduction.
% The toolbox can be obtained from http://homepage.tudelft.nl/19j49
% You are free to use, change, or redistribute this code in any way you
% want for non-commercial purposes. However, it is appreciated if you
% maintain the name of the original author.
%
% (C) Laurens van der Maaten, Delft University of Technology

    if ~exist('u', 'var') || isempty(u)
        u = 15;
    end
    if ~exist('tol', 'var') || isempty(tol)
        tol = 1e-4;
    end

    % Initialize some variables
    n = size(X, 1);                     % number of instances
    P = zeros(n, n);                    % empty probability matrix
    beta = ones(n, 1);                  % empty precision vector
    logU = log(u);                      % log of perplexity (= entropy)

    % Compute pairwise distances
%     disp('Computing pairwise distances...');
    D = squareform(pdist(X, 'euclidean') .^ 2);

    % Run over all datapoints
%     disp('Computing P-values...');
    for i=1:n

%         if ~rem(i, 500)
%             disp(['Computed P-values ' num2str(i) ' of ' num2str(n) ' datapoints...']);
%         end

        % Set minimum and maximum values for precision
        betamin = -Inf;
        betamax = Inf;

        % Compute the Gaussian kernel and entropy for the current precision
        Di = D(i, [1:i-1 i+1:end]);
        [H, thisP] = Hbeta(Di, beta(i));

        % Evaluate whether the perplexity is within tolerance
        Hdiff = H - logU;
        tries = 0;
        while abs(Hdiff) > tol && tries < 50

            % If not, increase or decrease precision
            if Hdiff > 0
                betamin = beta(i);
                if isinf(betamax)
                    beta(i) = beta(i) * 2;
                else
                    beta(i) = (beta(i) + betamax) / 2;
                end
            else
                betamax = beta(i);
                if isinf(betamin)
                    beta(i) = beta(i) / 2;
                else
                    beta(i) = (beta(i) + betamin) / 2;
                end
            end

            % Recompute the values
            [H, thisP] = Hbeta(Di, beta(i));
            Hdiff = H - logU;
            tries = tries + 1;
        end

        % Set the final row of P
        P(i, [1:i - 1, i + 1:end]) = thisP;
    end
%     disp(['Mean value of sigma: ' num2str(mean(sqrt(1 ./ beta)))]);
%     disp(['Minimum value of sigma: ' num2str(min(sqrt(1 ./ beta)))]);
%     disp(['Maximum value of sigma: ' num2str(max(sqrt(1 ./ beta)))]);
end

% Function that computes the Gaussian kernel values given a vector of
% squared Euclidean distances, and the precision of the Gaussian kernel.
% The function also computes the perplexity of the distribution.
function [H, P] = Hbeta(D, beta)
    P = exp(-D * beta);
    sumP = sum(P);
    H = log(sumP) + beta * sum(D .* P) / sumP;
    P = P / sumP;
end


function [X,rho,eta,F] = nu(A,b,k,nu,s)
%NU Brakhage's nu-method.
%
% [X,rho,eta,F] = nu(A,b,k,nu,s)
%
% Performs k steps of Brakhage's nu-method for the problem
%    min || A x - b || .
% The routine returns all k solutions, stored as columns of
% the matrix X.  The solution norm and residual norm are returned
% in eta and rho, respectively.
%
% If nu is not specified, nu = .5 is the default value, which gives
% the Chebychev method of Nemirovskii and Polyak.
%
% If the singular values s are also provided, nu computes the
% filter factors associated with each step and stores them
% columnwise in the matrix F.

% Reference: H. Brakhage, "On ill-posed problems and the method of
% conjugate gradients"; in H. W. Engl & G. W. Groetsch, "Inverse and
% Ill-Posed Problems", Academic Press, 1987.

% Martin Hanke, Institut fuer Praktische Mathematik, Universitaet
% Karlsruhe and Per Christian Hansen, IMM, 03/21/92.

% Set parameter.
l_steps = 3;      % Number of Lanczos steps for est. of || A ||.
fudge   = 0.99;   % Scale A and b by fudge/|| A*L_p ||.
fudge_thr = 1e-4; % Used to prevent filter factors from exploding.

% Initialization.
if (k < 1), error('Number of steps k must be positive'), end
if (nargin==3), nu = .5; end
[m,n] = size(A); X = zeros(n,k);
if (nargout > 1)
  rho = zeros(k,1); eta = rho;
end;
if (nargin==5)
  F = zeros(n,k); Fd = zeros(n,1); s = s.^2;
end
V = zeros(n,l_steps); B = zeros(l_steps+1,l_steps);
v = zeros(n,1); eta = zeros(l_steps+1,1);

% Compute a rough estimate of the norm of A by means of a few
% steps of Lanczos bidiagonalization, and scale A and b such
% that || A || is slightly less than one.
beta = norm(b); u = b/beta;
for i=1:l_steps
  r = A'*u - beta*v;
  alpha = norm(r); v = r/alpha;
  B(i,i) = alpha; V(:,i) = v;
  p = A*v - alpha*u;
  beta = norm(p); u = p/beta;
  B(i+1,i) = beta;
end
scale = fudge/norm(B); A = scale*A; b = scale*b;
if (nargin==5), s = scale^2*s; end

% Prepare for iteration.
x = zeros(n,1);
d = A'*b;
r = d;
if (nargout>1), z = b; end

% Iterate.
for j=0:k-1

  % Updates.
  alpha = 4*(j+nu)*(j+nu+0.5)/(j+2*nu)/(j+2*nu+0.5);
  beta  = (j+nu)*(j+1)*(j+0.5)/(j+2*nu)/(j+2*nu+0.5)/(j+nu+1);
  Ad = A*d; AAd = A'*Ad;
  x  = x + alpha*d;
  r  = r - alpha*AAd;
  d  = r + beta*d;
  X(:,j+1) = x;
  if (nargout>1)
    z = z - alpha*Ad; rho(j+1) = norm(z)/scale;
  end;
  if (nargout>2), eta(j+1) = norm(x); end;

  % Filter factors.
  if (nargin==5)
    if (j==0)
      F(:,1) = alpha*s;
      Fd = s - s.*F(:,1) + beta*s;
    else
      F(:,j+1) = F(:,j) + alpha*Fd;
      Fd = s - s.*F(:,j+1) + beta*Fd;
    end
    if (j > 1)
      f = find(abs(F(:,j)-1) < fudge_thr & abs(F(:,j-1)-1) < fudge_thr);
      if ~isempty(f), F(f,j+1) = ones(length(f),1); end
    end
  end

end


function value = r8_invgam_sample ( beta, alpha )

%*****************************************************************************80
%
%% R8_INVGAM_SAMPLE samples an inverse gamma distribution.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    25 June 2013
%
%  Author:
%
%    Original FORTRAN90 version by Guannan Zhang.
%    MATLAB version by John Burkardt.
%
%  Parameters:
%
%    Input, real BETA, the rate parameter.
%    0.0 < BETA.
%
%    Input, real ALPHA, the shape parameter.
%    0.0 < ALPHA.
%
%    Output, real VALUE, a sample value.
%
  value = r8_gamma_sample ( beta, alpha );

  if ( value ~= 0.0 )
    value = 1.0 / value;
  end

  return
end


function [F,G,rho,u,v,p] = EulerFluxes2D(Q, gamma)

% function [F,G,rho,u,v,p] = EulerFluxes2D(Q, gamma)
% Purpose: evaluate primitive variables and Euler flux functions

% extract conserved variables
rho = Q(:,:,1); rhou = Q(:,:,2); rhov = Q(:,:,3); Ener = Q(:,:,4);

% compute primitive variables
u = rhou./rho; v = rhov./rho; p = (gamma-1)*(Ener - 0.5*(rhou.*u + rhov.*v));

% compute flux functions
F = zeros(size(Q));
F(:,:,1) = rhou;
F(:,:,2) = rhou.*u + p;
F(:,:,3) = rhov.*u;
F(:,:,4) = u.*(Ener+p);

G = zeros(size(Q));
G(:,:,1) = rhov;
G(:,:,2) = rhou.*v;
G(:,:,3) = rhov.*v + p;
G(:,:,4) = v.*(Ener+p);
return;


function y = GUSFT_Toeplitz(x,lambda);
% GUSFT_Toeplitz: Gram matrix associated with the nonuniform FT
%  Usage:
%     y = GUSFT_Toeplitz(x,lambda);
%  Inputs:
%    x       vector of length n
%    lambda  Fourier multiplier of length 2n -1
%  Outputs:
%    y       vector of length n
%  Description:
%    Performs A'A where A is the nonuniform FT in the
%    Fourier domain. A'A has a Toeplitz structure which can be
%    embedded in a larger circulant matrix.  Applying A'A is a
%    multiplication in Fourier space with weights lambda. Note that
%    lambda specifies the unequispaced grid).
%  See Also
%    USFT_simple, USFFT, MakeFourierDiagonal
%
% By Emmanuel candes, 2003-2004

  n = length(x);
  extended.x = [x;zeros(n-1,1)];
  y = fft(ifft(extended.x) .* lambda);
  y = y(1:n);


function img = discreteReuleauxRevol(varargin)
%DISCRETEREULEAUXREVOL Discretize the revolution of a Reuleaux triangle
%
%   A Reuleaux triangle is formed by 3 circle arcs, and has the property to
%   have a constant width whatever the  orientation.
%   In 3 dimension, the surface of revolution obtained by rotating a
%   Reuleaux triangle around one of its axis of symetry has also a constant
%   width. The resulting shape looks like a hazelnut.
%
%   IMG = discreteReuleauxRevol(LX, LY, LZ, REULEAUX)
%   REULEAUX is the domaine enclosed by the revolution of a Reuleaux
%   triangle around one of its axis. REULEAUX is defined by:
%   [XC YC ZC R THETA PHI]
%   where (XC, YC, ZC) is the geometric centroid the triangle, R is the
%   radius of the circle arcs, and THETA and PHI define the orientation of
%   the Reuleaux Apex: THETA is the colatitude, between 0 and 180 degrees,
%   and PHI is the azimut, between 0 and 360 degrees.
%
%   IMG = discreteReuleauxRevol(LX, LY, LZ, REULEAUX, D)
%   Use the dilation of a Reuleaux shape by a ball of radius D. The
%   constant diameter of the resulting shape equals R + 2*D.
%
%   IMG = discreteReuleauxRevol(DIM, ...)
%   DIM is the size of image, with the format [x0 dx x1;y0 dy y1;z0 dz z1]
%
%   Examples
%   % Display oriented reuleaux triangle revolution
%     reuleaux = [50 50 50  60  30 40];
%     img = discreteReuleauxRevol(1:100, 1:100, 1:100, reuleaux);
%     figure();
%     isosurface(img, .5);
%     axis equal;
%
%   % The same, with a little bit dilation
%     reuleaux = [50 50 50  60  30 40]
%     img2 = discreteReuleauxRevol(1:100, 1:100, 1:100, reuleaux, 10);
%     figure();
%     isosurface(img2, .5);
%     axis equal;
%
%   % Alternative syntax
%     img = discreteReuleauxRevol([1 1 100;1 1 100;1 1 100], reuleaux);
%
%   See Also
%   imShapes, discreteEllipsoid, discreteTorus, discreteBall
%

%
% ------
% Author: David Legland
% e-mail: david.legland@inra.fr
% Created: 2006-02-27
% Copyright 2006 INRA - CEPIA Nantes - MIAJ (Jouy-en-Josas).

%   HISTORY
%   04/01/2007: concatenate transforms before transforming points
%   04/03/2009: use meshgrid
%   30/04/2009: update transforms
%   29/05/2009: use more possibilities for specifying grid

% compute coordinate of image voxels
[lx, ly, lz, varargin] = parseGridArgs3d(varargin{:});
[x, y, z] = meshgrid(lx, ly, lz);

% parameters of Revolved Reuleaux triangle
reul    = varargin{1};
center  = reul(1:3);
R       = reul(4);
theta   = deg2rad(reul(5));
phi     = deg2rad(reul(6));
varargin(1) = [];

% extract dilation factor if present
dil = 0;
if ~isempty(varargin)
    dil = varargin{1};
end

% top point of triangle
x1  = 0;
y1  = 0;
z1  = 0;

% the height of the triangle
h   = R * sqrt(3) / 2;
dil2 = dil * sqrt(3) / 2;

% create empty image
img = false(size(x));

% transforms voxels according to shape orientation
trans = composeTransforms3d(...
    createTranslation3d(-center),...
    createRotationOz(-phi),...
    createRotationOy(-theta), ...
    createTranslation3d([0 0 h*2/3]));
[x, y, z] = transformPoint3d(x, y, z, trans);

% distance of the points to the revolution axis
rho = hypot(x-x1, y-y1);

% points above the top of the triangle
ind = find((z <= z1) & (z >= z1-dil));
dist = rho(ind).^2 + (z(ind)-z1).^2;
img(ind) = dist <= dil ^ 2;

% points above the basis of the triangle and below the top
ind  = find(z >= z1-dil2 & z <= (z1+h));
dist = (rho(ind)+R/2).^2 + (z(ind)-z1-h).^2;
img(ind) = dist < (R+dil)^2;

% points around the 2 lower corners
dist = (rho-R/2).^2 + (z-z1-h).^2;
img(dist < dil^2) = 1;
ind  = find(z > z1+h & z <= z1+h+dil2);
dist = rho(ind) ;
img(ind(dist < R/2)) = 1;

% points below the basis of the triangle
ind  = find(z >= z1+h+dil2);
dist = rho(ind).^2 + (z(ind)-z1).^2;
img(ind) = dist < (R+dil)^2;


function [s_map1 s_map2 s3] = s3_map(img, show_res)
% Input: img is a gray scale image, in double type, range from 0 - 255.
% You have to convert to gray scale if your image
% is color. You also have to cast img to double in order to run this code
% Parameter show_res = 1 to show results
% Output:
% s_map1: The sharpness map measure based on spectral slope
% s_map2: The sharpness map measure based on total variation (spatial)
% s3: the final sharpness map (combination of s_map1 and s_map2)
if nargin < 2
  show_res = 0;
end

% ----------------------------------------------------------------------
% blr_map1
s_map1 = spectral_map(img, 16);

%-----------------------------------------------------------------------
% blr_map2
s_map21 = spatial_map(img, 8); % Spatial map, blocks start from (1,1)
s_map22 = spatial_map(img, 4); % Spatial map, blocks start from (5,5)
s_map2 = max(s_map21, s_map22);

%-----------------------------------------------------------------------
% combine
s_map1(s_map1 < -99) = 0;
s_map2(s_map2 < -99) = 0;

alpha = 0.5;
s3 = (s_map1.^alpha) .* ((s_map2).^(1-alpha));
if show_res
  figure; imshow(s_map1);
  figure; imshow(s_map2);
  figure; imshow(img/255);
  figure; imshow(s3);
end
end %function

%% Spectral Sharpness, slope of power spectrum
function res = spectral_map(img, pad_len)
blk_size = 32; %big block size for more coefficients of the power spectrum
d_blk = blk_size/4; % Distance b/w blocks

pad_L = fliplr(img(:, 1:pad_len)); % Take 16 columns on the left of the
                                    % original image to pad to the left
pad_R = fliplr(img(:, end-pad_len:end));%Take 16 columns on the right of the
                                        % original image to pad to the
                                        % right
img = [pad_L img pad_R]; %Pad left and right

pad_T = flipud(img(1:pad_len, :)); %Similarly, pad top and bottom
pad_B = flipud(img(end-pad_len:end, :));
img = [pad_T; img; pad_B];

num_rows = size(img, 1);
num_cols = size(img, 2);
res = zeros(num_rows, num_cols) - 100;
contrast_thresold = 0;

%disp_progress; % Just to show progress
for r = blk_size/2+1:d_blk:num_rows-blk_size/2 % Just start from inside blocks
                                                % of the padded image
  %disp_progress(r, num_rows);
  for c = blk_size/2+1:d_blk:num_cols-blk_size/2
    gry_blk = img(...
      r-blk_size/2:r+blk_size/2-1,...
      c-blk_size/2:c+blk_size/2-1 ...
      );
    contrastMap = contrast_map_overlap(gry_blk);
    if(max(contrastMap(:))> contrast_thresold) % Avoid the case when contrast = 0
      val = blk_amp_spec_slope_eo_toy_1(gry_blk); % Val(1) will be the slope of
                                                % power spectrum of the block
      val(1) = 1 - 1 ./ (1 + exp(-3*(val(1) - 2))); %Input to a sigmoid function
      %if(max(gry_blk(:))==min(gry_blk(:))) % Black block
       % val_1 = 0;
      %else
        val_1 = val(1);
      %end
    else
        val_1 = 0;
    end
    res(...
      r-d_blk/2:r+d_blk/2-1,...
      c-d_blk/2:c+d_blk/2-1 ...
      ) = val_1;
  end
end
% Remove padded parts
res = res(pad_len+1:end-pad_len-1, pad_len+1:end-pad_len-1);
end % function

%% ---Spatial Sharpness, local total variation
function res = spatial_map(img, pad_len)
% pad_len = 8 if we dont want to shift img
% pad_len = 4 if we want to shift img by 4;
blk_size = 8;

pad_L = fliplr(img(:, 1:pad_len)); % Take pad_len columns on the left of
                                   % the original image to pad to the left
pad_R = fliplr(img(:, end-pad_len:end));%Take pad_len columns on the right
                                % of the original image to pad to the right
img = [pad_L img pad_R]; %Pad left and right

pad_T = flipud(img(1:pad_len, :)); %Similarly, pad top and bottom
pad_B = flipud(img(end-pad_len:end, :));
img = [pad_T; img; pad_B];

[num_rows, num_cols] = size(img);
res = zeros(num_rows, num_cols);

for r = blk_size/2+1 : blk_size : num_rows-blk_size/2
  for c = blk_size/2+1 : blk_size : num_cols-blk_size/2
    gry_blk = img(...
      r-blk_size/2 : r+blk_size/2-1,...
      c-blk_size/2 : c+blk_size/2-1 ...
      );
    % Measure local total variation for every 2x2 block of gry_blk
    tmp_idx = 1;
    for i = 1 : blk_size - 1
      for j = 1 : blk_size - 1
        tv_tmp(tmp_idx) = (abs(gry_blk(i,j) - gry_blk(i,j+1))...
          + abs(gry_blk(i,j) - gry_blk(i+1,j))...
          + abs(gry_blk(i,j) - gry_blk(i+1,j+1))...
          + abs(gry_blk(i+1,j+1) - gry_blk(i+1,j))...
          + abs(gry_blk(i+1,j) - gry_blk(i,j+1))...
          + abs(gry_blk(i+1,j+1) - gry_blk(i,j+1)))/255; %Each pixel ranges
        %from 0 - 255, so divide by 255 to make it from 0 - 1
        tmp_idx = tmp_idx + 1;
      end
    end

    tv_max = max(tv_tmp) / 4; % Normalize tv_max to be from 0 -1. We can
                              % easily see that the maximum value of total
                              % variation for each 2x2 block is 4, in
                              % blocks like   1 0
                              %               0 1

    res(...
      r - blk_size/2 : r + blk_size/2-1,...
      c - blk_size/2 : c + blk_size/2-1 ...
      ) = tv_max;
  end
end
res = res(pad_len + 1 : end-pad_len - 1, pad_len + 1 : end-pad_len - 1);

end % function


% EX_MAXWELL_SRC_RING: solve Maxwell source problem in one quarter of a ring.

% 1) PHYSICAL DATA OF THE PROBLEM
clear problem_data
% Physical domain, defined as NURBS map given in a text file
problem_data.geo_name = 'geo_ring.txt';

% Type of boundary conditions
problem_data.nmnn_sides   = [];
problem_data.drchlt_sides = [1 2 3 4];

% Physical parameters
problem_data.c_stiff = @(x, y) ones(size(x));
problem_data.c_mass  = @(x, y) ones(size(x));

% Source and boundary terms
problem_data.f = @(x, y) cat(1, ...
             reshape (2*sin(y), [1, size(x)]), ...
             reshape (2*sin(x), [1, size(x)]));
problem_data.g = @(x, y, ind) test_maxwell_ring_g_nmnn (x, y, ind);
problem_data.h = @(x, y, ind) cat(1, ...
                    reshape (sin(y), [1, size(x)]), ...
                    reshape (sin(x), [1, size(x)]));

% Exact solution (optional)
problem_data.uex     = @(x, y) cat(1, ...
                    reshape (sin(y), [1, size(x)]), ...
                    reshape (sin(x), [1, size(x)]));
problem_data.curluex = @(x, y) cos(x) - cos(y);

% 2) CHOICE OF THE DISCRETIZATION PARAMETERS
clear method_data
method_data.degree     = [3 3];     % Degree of the bsplines
method_data.regularity = [2 2];     % Regularity of the splines
method_data.nsub       = [9 9];     % Number of subdivisions
method_data.nquad      = [4 4];     % Points for the Gaussian quadrature rule

% 3) CALL TO THE SOLVER
[geometry, msh, space, u] = solve_maxwell_src (problem_data, method_data);

% 4) POST-PROCESSING
% 4.1) EXPORT TO PARAVIEW
output_file = 'maxwell_ring_Deg3_Reg2_Sub9';

vtk_pts = {linspace(0, 1, 20), linspace(0, 1, 20)};
fprintf ('The result is saved in the file %s \n \n', output_file);
sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'u')

% 4.2) Plot in Matlab. Comparison with the exact solution
[eu, F] = sp_eval (u, space, geometry, vtk_pts);
[X, Y]  = deal (squeeze(F(1,:,:)), squeeze(F(2,:,:)));
eu2     = problem_data.uex (X, Y);

subplot(1,2,1),
quiver (X, Y, squeeze(eu(1,:,:)), squeeze(eu(2,:,:)))
axis equal tight
title('Computed solution')
subplot(1,2,2)
quiver (X, Y, squeeze(eu2(1,:,:)), squeeze(eu2(2,:,:)))
axis equal tight
title('Exact solution')

[error_hcurl, error_l2] = ...
    sp_hcurl_error (space, msh, u, problem_data.uex, problem_data.curluex)

%!demo
%! ex_maxwell_src_ring

%!test
%! problem_data.geo_name = 'geo_ring.txt';
%! problem_data.nmnn_sides   = [];
%! problem_data.drchlt_sides = [1 2 3 4];
%! problem_data.c_stiff = @(x, y) ones(size(x));
%! problem_data.c_mass  = @(x, y) ones(size(x));
%! problem_data.f = @(x, y) cat(1, ...
%!              reshape (2*sin(y), [1, size(x)]), ...
%!              reshape (2*sin(x), [1, size(x)]));
%! problem_data.g = @(x, y, ind) test_maxwell_ring_g_nmnn (x, y, ind);
%! problem_data.h = @(x, y, ind) cat(1, ...
%!                     reshape (sin(y), [1, size(x)]), ...
%!                     reshape (sin(x), [1, size(x)]));
%! problem_data.uex     = @(x, y) cat(1, ...
%!                     reshape (sin(y), [1, size(x)]), ...
%!                     reshape (sin(x), [1, size(x)]));
%! problem_data.curluex = @(x, y) cos(x) - cos(y);
%! method_data.degree     = [3 3];     % Degree of the bsplines
%! method_data.regularity = [2 2];     % Regularity of the splines
%! method_data.nsub       = [9 9];     % Number of subdivisions
%! method_data.nquad      = [4 4];     % Points for the Gaussian quadrature rule
%! [geometry, msh, space, u] = solve_maxwell_src (problem_data, method_data);
%! [error_hcurl, error_l2] = sp_hcurl_error (space, msh, u, problem_data.uex, problem_data.curluex);
%! assert (msh.nel, 81)
%! assert (space.ndof, 264)
%! assert (error_l2, 3.85922857182716e-04, 1e-16)
%! assert (error_hcurl, 5.72616592482421e-04, 1e-16)


function [vx, vy] = vbeta2vxvy(v, beta)

vx = v*cos(beta);
vy = v*sin(beta);


function K = slkernel(varargin)
%SLKERNEL Computes the kernel for samples
%
% $ Syntax $
%   - K = slkernel(X0, kernel_type, ...)
%   - K = slkernel(X0, X, kernel_type, ...)
%
% $ Description $
%   - K = slkernel(X0, kernel_type, ...) Computes the Gram matrix for
%     the samples in matrix X0 using the kernel specified by kernel_type.
%     kernel_type can be name of a built-in kernel type, or the name,
%     handle of an user-specified function. The user-specified function
%     should take in two d x n matrix containing n pairs of vectors, and
%     output a 1 x n vector of their kernel values. The available builtin
%     kernels are given as follows:
%     \*
%     \t   Table 1.  Built-in Kernel Types          \\
%     \h     name     &    description              \\
%           'lin'     &  Linear Kernel:
%                        x1' * x2,
%                        with no parameters         \\
%           'gauss'   &  Gaussian RBF Kernel:
%                        exp(- ||x1 - x2||^2 / (2 * sigma^2)),
%                        with one parameter sigma   \\
%           'poly'    &  Polynomial Kernel:
%                        ((x1' * x2) + a)^k,
%                        with two parameters: k and a \\
%           'sigmoid' &  Sigmoidal Kernel:
%                        tanh(k * (x1' * x2) + a),
%                        with two parameters: k and a \\
%           'invquad' &  Inverse Quadratic Kernel:
%                        1 / sqrt(||x1 - x2||^2 + a),
%                        with one parameter: a        \\
%     \*
%
%   - K = slkernel(X0, X, kernel_type, p1, p2, ...) Computes the empirical
%     kernel mapping for samples X with respect to data set X0. Suppose
%     there are n0 samples in X0, n samples in X, then K will be an n0 * n
%     matrix. Each column in K corresponds to a column in X.
%
% $ History $
%   - Created by Dahua Lin on Jul 13rd, 2005
%   - Modified by Dahua Lin on May 2nd, 2005
%       - base on sltoolbox v4
%       - re-organize the code structure
%       - add the ability of user-specified kernel functions.
%

%% parse and verify input arguments

% for X0
if ~isnumeric(varargin{1})
    error('sltoolbox:invalidarg', ...
        'The first argument should be an numeric matrix');
end
X0 = varargin{1};
if ndims(X0) ~= 2
    error('sltoolbox:invaliddims', ...
        'The X0 should be a 2D matrix');
end

% for X
if isnumeric(varargin{2})
    X = varargin{2};
    if ndims(X) ~= 2
        error('sltoolbox:invaliddims', ...
            'X should be a 2D matrix');
    end
    ipkt = 3;       % argument index of kernel type
else
    X = X0;
    ipkt = 2;
end

% for kernel type
if nargin < ipkt || isempty(varargin{ipkt})
    error('sltoolbox:invalidarg', ...
        'kernel type is not specified');
end
kernel_type = varargin{ipkt};

% for extra parameters
if nargin == ipkt       % no extra parameters
    params = {};
else
    params = varargin(ipkt+1:end);
end

%% Determine the computation routine and delegate to it

% determine for the built-in ones

bik = false;
if ischar(kernel_type)
    switch kernel_type
        case 'lin'
            bik = true;   % bik means built-in kernel
            fh_kernel = @lin_kernel;
        case 'gauss'
            bik = true;
            fh_kernel = @gauss_kernel;
        case 'poly'
            bik = true;
            fh_kernel = @poly_kernel;
        case 'sigmoid'
            bik = true;
            fh_kernel = @sigmoid_kernel;
        case 'invquad'
            bik = true;
            fh_kernel = @invquad_kernel;
    end
end

% delegate
if bik
    K = fh_kernel(X0, X, params{:});
else
    K = slpweval(X0, X, kernel_type, params{:});
end

%% The built-in kernel functions

% Linear Kernel
function K = lin_kernel(X0, X)

K = X0' * X;

% Gaussian Radius Base Function Kernel
function K = gauss_kernel(X0, X, sigma)

D2 = slmetric_pw(X0, X, 'sqdist');
K = exp(- D2 / (2 * sigma * sigma));

% Polynomial Kernel
function K = poly_kernel(X0, X, k, a)

K = (X0' * X + a).^k;

% Sigmoidal Kernel
function K = sigmoid_kernel(X0, X, k, a)

K = tanh(k * (X0' * X) + a);

% Inverse Quadratic Kernel
function K = invquad_kernel(X0, X, a)

D2 = slmetric_pw(X0, X, 'sqdist');
K = 1 ./ sqrt(D2 + a);


function [x,e_conn,index_b] = twod_mesh(x_l, x_r, y_l, y_r, ...
                                        etype, ...
                                        n_nodesx, n_nodesy, ...
                                        fig_num )
%-----------------------------------------------------------------------
%  twod_mesh.m - Generate a rectangular mesh with a prescribed density.
%                This routine returns nodal coordinates, element
%                connectivity, and the nodal indices of boundary nodes.
%
%  Copyright (c) 2001, Jeff Borggaard, Virginia Tech
%  Version: 1.0
%
%  Usage:    [x,e_conn,index_b] = twod_mesh(x_l,x_r,y_l,y_r,etype,...
%                                           n_nodex,n_nodesy,fig_num)
%
%  Variables:     (x_l,y_l)
%                        coordinates of lower left corner
%                 (x_r,y_r)
%                        coordinates of upper right corner
%
%                 etype
%                        element type
%                          'linear', 'quadratic', 'cubic'
%
%                 n_nodesx, n_nodesy
%                        number of nodes in x and y directions
%                        (must be compatible with element type)
%
%                 fig_num  (optional)
%                        specifies the figure number for mesh plot
%    Outputs:
%                 x
%                        node coordinates of mesh
%                 e_conn
%                        element connectivity of mesh
%                 index_b
%                        node numbers of boundary nodes
%-----------------------------------------------------------------------

  if ( strcmp( etype, 'linear' ) )
    %  Generate node coordinates
    dx = (x_r-x_l)/(n_nodesx-1);
    dy = (y_r-y_l)/(n_nodesy-1);
    for i=1:n_nodesx
      for j=1:n_nodesy
        k = i+(j-1)*n_nodesx;
        x(k,1) = x_l + dx*(i-1);
        x(k,2) = y_l + dy*(j-1);
      end
    end

    %  Generate element connectivity
    e_conn = zeros(n_elements, 3);
    ie     = 0;
    for j=1:n_nodesy-1
      for i=1:n_nodesx-1
        ie = ie + 1;
        k = i + (j-1)*n_nodesx;
        e_conn(ie,:) = [k, k+1+n_nodesx, k+n_nodesx];
        ie = ie + 1;
        e_conn(ie,:) = [k, k+1, k+1+n_nodesx];
      end
    end

  elseif ( strcmp( etype, 'quadratic') )
    %  Generate a mesh with quadratic elements
    n_nodes  = n_nodesx*n_nodesy;
    n_elements = 2*(n_nodesx-1)*(n_nodesy-1)/4;

    dx = (x_r-x_l)/(n_nodesx-1);
    dy = (y_r-y_l)/(n_nodesy-1);
    for i=1:n_nodesx
      for j=1:n_nodesy
        k = i+(j-1)*n_nodesx;
        x(k,1) = x_l + dx*(i-1);
        x(k,2) = y_l + dy*(j-1);
      end
    end

    %  Generate element connectivity
    e_conn = zeros(n_elements, 6);
    ie     = 0;
    for j=1:2:n_nodesy-1
      for i=1:2:n_nodesx-1
        ie = ie + 1;
        k = i + (j-1)*n_nodesx;
        e_conn(ie,:) = [k, k+2+2*n_nodesx, k+2*n_nodesx, ...
                        k + 1 + n_nodesx, k+1+2*n_nodesx, k+n_nodesx ];
        ie = ie + 1;
        e_conn(ie,:) = [k, k+2, k+2+2*n_nodesx, ...
                        k+1, k+2+n_nodesx, k+1+n_nodesx ];
      end
    end

  elseif ( strcmp( etype, 'cubic' ) )
    error('twod_mesh: cubic elements are not currently implemented\n')
  else
    error('twod_mesh: etype is not a valid string\n')
  end

  if ( nargout==3 )
    index_b = [ 2:n_nodesx-1, ...
               1:n_nodesx:(n_nodesy-1)*n_nodesx, ...
               n_nodesx:n_nodesx:n_nodesy*n_nodesx, ...
               (n_nodesy-1)*n_nodesx+1:n_nodes-1 ];
  end

  if ( nargin==8 )
    twod_plotm2(fig_num,x,e_conn,'+')
  end


function [ y, m, d, f ] = jed_to_ymdf_hindu_solar ( jed )

%*****************************************************************************80
%
%% JED_TO_YMDF_HINDU_SOLAR converts a JED to a Hindu solar YMDF date.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    12 March 2013
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Edward Reingold, Nachum Dershowitz, Stewart Clamen,
%    Calendrical Calculations, II: Three Historical Calendars,
%    Software - Practice and Experience,
%    Volume 23, Number 4, pages 383-404, April 1993.
%
%  Parameters:
%
%    Input, real JED, the Julian Ephemeris Date.
%
%    Output, integer Y, M, D, real F, the YMDF date.
%

%
%  Date = JF.
%
  jf = jed;
%
%  Date = JED_EPOCH + JF
%
  jed_epoch = epoch_to_jed_hindu_solar ( );
  jf = jf - jed_epoch;
%
%  Date = JED_EPOCH + Y years + JF
%
  y = floor ( jf / year_length_hindu_solar ( ) );
  jf = jf - floor ( y * year_length_hindu_solar ( ) );
%
%  Date = JED_EPOCH + Y years + ( M - 1 ) months + JF
%
  m = 1 + floor ( jf / month_length_hindu_solar ( ) );
  jf = jf - floor ( ( m - 1 ) * month_length_hindu_solar ( ) );
%
%  Date = JED_EPOCH + Y years + ( M - 1 ) months + ( D - 1 ) days + f
%
  d = floor ( jf ) + 1;
  f = jf - ( d - 1 );

  return
end


% example_2_min_new.m VAR inference with Minnesota Prior
% Author:   Filippo Ferroni and  Fabio Canova
% Date:     27/02/2020, revised  14/10/2020
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Compute  posterior estimate with
% 1) mixed calibrated/estimated Minnesota prior
% 2) optimally chosen  Minnesota prior.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
warning off; clear; close all; clc;

addpath ../../cmintools/
addpath ../../bvartools/

% load Euro data
load Data
y= [IPI HICP CORE Euribor1Y M3 EXRATE];% the variables for the VAR

%% Case 1: Estimation with calibrated Minnesota Prior

lags = 6;
options.max_minn_hyper  = 1;       % start the  optimization routine
BVAR0                    = bvar_(y,lags,options);
pause;

%% Case 2: Estimation with calibrated/ estimated Minnesota Prior
lags = 6;
options.max_minn_hyper  = 1;       % start the  optimization routine
options.minn_prior_tau  = 10;      % set tau
options.index_est       = [3 4];   % hyper-parameters to maximize
options.lb              = [0 0];   % the lower bounds
options.ub              = [20 20]; % the upper bounds
options.max_compute     = 7;       % optimization  by Matlab Simplex
BVAR1                   = bvar_(y,lags,options);
pause;

%% Case 3:  Optimization of one dimension of the Minnesota Prior
%           (without  posterior draws to speed up computations)
%%  3.1 maximization of  tau
clear options
lags = 6;
% setting the default values for the hyperparameters
hyperpara(1)    = 3;		  % tau
hyperpara(2)    = 0.5;		  % decay
hyperpara(3)    = 5;		  % lambda
hyperpara(4)    = 2;		  % mu
hyperpara(5)    = 2;		  % omega
% setting the options
options.index_est	   = 1:1;    % hyper-parameter over which maximize
options.max_compute    = 2;      % maximize  using Matlab fmincon function
options.lb             = 0.8;    % Lower bound
options.ub             = 10;     % Upper bound
[postmode,logmlike,~] = bvar_max_hyper(hyperpara,y,lags,options);
pause;

%% 3.2    Take  optimal value for hyperparameter(1) and compute optimal
%%         values for tau, decay, lambda (without  posterior  draws)
hyperpara(1)            = postmode(1); % use as starting value previous mode
options.index_est       = 1:3;         % set hyper-parameters over which maximize
options.lb              = [0.1 0.1 0.1]; % Lower bounds
options.ub              = [10 10 10];    % Upper bounds
[postmode1,log_dnsty,~] = bvar_max_hyper(hyperpara,y,lags,options);

%% 3.3  Take  optimal value for hyperparameter(1:3) and compute optimal
%%           values for tau, decay, lambda, mu (without  posterior  draws)

hyperpara(1:3)          = postmode1(1:3); % use as starting value previous mode
options.index_est       = 1:4;         % set hyper-parameters over which maximize
options.lb              = [0.1 0.1 0.1 0.1]; % Lower bounds
options.ub              = [10 10 10 10];    % Upper bounds
[postmode,log_dnsty1,~] = bvar_max_hyper(hyperpara,y,lags,options);
% then run BVAR with  optimal  parameters
BVAR2                   = bvar_(y,lags,options);

%Plotting cholesky responses  to  Monetary  policy  shocks
% Define the IRF of Interest
indx_sho              = 4;
% Change the order of the variables for the plot
indx_var              = [4, 1, 2, 3];

% % IRFs to PLOT: compare different max hyperparam
mltple_irfs_to_plot_all(:,:,1,:) = BVAR0.ir_draws(indx_var,:,indx_sho,:);
mltple_irfs_to_plot_all(:,:,2,:) = BVAR1.ir_draws(indx_var,:,indx_sho,:);
mltple_irfs_to_plot_all(:,:,3,:) = BVAR2.ir_draws(indx_var,:,indx_sho,:);

% Customize the plot
% variables names for the plots
options.varnames      = {'1 year rate','IP','HICP','CORE'};
% name of the directory where the figure is saved
options.saveas_dir    = './irfs_plt';
% name of the figure to save
options.saveas_strng  = 'diff_minn_opt';
% name of the shock
options.shocksnames   = {'MP opt1','MP opt2','MP opt3'};
% additional 90% HPD set
options.conf_sig_2    = 0.9;
% the plotting command
plot_all_irfs_(mltple_irfs_to_plot_all,options)


function e=v_rotro2eu(m,r)
%V_ROTRO2EU converts a 3x3 rotation matrix into the corresponding euler angles
% inverse of v_roteu2ro
%     M        a string of n characters from the set determining the order of rotation axes
%              as listed below. Note that the control characters 'rdoOaA' may occur anywhere in the string:
%                'x','y','z'    rotate around the given axis by the corresponding angle
%                               given in e()
%                '1','2','3'    90 degree rotation around x,y or z axis; doesn't use a value from e()
%                '4','5','6'    180 degree rotation around x,y or z axis; doesn't use a value from e()
%                '7','8','9'    270 degree rotation around x,y or z axis; doesn't use a value from e()
%                'r','d'        all angles are given in radians or degrees  [default='r']
%                'R','D'        all angles are given in radians or degrees and are negated
%             'o','O','a','A'   selects whether to rotate the object or the coordinate axes and
%                               whether the rotation axes remain fixed in space for consecutive
%                               rotations (extrinsic) or else move with each rotation (intrinsic).
%                                  'o' = object-extrinsic [default]
%                                  'O' = object-intrinsic
%                                  'a' = axes-extrinsic
%                                  'A' = axes-intrinsic
%
%     R(3,3,...)   Input rotation matrix (or array of matrices)
%
% Outputs:
%
%     E(K,...)  K Euler angles in radians (or degrees if 'd' or 'D' specified) per quaternion where K is the number of 'xyz' characters in M.
%               A positive rotation is clockwise if looking along the +ve axis away from the origin or anti-clockwise if 'R' or 'D' is given.
%               The x, y, z axes form a right-handed triple.
%
% The string M specifies the seqeunce of axes about which the rotations are performed. There are 12
% possible 3-character sequences that avoid consecutive repetitions. These are 'Euler angles' if
% there is a repeated axis or 'Tait-Bryan angles' if not. Common choices are:
% (1) 'zxz' the most common Euler angle set
% (2) 'xyz' corresponds to 'roll, pitch, yaw' for an aeroplane heading in the x direction with y to
%     the right and z down. The intrinsic equivalent is 'Ozyx' corresponding to 'yaw, pitch, roll'.
% (3) 'z1z1z' involves 5 rotations, in which all the non-fixed rotations are around the z axis.
%
% The Euler angles are not, in general, unique. In particular:
%  (1) v_roteu2ro('zxz',[a b c]) = v_roteu2ro('zxz',[a+pi -b c+pi])
%  (2) v_roteu2ro('xyz',[a b c]) = v_roteu2ro('xyz',[a+pi pi-b c+pi])

%      Copyright (C) Mike Brookes 2007-2020
%      Version: $Id: v_rotro2eu.m 11260 2020-07-18 20:07:58Z dmb $
%
%   VOICEBOX is a MATLAB toolbox for speech processing.
%   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   This program is free software; you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation; either version 2 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You can obtain a copy of the GNU General Public License from
%   http://www.gnu.org/copyleft/gpl.html or by writing to
%   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
persistent mch mvch rtr rtci rtsi scai w6 th6 x6 pmw
if isempty(mvch)
    mch=''; % cached rotation code string
    mvch=[0;0;1;1;0;0;1];
    rtr=[1 4 7 2 5 8 3 6 9]; % indices to transpose a vectorized 3x3 matrix
    rtci=[2 3 5 6 8 9; 3 1 6 4 9 7; 1 2 4 5 7 8]';
    rtsi=[3 2 6 5 9 8; 1 3 4 6 7 9; 2 1 5 4 8 7]';
    scai=[0 0 0 1; 0 0 0 2; 0 0 0 3; 1 -1 0 1; 1 -1 0 2; 1 -1 0 3; 0 0 -1 1; 0 0 -1 2; 0 0 -1 3; -1 1 0 1; -1 1 0 2; -1 1 0 3]'; % [sin; -sin; cos; xyz] for fixed rotations
    w6=ones(6,1); %
    th6=3*w6;
    x6=[2 1 2 1 2 1]'; % Index for sin components
    pmw=[1; -1];
end

if ~nargout
    v_rotro2qr(r);
else
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Convert the m string
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if ischar(m) && strcmp(m,mch) % check if the rotation code string is cached
        mv=mvch;
    else
        mv=v_roteucode(m); % else decode the string
        mch=m; % and save the result in the cache for next time.
        mvch=mv;
    end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Now calculate euler angles
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    nm=size(mv,2)-1; % number of rotation codes
    sz=size(r);
    r=reshape(r,9,[]); % vectorize the rotation matrices
    nr=size(r,2);                       % number of rotation matrices
    if mv(end)<0
        r=r(rtr,:);                     % transpose rotation matrix
    end
    e=zeros(mv(2,end),nr);              % initialize array of euler angles
    ef=mv(end-3);
    for i=nm:-1:1                       % process rotations in reverse order
        mvi=mv(:,i);
        mi=mvi(1);
        if mi<=3                        % rotation around x,y or z
            if mvi(6)~=0               % skip if this rotation is redundant
                [si,ci,ri,ti]=v_atan2sc(mvi(7)*r(mvi(4),:),mvi(7)*r(mvi(5),:));
                e(mv(2,i),:)=ti*mvi(6)/ef;  % save the euler angle
                si=mvi(6)*pmw*si;          % make -si available and correct sign
                r(rtci(:,mi),:)=ci(w6,:).*r(rtci(:,mi),:)-si(x6,:).*r(rtsi(:,mi),:); % apply reverse rotation
            end
        else % fixed rotation
            ai=scai(4,mi);                      % axis of rotation: 1, 2 or 3
            r(rtci(:,ai),:)=scai(th6,mi).*r(rtci(:,ai),:)-scai(x6,mi).*r(rtsi(:,ai),:); % apply reverse rotation
        end
    end
    if nr>1                                     % if there was >1 input matrix
        e=reshape(e,[size(e,1) sz(3:end)]);     % restore the shape of the Euler angle array
    end
end


function r8mat_trace_test ( )

%*****************************************************************************80
%
%% R8MAT_TRACE_TEST tests R8MAT_TRACE.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    19 April 2009
%
%  Author:
%
%    John Burkardt
%
  n = 4;

  for i = 1 : n
    for j = 1 : n

      if ( i <= j )
        a(i,j) = n + 1 - j;
      elseif ( j == i - 1 )
        a(i,j) = n - j;
      else
        a(i,j) = 0.0;
      end

    end
  end

  fprintf ( 1, '\n' );
  fprintf ( 1, 'R8MAT_TRACE_TEST\n' );
  fprintf ( 1, '  R8MAT_TRACE computes the trace of a matrix\n' );

  r8mat_print ( n, n, a, '  Matrix:' );

  trace = r8mat_trace ( n, a );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Trace is %f\n', trace );

  return
end


function ax = axis_pct(pct)
% AXIS_PCT       Set reasonable axis limits.
% AXIS_PCT(pct) sets axis limits to extend pct% beyond limits of plotted
% objects.  Default is 5%.
% Works for linear or log scale.
% Unfortunately, the axes won't change when new points are plotted.

if nargin < 1
  pct = 0.05;
end
ax = [Inf -Inf Inf -Inf Inf -Inf];

% find bounding box of plotted objects
children = get(gca,'children');
for child = children'
  if strcmp(get(child,'type'),'text')
    xyz = get(child,'position');
    % need to determine bounding box of the text
    c([1 2]) = xyz(1);
    c([3 4]) = xyz(2);
    c([5 6]) = xyz(3);
  else
    x = get(child,'xdata');
    c(1) = min(x);
    c(2) = max(x);
    y = get(child,'ydata');
    c(3) = min(y);
    c(4) = max(y);
    z = get(child,'zdata');
    if isempty(z)
      c([5 6]) = 0;
    else
      c(5) = min(z);
      c(6) = max(z);
    end
  end
  ax([1 3 5]) = min(ax([1 3 5]), c([1 3 5]));
  ax([2 4 6]) = max(ax([2 4 6]), c([2 4 6]));
end
if strcmp(get(gca,'xscale'), 'log')
  ax([1 2]) = log(ax([1 2]));
end
if strcmp(get(gca,'yscale'), 'log')
  ax([3 4]) = log(ax([3 4]));
end
dx = ax(2)-ax(1);
if dx == 0
  dx = 1;
end
dy = ax(4)-ax(3);
if dy == 0
  dy = 1;
end
dz = ax(6)-ax(5);
if dz == 0
  dz = 1;
end
ax = ax + [-dx dx -dy dy -dz dz]*pct;
if strcmp(get(gca,'xscale'), 'log')
  ax([1 2]) = exp(ax([1 2]));
end
if strcmp(get(gca,'yscale'), 'log')
  ax([3 4]) = exp(ax([3 4]));
end
% clip for 2D
ax = ax(1:length(axis));
axis(ax);
if nargout < 1
  clear ax
end


function [fx,dF_dX,dF_dTheta] = f_vanDerPol(Xt,Theta,ut,inF)
% evolution function for the Van Der Pol (limit cycle) oscillator.
% function [fx,dF_dX,dF_dTheta,d2F_dXdTheta] = f_vanDerPol(Xt,Theta,ut,inF)
% IN:
%   - Xt: current hidden state
%   - Theta: evolution parameter
%   - ut: current input to the system
%   - in: user-defined input structure (containing the time decimation)
% OUT:
%   - fx: the predicted hidden state
%   - dF_dX: the jacobian of the system
%   - dF_dTheta: the derivative of the evolution function w.r.t the
%   evolution parameters

deltat = inF.deltat;

x       = Xt;
mu       = Theta(1);

fx      = zeros(2,1);
fx(1)   = x(2);
fx(2)   = mu.*(1-x(1).^2).*x(2) - x(1);
fx      = deltat.*fx + x;

J       = zeros(2,2);
J(1,:)  = [0,1];
J(2,:)  = [-2.*mu.*x(1).*x(2)-1,mu.*(1-x(1).^2)];
dF_dX   = deltat.*J';

dF_dTheta           = zeros(1,2);
dF_dTheta(1,:)      = [0,(1-x(1).^2).*x(2)];
dF_dTheta           = deltat.*dF_dTheta;


function [D, ni] = find_nn(X, k)
%FIND_NN Finds k nearest neigbors for all datapoints in the dataset
%
%	[D, ni] = find_nn(X, k)
%
% Finds the k nearest neighbors for all datapoints in the dataset X.
% In X, rows correspond to the observations and columns to the
% dimensions. The value of k is the number of neighbors that is
% stored. The function returns a sparse distance matrix D, in which
% only the distances to the k nearest neighbors are stored. For
% equal datapoints, the distance is set to a tolerance value.
% The method is relatively slow, but has a memory requirement of O(nk).
%
%

% This file is part of the Matlab Toolbox for Dimensionality Reduction.
% The toolbox can be obtained from http://homepage.tudelft.nl/19j49
% You are free to use, change, or redistribute this code in any way you
% want for non-commercial purposes. However, it is appreciated if you
% maintain the name of the original author.
%
% (C) Laurens van der Maaten, Delft University of Technology

	if ~exist('k', 'var') || isempty(k)
		k = 12;
    end

    % Perform adaptive neighborhood selection if desired
    if ischar(k)
        [D, max_k] = find_nn_adaptive(X);
        ni = zeros(size(X, 1), max_k);
        for i=1:size(X, 1)
            tmp = find(D(i,:) ~= 0);
            tmp(tmp == i) = [];
            tmp = [tmp(2:end) zeros(1, max_k - length(tmp) + 1)];
            ni(i,:) = tmp;
        end

    % Perform normal neighborhood selection
    else

        % Compute distances in batches
        n = size(X, 1);
        sum_X = sum(X .^ 2, 2);
        batch_size = round(2e7 ./ n);
        D = zeros(n, k);
        ni = zeros(n, k);
        for i=1:batch_size:n
            batch_ind = i:min(i + batch_size - 1, n);
            DD = bsxfun(@plus, sum_X', bsxfun(@plus, sum_X(batch_ind), ...
                                                   -2 * (X(batch_ind,:) * X')));
            [DD, ind] = sort(DD, 2, 'ascend');
            D(batch_ind,:) = sqrt(DD(:,2:k + 1));
            ni(batch_ind,:) = ind(:,2:k + 1);
        end
        D(D == 0) = 1e-9;
        D = sparse(repmat(1:n, [1 k])', ni(:), D(:), n, n);
    end


function [x,tspan] = impliciteuler(f,tspan,x0)
%% IMPLICITEULER - Numerical ODE solver: Implicit Euler method
%
% Syntax:
%   [x,tspan] = euler(f,tspan,x0)
%
% In:
%   f      - Function handle, f(x,t)
%   tspan  - Time steps to simulate, [t0,...,tend]
%   x0     - Initial condition
%
% Out:
%   x      - Solved values
%   tspan  - Time steps
%
% Description:
%   Integrates the system of differential equations
%     x' = f(x,t),  for x(0) = x0
%   over the time interval defined in tspan.
%
% Copyright:
%   2018 - Simo Särkkä and Arno Solin
%
% License:
%   This software is provided under the MIT License. See the accompanying
%   LICENSE file for details.

%%

  % Number of steps
  steps = numel(tspan);

  % Allocate space
  x = zeros(size(x0,1),steps);

  % Initial state
  x(:,1) = x0;

  % Iterate
  for k=2:steps

    % Time discretization
    dt = tspan(k)-tspan(k-1);

    % Step solve the algebraic problem
    x(:,k) = fsolve(@(z) x(:,k-1) + f(z,tspan(k))*dt - z, ...
        x(:,k-1), optimset('display','none'));

  end


function pass = test_nonlinSysDampingBreaks_US(pref)
% Test 2x2 system (sin/cos) where damping is required
%
% Asgeir Birkisson, May 2014.

if ( nargin == 0 )
    pref = cheboppref;
end

tol = 1e-10;

%% Piecewise:
d = [-pi 0 pi];
x = chebfun('x',d);
f = [ 0*x ; 0*x ];

%% ULTRAS:
pref.discretization = @ultraS;

A = chebop(@(x,u,v) [u - diff(v,2); diff(u,2) + cos(v)], d);
A.lbc = @(u,v) [u-1/2; v+1/4];
A.rbc = @(u,v) [v-1/4; u+1/2];

[u1, u2, info] = solvebvp(A, f, pref);

% Want to check BCs as well.
bcFunLeft = chebfun(A.lbc(u1,u2));
bcFunRight = chebfun(A.rbc(u1,u2));

% And check that we're continuous over breakpoint
u1jump = jump(u1, 0);
u2jump = jump(u2, 0);

pass(1) = abs(info.error) < tol;
pass(2) = norm(bcFunLeft(d(1))) < tol && norm(bcFunRight(d(end))) < tol;
pass(3) = norm(u1jump) < tol && norm(u2jump) < tol;

end


%%%%%%%VERSION 1

%The Gabor filter is basically a Gaussian (with variances sx and sy along x and y-axes respectively)
%modulated by a complex sinusoid (with centre frequencies U and V along x and y-axes respectively)
%described by the following equation
%%
%               1                -1     x  ^    y  ^
%%% G(x,y) = ---------- * exp ([----{(----) 2+(----) 2}+2*pi*i*(Ux+Vy)])
%            2*pi*sx*sy           2    sx       sy

%% Describtion :

%% I : Input image
%% Sx & Sy : Variances along x and y-axes respectively
%% U & V : Centre frequencies  along x and y-axes respectively

%% G : The output filter as described above
%% gabout : The output filtered image

%%  Author : Ahmad poursaberi  e-mail : a.poursaberi@ece.ut.ac.ir
%%          Faulty of Engineering, Electrical&Computer Department,Tehran
%%          University,Iran,June 2004

function [G,gabout] = gaborfilter(I,Sx,Sy,U,V);
I=imread('G:\eye.jpg');

if isa(I,'double')~=1
    I = double(I);
end

for x = -fix(Sx):fix(Sx)
    for y = -fix(Sy):fix(Sy)
        G(fix(Sx)+x+1,fix(Sy)+y+1) = (1/(2*pi*Sx*Sy))*exp(-.5*((x/Sx)^2+(y/Sy)^2)+2*pi*i*(U*x+V*y));
    end
end

Imgabout = conv2(I,double(imag(G)),'same');
Regabout = conv2(I,double(real(G)),'same');

gabout = uint8(sqrt(Imgabout.*Imgabout + Regabout.*Regabout));


function v = m2v(h,k,l,cs)
% Miller-indece --> cartesian coordinates
% Input
%  h,k,l -
%  cs - crystal symmetry (optional)
%
% Output
%  v - @vector3d

if any(h == 0 & k == 0 & l ==0)
  error('(0,0,0) is not a valid Miller index');
end

a = cs.axes;
V  = dot(a(1),cross(a(2),a(3)));
a_star = cross(a(2),a(3)) ./ V;
b_star = cross(a(3),a(1)) ./ V;
c_star = cross(a(1),a(2)) ./ V;

% reciprocal space
v = h * a_star + k * b_star + l * c_star;
% v = v ./ norm(v);


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%        Sample Data and Metch Registration Sessions        %
%                                                           %
%           by Qianqian Fang <q.fang at neu.edu>            %
%                                                           %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% first of all, make sure you've already add the metch root
% folder to your matlab/octave search path list

% load the sample data, where
%   no: the node coordinates of a surface mesh
%   el: the surface triangles
%   pt: the point cloud to be registered

disp('(*)First load the mesh and point cloud. Hit Enter to continue...');
pause;

load sampledata
if(exist('OCTAVE_VERSION')~=0)
	trimesh(el,no(:,1),no(:,2),no(:,3));
else
	cla;
	trisurf(el,no(:,1),no(:,2),no(:,3));
end
title('Metch toolbox demonstration');
axis equal;
hold on;

% use metch functions to perform the registration

pnum=size(pt,1);

% define a number of point pairs to initialize the registration
disp('(*)Create 4 mapping pairs to initialize the mapping. Hit Enter to continue...');
pause;

% select 4 land-marks on the point cloud (specified by their indicies)
ptidx=[4 107 1 190];
ptselected=pt(ptidx,:);

% find the corresponding land-marks on the mesh
meshidx=[3173 1715 156 1740];
meshselected=no(meshidx,:);

% calculate the affine mapping using these point pairs
[A0,b0]=affinemap(ptselected,meshselected)

disp('(*)Display the updated points. Hit Enter to continue...');
pause;

% a rough registration from the selected point pairs
points_after_initmap=(A0*pt'+repmat(b0(:),1,pnum))';
plot3(points_after_initmap(:,1),points_after_initmap(:,2),points_after_initmap(:,3),'r.');

disp('(*)Optimize the mapping matrix to fit the surface. Hit Enter to continue...');
pause;

% set pmask: if pmask(i) is -1, it is a free nodes to be optimized
%            if pmask(i) is 0, it is fixed
%            if pmask(i) is a positive number, it is the index of
%               the mesh node to map to

pmask=-1*ones(pnum,1);
pmask(ptidx)=meshidx;

% perform mesh registration with Gauss-Newton method using A0/b0
% as initial guess
[A,b,newpos]=regpt2surf(no,el,pt,pmask,A0,b0,ones(12,1),10);
A
b

disp('(*)Display the optimized point cloud. Hit Enter to continue...');
pause;

% update point cloud with the optimized mapping
points_after_optimize=(A*pt'+repmat(b(:),1,pnum))';

plot3(points_after_optimize(:,1),points_after_optimize(:,2),points_after_optimize(:,3),'g+');

disp('(*)Project the point cloud on the surface. Hit Enter to continue...');
pause;

% project the optimized point cloud onto the surface, and make
% sure the comformity

nv=nodesurfnorm(no,el);
[d2surf,cn]=dist2surf(no,nv,points_after_optimize);
[points_after_proj eid weights]=proj2mesh(no,el,points_after_optimize,nv,cn);

disp('(*)Display the final results. Hit Enter to continue...');
pause;

plot3(points_after_proj(:,1),points_after_proj(:,2),points_after_proj(:,3),'c*');

legend('surface mesh','points after initial map','points after optimized map',...
      'points after projection');


function ell = inertiaEllipsoid(points)
%INERTIAELLIPSOID Inertia ellipsoid of a set of 3D points.
%
%   Note: Deprecated! Use equivalentEllipsoid instead.
%
%
%   ELL = inertiaEllipsoid(PTS)
%   Compute the inertia ellipsoid of the set of points PTS. The result is
%   an ellipsoid defined by:
%   ELL = [XC YC ZC A B C PHI THETA PSI]
%   where [XC YC ZY] is the center, [A B C] are lengths of semi-axes (in
%   decreasing order), and [PHI THETA PSI] are euler angles representing
%   the ellipsoid orientation, in degrees.
%
%   Example
%     pts = randn(300, 3);
%     pts = transformPoint3d(pts, createScaling3d([6 4 2]));
%     pts = transformPoint3d(pts, createRotationOx(pi/6));
%     pts = transformPoint3d(pts, createRotationOy(pi/4));
%     pts = transformPoint3d(pts, createRotationOz(pi/3));
%     pts = transformPoint3d(pts, createTranslation3d([5 4 3]));
%     elli = inertiaEllipsoid(pts);
%     figure; drawPoint3d(pts); axis equal;
%     hold on; drawEllipsoid(elli, ...
%         'drawEllipses', true, 'EllipseColor', 'b', 'EllipseWidth', 3);
%
%   See also
%     equivalentEllipsoid
%

% ------
% Author: David Legland
% e-mail: david.legland@inra.fr
% Created: 2011-03-12, using Matlab 7.9.0.529 (R2009b)
% Copyright 2011 INRA - Cepia Software Platform

% deprecation warning
warning('geom3d:deprecated', ...
    [mfilename ' is deprecated, use ''equivalentEllipsoid'' instead']);

% number of points
n = size(points, 1);

% compute centroid
center = mean(points);

% compute the covariance matrix
covPts = cov(points)/n;

% perform a principal component analysis with 2 variables,
% to extract inertia axes
[U, S] = svd(covPts);

% extract length of each semi axis
radii = sqrt(5) * sqrt(diag(S)*n)';

% sort axes from greater to lower
[radii, ind] = sort(radii, 'descend');

% format U to ensure first axis points to positive x direction
U = U(ind, :);
if U(1,1) < 0
    U = -U;
    % keep matrix determinant positive
    U(:,3) = -U(:,3);
end

% convert axes rotation matrix to Euler angles
angles = rotation3dToEulerAngles(U);

% concatenate result to form an ellipsoid object
ell = [center, radii, angles];