<commit_before>/*
 * 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 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2013 <NAME>
 * Written (W) 2011-2013 <NAME>
 * Written (W) 2013 <NAME>
 * Written (W) 2012 <NAME>
 * Written (W) 2010,2012 <NAME>
 * Copyright (C) 2010 Berlin Institute of Technology
 * Copyright (C) 2012 <NAME>
 */

#include <shogun/lib/config.h>
#include <shogun/lib/SGVector.h>
#include <shogun/lib/SGMatrix.h>
#include <shogun/lib/SGSparseVector.h>
#include <shogun/lib/SGReferencedData.h>
#include <shogun/io/File.h>

#include <shogun/mathematics/Math.h>
#include <shogun/mathematics/linalg/LinalgNamespace.h>
#include <shogun/mathematics/lapack.h>
#include <algorithm>

#define COMPLEX128_ERROR_NOARG(function) \
template <> \
void SGVector<complex128_t>::function() \
{ \
	SG_SERROR("SGVector::%s():: Not supported for complex128_t\n",\
		#function);\
}

#define BOOL_ERROR_ONEARG(function) \
template <> \
void SGVector<bool>::function(bool a) \
{ \
	SG_SERROR("SGVector::%s():: Not supported for bool\n",\
		#function);\
}

#define COMPLEX128_ERROR_ONEARG(function) \
template <> \
void SGVector<complex128_t>::function(complex128_t a) \
{ \
	SG_SERROR("SGVector::%s():: Not supported for complex128_t\n",\
		#function);\
}

#define COMPLEX128_ERROR_TWOARGS(function) \
template <> \
void SGVector<complex128_t>::function(complex128_t a, complex128_t b) \
{ \
	SG_SERROR("SGVector::%s():: Not supported for complex128_t\n",\
		#function);\
}

#define COMPLEX128_ERROR_THREEARGS(function) \
template <> \
void SGVector<complex128_t>::function(complex128_t a, complex128_t b,\
	complex128_t c) \
{ \
	SG_SERROR("SGVector::%s():: Not supported for complex128_t\n",\
		#function);\
}

namespace shogun {

template<class T>
SGVector<T>::SGVector() : SGReferencedData()
{
	init_data();
}

template<class T>
SGVector<T>::SGVector(T* v, index_t len, bool ref_counting)
: SGReferencedData(ref_counting), vector(v), vlen(len), gpu_ptr(NULL)
{
	m_on_gpu.store(false, std::memory_order_release);
}

template<class T>
SGVector<T>::SGVector(T* m, index_t len, index_t offset)
: SGReferencedData(false), vector(m+offset), vlen(len)
{
	m_on_gpu.store(false, std::memory_order_release);
}

template<class T>
SGVector<T>::SGVector(index_t len, bool ref_counting)
: SGReferencedData(ref_counting), vlen(len), gpu_ptr(NULL)
{
	vector=SG_CALLOC(T, len);
	m_on_gpu.store(false, std::memory_order_release);
}

template <class T>
SGVector<T>::SGVector(SGMatrix<T> matrix)
	: SGReferencedData(matrix), vlen(matrix.num_cols * matrix.num_rows),
	  gpu_ptr(NULL)
{
	ASSERT(!matrix.on_gpu())
	vector = matrix.data();
	m_on_gpu.store(false, std::memory_order_release);
}

template <class T>
SGVector<T>::SGVector(GPUMemoryBase<T>* gpu_vector, index_t len)
	: SGReferencedData(true), vector(NULL), vlen(len),
	  gpu_ptr(std::shared_ptr<GPUMemoryBase<T>>(gpu_vector))
{
	m_on_gpu.store(true, std::memory_order_release);
}

template <class T>
SGVector<T>::SGVector(std::initializer_list<T> il):
	SGVector(il.begin(), il.end())
{
}

template<class T>
SGVector<T>::SGVector(const SGVector &orig) : SGReferencedData(orig)
{
	copy_data(orig);
}

template<class T>
SGVector<T>& SGVector<T>::operator=(const SGVector<T>& other)
{
	if(&other == this)
	return *this;

	unref();
	copy_data(other);
	copy_refcount(other);
	ref();
	return *this;
}

template<class T>
void SGVector<T>::set(SGVector<T> orig)
{
	*this = SGVector<T>(orig);
}

template<class T>
SGVector<T>::~SGVector()
{
	unref();
}

template <class T>
SGVector<T>::SGVector(EigenVectorXt& vec)
: SGReferencedData(false), vector(vec.data()), vlen(vec.size()), gpu_ptr(NULL)
{
	m_on_gpu.store(false, std::memory_order_release);
}

template <class T>
SGVector<T>::SGVector(EigenRowVectorXt& vec)
: SGReferencedData(false), vector(vec.data()), vlen(vec.size()), gpu_ptr(NULL)
{
	m_on_gpu.store(false, std::memory_order_release);
}

template <class T>
SGVector<T>::operator EigenVectorXtMap() const
{
	assert_on_cpu();
	return EigenVectorXtMap(vector, vlen);
}

template <class T>
SGVector<T>::operator EigenRowVectorXtMap() const
{
	assert_on_cpu();
	return EigenRowVectorXtMap(vector, vlen);
}

template<class T>
void SGVector<T>::zero()
{
	assert_on_cpu();
	if (vector && vlen)
		set_const(0);
}

template <>
void SGVector<complex128_t>::zero()
{
	assert_on_cpu();
	if (vector && vlen)
		set_const(complex128_t(0.0));
}

template<class T>
void SGVector<T>::set_const(T const_elem)
{
	assert_on_cpu();
	for (index_t i=0; i<vlen; i++)
		vector[i]=const_elem ;
}

#if HAVE_CATLAS
template<>
void SGVector<float64_t>::set_const(float64_t const_elem)
{
	assert_on_cpu();
	catlas_dset(vlen, const_elem, vector, 1);
}

template<>
void SGVector<float32_t>::set_const(float32_t const_elem)
{
	assert_on_cpu();
	catlas_sset(vlen, const_elem, vector, 1);
}
#endif // HAVE_CATLAS

template<class T>
void SGVector<T>::range_fill(T start)
{
	assert_on_cpu();
	range_fill_vector(vector, vlen, start);
}

COMPLEX128_ERROR_ONEARG(range_fill)

template<class T>
void SGVector<T>::random(T min_value, T max_value)
{
	assert_on_cpu();
	random_vector(vector, vlen, min_value, max_value);
}

COMPLEX128_ERROR_TWOARGS(random)

template <class T>
index_t SGVector<T>::find_position_to_insert(T element)
{
	assert_on_cpu();
	index_t i;
	for (i=0; i<vlen; ++i)
	{
		if (vector[i]>element)
			break;
	}
	return i;
}

template <>
index_t SGVector<complex128_t>::find_position_to_insert(complex128_t element)
{
	SG_SERROR("SGVector::find_position_to_insert():: \
		Not supported for complex128_t\n");
	return index_t(-1);
}

template<class T>
SGVector<T> SGVector<T>::clone() const
{
	if (on_gpu())
		return SGVector<T>(gpu_ptr->clone_vector(gpu_ptr.get(), vlen), vlen);
	else
		return SGVector<T>(clone_vector(vector, vlen), vlen);
}

template<class T>
T* SGVector<T>::clone_vector(const T* vec, int32_t len)
{
	T* result = SG_MALLOC(T, len);
	sg_memcpy(result, vec, sizeof(T)*len);
	return result;
}

template<class T>
void SGVector<T>::fill_vector(T* vec, int32_t len, T value)
{
	for (int32_t i=0; i<len; i++)
		vec[i]=value;
}

template<class T>
void SGVector<T>::range_fill_vector(T* vec, int32_t len, T start)
{
	for (int32_t i=0; i<len; i++)
		vec[i]=i+start;
}

template <>
void SGVector<complex128_t>::range_fill_vector(complex128_t* vec,
	int32_t len, complex128_t start)
{
	SG_SERROR("SGVector::range_fill_vector():: \
		Not supported for complex128_t\n");
}

template<class T>
void SGVector<T>::resize_vector(int32_t n)
{
	assert_on_cpu();
	vector=SG_REALLOC(T, vector, vlen, n);

	if (n > vlen)
		memset(&vector[vlen], 0, (n-vlen)*sizeof(T));
	vlen=n;
}

/** addition operator */
template<class T>
SGVector<T> SGVector<T>::operator+ (SGVector<T> x)
{
	assert_on_cpu();
	REQUIRE(x.vector && vector, "Addition possible for only non-null vectors.\n");
	REQUIRE(x.vlen == vlen, "Length of the two vectors to be added should be same. [V(%d) + V(%d)]\n", vlen, x.vlen);

	SGVector<T> result=clone();
	result.add(x);
	return result;
}

template<class T>
void SGVector<T>::add(const SGVector<T> x)
{
	assert_on_cpu();
	REQUIRE(x.vector && vector, "Addition possible for only non-null vectors.\n");
	REQUIRE(x.vlen == vlen, "Length of the two vectors to be added should be same. [V(%d) + V(%d)]\n", vlen, x.vlen);

	for (int32_t i=0; i<vlen; i++)
		vector[i]+=x.vector[i];
}

template<class T>
void SGVector<T>::add(const T x)
{
	assert_on_cpu();
	REQUIRE(vector, "Addition possible for only non-null vectors.\n");
	for (int32_t i=0; i<vlen; i++)
		vector[i]+=x;
}

template<class T>
void SGVector<T>::add(const SGSparseVector<T>& x)
{
	assert_on_cpu();
	if (x.features)
	{
		for (int32_t i=0; i < x.num_feat_entries; i++)
		{
			index_t idx = x.features[i].feat_index;
			REQUIRE(idx < vlen, "Feature index should be less than %d.\n", vlen);
			vector[idx] += x.features[i].entry;
		}
	}
}

template<class T>
void SGVector<T>::display_size() const
{
	assert_on_cpu();
	SG_SPRINT("SGVector '%p' of size: %d\n", vector, vlen)
}

template<class T>
void SGVector<T>::copy_data(const SGReferencedData &orig)
{
	gpu_ptr=std::shared_ptr<GPUMemoryBase<T>>(((SGVector*)(&orig))->gpu_ptr);
	vector=((SGVector*)(&orig))->vector;
	vlen=((SGVector*)(&orig))->vlen;
	m_on_gpu.store(((SGVector*)(&orig))->m_on_gpu.load(
		std::memory_order_acquire), std::memory_order_release);
}

template<class T>
void SGVector<T>::init_data()
{
	vector=NULL;
	vlen=0;
	gpu_ptr=NULL;
	m_on_gpu.store(false, std::memory_order_release);
}

template<class T>
void SGVector<T>::free_data()
{
	SG_FREE(vector);
	vector=NULL;
	vlen=0;
	gpu_ptr=NULL;
}

template <class T>
bool SGVector<T>::equals(SGVector<T>& other) const
{
	assert_on_cpu();
	if (other.vlen!=vlen)
		return false;

	for (index_t i=0; i<vlen; ++i)
	{
		if (other.vector[i]!=vector[i])
			return false;
	}

	return true;
}

template<class T>
void SGVector<T>::display_vector(const char* name,
		const char* prefix) const
{
	display_vector(vector, vlen, name, prefix);
}

template <class T>
void SGVector<T>::display_vector(const SGVector<T> vector, const char* name,
		const char* prefix)
{
	vector.display_vector(prefix);
}

template <>
void SGVector<bool>::display_vector(const bool* vector, int32_t n, const char* name,
		const char* prefix)
{
	REQUIRE(n>=0, "Vector size can not be negative.\n");<commit_msg>add fequals based equals for floats<commit_after>/*
 * 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 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2013 <NAME>
 * Written (W) 2011-2013 <NAME>
 * Written (W) 2013 <NAME>
 * Written (W) 2012 <NAME>
 * Written (W) 2010,2012 Soeren Sonnenburg
 * Copyright (C) 2010 Berlin Institute of Technology
 * Copyright (C) 2012 Soeren Sonnenburg
 */

#include <shogun/lib/config.h>
#include <shogun/lib/SGVector.h>
#include <shogun/lib/SGMatrix.h>
#include <shogun/lib/SGSparseVector.h>
#include <shogun/lib/SGReferencedData.h>
#include <shogun/io/File.h>

#include <shogun/mathematics/Math.h>
#include <shogun/mathematics/linalg/LinalgNamespace.h>
#include <shogun/mathematics/lapack.h>
#include <algorithm>
#include <limits>

#define COMPLEX128_ERROR_NOARG(function) \
template <> \
void SGVector<complex128_t>::function() \
{ \
	SG_SERROR("SGVector::%s():: Not supported for complex128_t\n",\
		#function);\
}

#define BOOL_ERROR_ONEARG(function) \
template <> \
void SGVector<bool>::function(bool a) \
{ \
	SG_SERROR("SGVector::%s():: Not supported for bool\n",\
		#function);\
}

#define COMPLEX128_ERROR_ONEARG(function) \
template <> \
void SGVector<complex128_t>::function(complex128_t a) \
{ \
	SG_SERROR("SGVector::%s():: Not supported for complex128_t\n",\
		#function);\
}

#define COMPLEX128_ERROR_TWOARGS(function) \
template <> \
void SGVector<complex128_t>::function(complex128_t a, complex128_t b) \
{ \
	SG_SERROR("SGVector::%s():: Not supported for complex128_t\n",\
		#function);\
}

#define COMPLEX128_ERROR_THREEARGS(function) \
template <> \
void SGVector<complex128_t>::function(complex128_t a, complex128_t b,\
	complex128_t c) \
{ \
	SG_SERROR("SGVector::%s():: Not supported for complex128_t\n",\
		#function);\
}

namespace shogun {

template<class T>
SGVector<T>::SGVector() : SGReferencedData()
{
	init_data();
}

template<class T>
SGVector<T>::SGVector(T* v, index_t len, bool ref_counting)
: SGReferencedData(ref_counting), vector(v), vlen(len), gpu_ptr(NULL)
{
	m_on_gpu.store(false, std::memory_order_release);
}

template<class T>
SGVector<T>::SGVector(T* m, index_t len, index_t offset)
: SGReferencedData(false), vector(m+offset), vlen(len)
{
	m_on_gpu.store(false, std::memory_order_release);
}

template<class T>
SGVector<T>::SGVector(index_t len, bool ref_counting)
: SGReferencedData(ref_counting), vlen(len), gpu_ptr(NULL)
{
	vector=SG_CALLOC(T, len);
	m_on_gpu.store(false, std::memory_order_release);
}

template <class T>
SGVector<T>::SGVector(SGMatrix<T> matrix)
	: SGReferencedData(matrix), vlen(matrix.num_cols * matrix.num_rows),
	  gpu_ptr(NULL)
{
	ASSERT(!matrix.on_gpu())
	vector = matrix.data();
	m_on_gpu.store(false, std::memory_order_release);
}

template <class T>
SGVector<T>::SGVector(GPUMemoryBase<T>* gpu_vector, index_t len)
	: SGReferencedData(true), vector(NULL), vlen(len),
	  gpu_ptr(std::shared_ptr<GPUMemoryBase<T>>(gpu_vector))
{
	m_on_gpu.store(true, std::memory_order_release);
}

template <class T>
SGVector<T>::SGVector(std::initializer_list<T> il):
	SGVector(il.begin(), il.end())
{
}

template<class T>
SGVector<T>::SGVector(const SGVector &orig) : SGReferencedData(orig)
{
	copy_data(orig);
}

template<class T>
SGVector<T>& SGVector<T>::operator=(const SGVector<T>& other)
{
	if(&other == this)
	return *this;

	unref();
	copy_data(other);
	copy_refcount(other);
	ref();
	return *this;
}

template<class T>
void SGVector<T>::set(SGVector<T> orig)
{
	*this = SGVector<T>(orig);
}

template<class T>
SGVector<T>::~SGVector()
{
	unref();
}

template <class T>
SGVector<T>::SGVector(EigenVectorXt& vec)
: SGReferencedData(false), vector(vec.data()), vlen(vec.size()), gpu_ptr(NULL)
{
	m_on_gpu.store(false, std::memory_order_release);
}

template <class T>
SGVector<T>::SGVector(EigenRowVectorXt& vec)
: SGReferencedData(false), vector(vec.data()), vlen(vec.size()), gpu_ptr(NULL)
{
	m_on_gpu.store(false, std::memory_order_release);
}

template <class T>
SGVector<T>::operator EigenVectorXtMap() const
{
	assert_on_cpu();
	return EigenVectorXtMap(vector, vlen);
}

template <class T>
SGVector<T>::operator EigenRowVectorXtMap() const
{
	assert_on_cpu();
	return EigenRowVectorXtMap(vector, vlen);
}

template<class T>
void SGVector<T>::zero()
{
	assert_on_cpu();
	if (vector && vlen)
		set_const(0);
}

template <>
void SGVector<complex128_t>::zero()
{
	assert_on_cpu();
	if (vector && vlen)
		set_const(complex128_t(0.0));
}

template<class T>
void SGVector<T>::set_const(T const_elem)
{
	assert_on_cpu();
	for (index_t i=0; i<vlen; i++)
		vector[i]=const_elem ;
}

#if HAVE_CATLAS
template<>
void SGVector<float64_t>::set_const(float64_t const_elem)
{
	assert_on_cpu();
	catlas_dset(vlen, const_elem, vector, 1);
}

template<>
void SGVector<float32_t>::set_const(float32_t const_elem)
{
	assert_on_cpu();
	catlas_sset(vlen, const_elem, vector, 1);
}
#endif // HAVE_CATLAS

template<class T>
void SGVector<T>::range_fill(T start)
{
	assert_on_cpu();
	range_fill_vector(vector, vlen, start);
}

COMPLEX128_ERROR_ONEARG(range_fill)

template<class T>
void SGVector<T>::random(T min_value, T max_value)
{
	assert_on_cpu();
	random_vector(vector, vlen, min_value, max_value);
}

COMPLEX128_ERROR_TWOARGS(random)

template <class T>
index_t SGVector<T>::find_position_to_insert(T element)
{
	assert_on_cpu();
	index_t i;
	for (i=0; i<vlen; ++i)
	{
		if (vector[i]>element)
			break;
	}
	return i;
}

template <>
index_t SGVector<complex128_t>::find_position_to_insert(complex128_t element)
{
	SG_SERROR("SGVector::find_position_to_insert():: \
		Not supported for complex128_t\n");
	return index_t(-1);
}

template<class T>
SGVector<T> SGVector<T>::clone() const
{
	if (on_gpu())
		return SGVector<T>(gpu_ptr->clone_vector(gpu_ptr.get(), vlen), vlen);
	else
		return SGVector<T>(clone_vector(vector, vlen), vlen);
}

template<class T>
T* SGVector<T>::clone_vector(const T* vec, int32_t len)
{
	T* result = SG_MALLOC(T, len);
	sg_memcpy(result, vec, sizeof(T)*len);
	return result;
}

template<class T>
void SGVector<T>::fill_vector(T* vec, int32_t len, T value)
{
	for (int32_t i=0; i<len; i++)
		vec[i]=value;
}

template<class T>
void SGVector<T>::range_fill_vector(T* vec, int32_t len, T start)
{
	for (int32_t i=0; i<len; i++)
		vec[i]=i+start;
}

template <>
void SGVector<complex128_t>::range_fill_vector(complex128_t* vec,
	int32_t len, complex128_t start)
{
	SG_SERROR("SGVector::range_fill_vector():: \
		Not supported for complex128_t\n");
}

template<class T>
void SGVector<T>::resize_vector(int32_t n)
{
	assert_on_cpu();
	vector=SG_REALLOC(T, vector, vlen, n);

	if (n > vlen)
		memset(&vector[vlen], 0, (n-vlen)*sizeof(T));
	vlen=n;
}

/** addition operator */
template<class T>
SGVector<T> SGVector<T>::operator+ (SGVector<T> x)
{
	assert_on_cpu();
	REQUIRE(x.vector && vector, "Addition possible for only non-null vectors.\n");
	REQUIRE(x.vlen == vlen, "Length of the two vectors to be added should be same. [V(%d) + V(%d)]\n", vlen, x.vlen);

	SGVector<T> result=clone();
	result.add(x);
	return result;
}

template<class T>
void SGVector<T>::add(const SGVector<T> x)
{
	assert_on_cpu();
	REQUIRE(x.vector && vector, "Addition possible for only non-null vectors.\n");
	REQUIRE(x.vlen == vlen, "Length of the two vectors to be added should be same. [V(%d) + V(%d)]\n", vlen, x.vlen);

	for (int32_t i=0; i<vlen; i++)
		vector[i]+=x.vector[i];
}

template<class T>
void SGVector<T>::add(const T x)
{
	assert_on_cpu();
	REQUIRE(vector, "Addition possible for only non-null vectors.\n");
	for (int32_t i=0; i<vlen; i++)
		vector[i]+=x;
}

template<class T>
void SGVector<T>::add(const SGSparseVector<T>& x)
{
	assert_on_cpu();
	if (x.features)
	{
		for (int32_t i=0; i < x.num_feat_entries; i++)
		{
			index_t idx = x.features[i].feat_index;
			REQUIRE(idx < vlen, "Feature index should be less than %d.\n", vlen);
			vector[idx] += x.features[i].entry;
		}
	}
}

template<class T>
void SGVector<T>::display_size() const
{
	assert_on_cpu();
	SG_SPRINT("SGVector '%p' of size: %d\n", vector, vlen)
}

template<class T>
void SGVector<T>::copy_data(const SGReferencedData &orig)
{
	gpu_ptr=std::shared_ptr<GPUMemoryBase<T>>(((SGVector*)(&orig))->gpu_ptr);
	vector=((SGVector*)(&orig))->vector;
	vlen=((SGVector*)(&orig))->vlen;
	m_on_gpu.store(((SGVector*)(&orig))->m_on_gpu.load(
		std::memory_order_acquire), std::memory_order_release);
}

template<class T>
void SGVector<T>::init_data()
{
	vector=NULL;
	vlen=0;
	gpu_ptr=NULL;
	m_on_gpu.store(false, std::memory_order_release);
}

template<class T>
void SGVector<T>::free_data()
{
	SG_FREE(vector);
	vector=NULL;
	vlen=0;
	gpu_ptr=NULL;
}

template <class T>
bool SGVector<T>::equals(SGVector<T>& other) const
{
	assert_on_cpu();
	if (other.vlen!=vlen)
		return false;

	for (index_t i=0; i<vlen; ++i)
	{
		if (other.vector[i]!=vector[i])
			return false;
	}

	return true;
}

#ifndef REAL_EQUALS
#define REAL_EQUALS(real_t)	\
	template <>	\
	bool SGVector<real_t>::equals(SGVector<real_t>& other) const	\
	{	\
		assert_on_cpu();	\
		if (other.vlen!=vlen)	\
			return false;	\
			\
		for (index_t i=0; i<vlen; ++i)	\
		{	\
			if (!CMath::fequals(vector[i], other.vector[i], \
					std::numeric_limits<real_t>::epsilon()))	\
				return false;	\
		}	\
		return true;	\
	}
REAL_EQUALS(float32_t)
REAL_EQUALS(float64_t)
REAL_EQUALS(floatmax_t)
#undef REAL_EQUALS
#endif // REAL_EQUALS

template<class T>
void SGVector<T>::display_vector(const char* name,
		const char* prefix) const
{
	display_vector(vector, vlen, name, prefix);
}

template <class T>
void SGVector<T>::display_vector(const SGVector<T> vector, const char* name,
		const char* prefix)
{
	vector.display_vector(prefix);
}

template <>
void SGVector<bool>::display_vector(const bool* vector, int32_t n, const char* name,
		const char* prefix)
{
	REQUIRE(n>=0, "Vector size can not be negative.\n");
{'fraction_non_alphanumeric': 0.16586921850079744, 'fraction_numerical': 0.017955445799248855, 'mean_word_length': 6.03001808318264, 'pattern_counts': {'":': 0, '<': 287, '<?xml version=': 0, '>': 284, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5154420', 'n_tokens_mistral': 8267, 'n_tokens_neox': 7762, 'n_words': 1544}