// ----------------------------------------------------------------------------
//
// Copyright (C) Columbia University, 1994. All Rights Reserved.
// Sameer A. Nene, Shree K. Nayar, Hiroshi Murase
//
// See file LICENSE for details of software license agreement.
//
// ----------------------------------------------------------------------------
//
// partialsearch.C
//
// Author:               Sameer Nene
// Date:                 05/26/94
// Version:              1.0
// Modification History:
//   06/26/94: Changes necessary because of change in interface.
//   08/18/94: Fixed bug which was not copying dimensionality info. to dataset
//             inside PartialSearch
//   04/09/96: Fixed scoping problem for compatibility with new ANSI standard
//
// Bugs:
//
// Classes:
//   PartialSearch
//
// Notes:
//   This module contains implementation of classes declared in partialsearch.h
//
// ----------------------------------------------------------------------------

#include <stdio.h>
#include <values.h>
#include "errorscope.h"
#include "registry.h"
#include "persistent.h"
#include "vector.h"
#include "dataset.h"
#include "persscheme.h"
#include "partialsearch.h"

void* PartialSearch::d_protocol = (void*)(&PartialSearch::d_protocol);
char* PartialSearch::d_name_p = "PartialSearch";
Registrar PartialSearch::d_registrar(PartialSearch::d_name_p,
				     &(PartialSearch::createFunc));
				     
Persistent* PartialSearch::createFunc()
{
  return new PartialSearch;
}

PartialSearch::PartialSearch() : d_thresh(.01)
{
}

int PartialSearch::hasProtocol(void* protocol) const
{
  return d_protocol == protocol || PersistentSearchScheme::hasProtocol(protocol);
}

PartialSearch::PartialSearch(const DataSet &ds, const Vector &rangemin,
			     const Vector &rangemax) : d_thresh(.01),
			     d_data(ds.getSize(), ((DataSet&)ds)().getSize()),
			     d_rangemin(rangemin), d_rangemax(rangemax)
{
  int i, j;
  const VectAry &vaSrc = ((DataSet&)ds)();
  VectAry &vaDst = d_data();
  
  for(i = 0, j = vaSrc.getSize(); i < j; ++i)
    vaDst[i] = vaSrc[i];
  for(i = 0, j = ds.getSize(); i < j; ++i)
    d_data.setSize(i, ds.getSize(i));
}

PartialSearch* PartialSearch::safeCast(Persistent *p)
{
  return p -> hasProtocol(d_protocol) ? (PartialSearch*)p : 0;
}

Vector PartialSearch::search(const Vector &v) const
{
  int i, j, k, l, n, *list = new int[l = d_data().getSize()];
  double m, t;
  Vector r(d_data.getSize());
  const VectAry &va = d_data();

  for(k = 0; k < l; ++k)
    list[k] = k;

  for(i = 0, j = v.length(); i < j; ++i, l = n) {
    t = v.element(i);
    for(k = 0, n = 0; k < l; ++k) {
      m = va[list[k]].element(i) - t;
      if(m * m <= d_thresh)
	list[n++] = list[k];
    }
  }
  
  m = MAXDOUBLE;
  for(k = 0; k < l; ++k)
    if((t = va[list[k]].distance(v)) < m) {
      m = t;
      n = list[k];
    }
  
  delete[] list;

  for(i = 0, j = d_data.getSize(), k = 1; i < j; k *= d_data.getSize(i++));

  for(i = 0; i < j; ++i) {
    k /= d_data.getSize(i);
    r.element(i, (n / k) * (d_rangemax.element(i) - d_rangemin.element(i)) /
	      (d_data.getSize(i) - 1.) + d_rangemin.element(i));
    n %= k;
  }
  
  return r;
}

void PartialSearch::setSearchParameters(const Vector &v)
{
  d_thresh = v.element(0) * v.element(0);
}

ErrorScope::Error PartialSearch::get(FILE *file)
{
  ErrorScope::Error error;

  if((error = d_rangemin.get(file)) != OK)
    return error;
  
  if((error = d_rangemax.get(file)) != OK)
    return error;

  if((error = d_data.get(file)) != OK)
    return error;

  return OK;
}

ErrorScope::Error PartialSearch::put(FILE *file) const
{
  ErrorScope::Error error;
  
  if((error = d_rangemin.put(file)) != OK)
    return error;
  
  if((error = d_rangemax.put(file)) != OK)
    return error;

  if((error = d_data.put(file)) != OK)
    return error;

  return OK;
}

const char* PartialSearch::name() const
{
  return d_name_p;
}

const VectAry& PartialSearch::getData() const
{
  return d_data();
}
