//
// This file is part of MorphoGraphX - http://www.MorphoGraphX.org
// Copyright (C) 2012-2016 Richard S. Smith and collaborators.
//
// If you use MorphoGraphX in your work, please cite:
//   http://dx.doi.org/10.7554/eLife.05864
//
// MorphoGraphX is free software, and is licensed under under the terms of the 
// GNU General (GPL) Public License version 2.0, http://www.gnu.org/licenses.
// 
#include <Cuda.hpp>
#include <ThrustTypes.hpp>
#include <DistMatrixCuda.hpp>
#include <CachedAlloc.hpp>

#include <thrust/inner_product.h> 
#include <thrust/extrema.h> 

namespace mgx
{
  template int multGPU<DeviceVM3d>(DeviceVM3d *v, double a, DeviceVM3d *r);
  template int multGPU<DeviceVM2d>(DeviceVM2d *v, double a, DeviceVM2d *r);
  template int multGPU<DeviceVM1d>(DeviceVM1d *v, double a, DeviceVM1d *r);
  template int multGPU<DeviceV3d>(DeviceV3d *v, double a, DeviceV3d *r);
  template int multGPU<DeviceV2d>(DeviceV2d *v, double a, DeviceV2d *r);
  template int multGPU<DeviceV1d>(DeviceV1d *v, double a, DeviceV1d *r);

  template int multGPU(DeviceV3d *v1, DeviceV3d *v2, double &r);
  template int multGPU(DeviceV2d *v1, DeviceV2d *v2, double &r);
  template int multGPU(DeviceV1d *v1, DeviceV1d *v2, double &r);

  template int multGPU<DeviceVM3d, DeviceV3d>(DeviceVu *nb, DeviceVM3d *mv, DeviceVM3d *me, DeviceV3d *v, DeviceV3d *r);
  template int multGPU<DeviceVM2d, DeviceV2d>(DeviceVu *nb, DeviceVM2d *mv, DeviceVM2d *me, DeviceV2d *v, DeviceV2d *r);
  template int multGPU<DeviceVM1d, DeviceV1d>(DeviceVu *nb, DeviceVM1d *mv, DeviceVM1d *me, DeviceV1d *v, DeviceV1d *r);

  template int addToDiagGPU<DeviceVM3d>(double a, DeviceVM3d *r);
  template int addToDiagGPU<DeviceVM2d>(double a, DeviceVM2d *r);
  template int addToDiagGPU<DeviceVM1d>(double a, DeviceVM1d *r);

  template int addGPU<DeviceVM3d>(DeviceVM3d *v1, DeviceVM3d *v2, DeviceVM3d *r);
  template int addGPU<DeviceVM2d>(DeviceVM2d *v1, DeviceVM2d *v2, DeviceVM2d *r);
  template int addGPU<DeviceVM1d>(DeviceVM1d *v1, DeviceVM1d *v2, DeviceVM1d *r);

  template int addGPU<DeviceV3d>(DeviceV3d *v1, DeviceV3d *v2, DeviceV3d *r);
  template int addGPU<DeviceV2d>(DeviceV2d *v1, DeviceV2d *v2, DeviceV2d *r);
  template int addGPU<DeviceV1d>(DeviceV1d *v1, DeviceV1d *v2, DeviceV1d *r);

  template int subtractGPU<DeviceVM3d>(DeviceVM3d *v1, DeviceVM3d *v2, DeviceVM3d *r);
  template int subtractGPU<DeviceVM2d>(DeviceVM2d *v1, DeviceVM2d *v2, DeviceVM2d *r);
  template int subtractGPU<DeviceVM1d>(DeviceVM1d *v1, DeviceVM1d *v2, DeviceVM1d *r);

  template int subtractGPU<DeviceV3d>(DeviceV3d *v1, DeviceV3d *v2, DeviceV3d *r);
  template int subtractGPU<DeviceV2d>(DeviceV2d *v1, DeviceV2d *v2, DeviceV2d *r);
  template int subtractGPU<DeviceV1d>(DeviceV1d *v1, DeviceV1d *v2, DeviceV1d *r);

  template int saxpyGPU<DeviceV3d>(DeviceV3d *v1, DeviceV3d *v2, double a, DeviceV3d *r);
  template int saxpyGPU<DeviceV2d>(DeviceV2d *v1, DeviceV2d *v2, double a, DeviceV2d *r);
  template int saxpyGPU<DeviceV1d>(DeviceV1d *v1, DeviceV1d *v2, double a, DeviceV1d *r);

  template int fillGPU<DeviceVM3d>(double a, DeviceVM3d *r);
  template int fillGPU<DeviceVM2d>(double a, DeviceVM2d *r);
  template int fillGPU<DeviceVM1d>(double a, DeviceVM1d *r);

  template int fillGPU<DeviceV3d>(double a, DeviceV3d *r);
  template int fillGPU<DeviceV2d>(double a, DeviceV2d *r);
  template int fillGPU<DeviceV1d>(double a, DeviceV1d *r);

  template int fillGPU<DeviceV3u>(uint a, DeviceV3u *r);

  template int minGPU<DeviceVM3d>(DeviceVM3d *v, double &r);
  template int minGPU<DeviceVM2d>(DeviceVM2d *v, double &r);
  template int minGPU<DeviceVM1d>(DeviceVM1d *v, double &r);

  template int maxGPU<DeviceVM3d>(DeviceVM3d *v, double &r);
  template int maxGPU<DeviceVM2d>(DeviceVM2d *v, double &r);
  template int maxGPU<DeviceVM1d>(DeviceVM1d *v, double &r);

  template int jacobiPreCondGPU<DeviceVM3d>(DeviceVu *nb, DeviceVM3d *mv, DeviceVM3d *me, DeviceVM3d *av, DeviceVM3d *ae);
  template int jacobiPreCondGPU<DeviceVM2d>(DeviceVu *nb, DeviceVM2d *mv, DeviceVM2d *me, DeviceVM2d *av, DeviceVM2d *ae);
  template int jacobiPreCondGPU<DeviceVM1d>(DeviceVu *nb, DeviceVM1d *mv, DeviceVM1d *me, DeviceVM1d *av, DeviceVM1d *ae);
}
