用C++写的矩阵处理函数 包括求逆、转置、乘积等等

 

用C++写的矩阵处理函数 包括求逆、转置、乘积等等

 

最近,无论是大学还是小学,都放暑假了。

 

我们本来也应该有暑假的,可是悲催地被老师给残忍剥夺了,只能继续呆在实验室里面苦逼地干活。

 

最近南方天气太热,室外的温度老是挑战40度大关,中午出去吃个饭,回来时身上的衣服都会彻底湿透,在这样的天气里,干活的效率可想而知了。

 

最近在看机器学习和动态贝叶斯网络的书,顺便找了一些源代码来看,看的过程实在痛苦,书上全是多元统计分析的东西,神马狄利克雷分布,贝塔分布,伽马分布,高斯分布...,看一会儿脑袋就大了,这时索性看点代码换换脑子。在众多的动态贝叶斯源码中,有一种是由C++代码写成的,我们知道,在机器学习领域,编码时需要处理很多的高维矩阵运算,这让人(尤其是数学学得不好的人)很是头疼,所幸的是现在有很多语言提供了对这些公式的编码支持,只需要写很少的代码就可以实现复杂的运算,比如Matlab、

Python等,同时,我们也知道如果用C系列的语言,比如C、C++之类的,写这种代码,会写死人的,因为一些矩阵的处理和运算实在是太麻烦。但是,有时候由于各种原因,用这些语言写矩阵运算是不可避免的,所以,掌握一些C系列语言的矩阵运算操作是有必要的。

 

好了,言归正传,我下面贴出源代码,希望对某些人能起到一点的帮助~~

 

后期我会把我写好的注释贴出来,并提供一些可运行的例子,让大家能够直接运行,在编写程序的过程中进行学习。

 

/*
 * mdarray.h
*/

#ifndef MDARRAY_H_
#define MDARRAY_H_

// For Boost serialization
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include "../framework/mocapyexceptions.h"
#include "randomgen.h"
#include "utils.h"


namespace mocapy {

// Forwards
template
class MDArray;




template std::ostream& operator<<(std::ostream&, const MDArray&);

 template T sumvect(std::vector & v);

#define __CLPK_integer int                
#define __CLPK_doublereal double

extern "C" void dgeev_(char *jobvl, char *jobvr, int *n, double *a, int *lda, double *wr, double *wi, double *vl, int *ldvl, double *vr, int *ldvr, double *work, int *lwork, int *info);
extern "C" void dgetrf_(const int*, const int*, double*, const int*, int*, int*);
extern "C" void dgetri_(const int*, double*, const int*, const int*, double*, const int*, int*);

template
class MDArray {
public:
	// Constructors
	MDArray() {};
	MDArray(const MDArray& a) {
		copy(a);
	}
	MDArray(const std::vector & shape) {
		set_shape(shape);
	}

	MDArray(const std::vector & shape) {
	  std::vector sh;
		for (uint i=0; i get_shape() const {
		return shape;
	}
	void set_shape(const std::vector & new_shape, bool reset = true);
	void set_shape(uint a, uint b = INF, uint c = INF, uint d = INF);

	// Getters
	std::vector& get_values() {
		return values;
	}
	std::vector get_values_flat();

	const std::vector get_own_index() {
		return ownIndex;
	}

	MDArray & get_view(const std::vector & indices);
	MDArray& get_view(uint a);
	inline T & get(uint a, uint b);
	inline T & get(uint a, uint b, uint c);
	T get_max();
	void get_max(T & m);
	std::vector get_slice(uint from, uint to);

	// Setters
	void set(uint a, T new_value);
	void set(uint a, uint b, T new_value);
	void set(uint a, uint b, uint c, T new_value);
	void set(uint a, MDArray & new_value);
	void set_values(const std::vector & a);
	void set_values(T * a);

	// set_wildcard assigns specified value to the elements in the index vector.
	// The index vector can have -1 valued indices corresponding to wildcards.
	// e.g. set_wildcard with index=[3,-1,0], value=5, assigns integer value 5
	// to [3,0,0], [3,1,0], [3,2,0], ...
	// There can be an arbitrary number of wildcards.
	void set_wildcard(const std::vector & index, T value, int depth=0);

	// In a 2-dim matrix M, repeat copies 'a' to M[i] for all i
	void repeat(uint s, const std::vector & a);

	void div_inplace(T a);
	void div_inplace(MDArray & a);
	void add_inplace(T a);
	void add_inplace(MDArray & a);
	void add_inplace(std::vector > & a);
	void add_inplace(std::vector & a);
	void sub_inplace(MDArray & a);
	void log_all(); //natural log
	void exp_all(); //natural exp
	void sqr_all(); //square the elements (x*x)
	void sqrt_all(); //square root of the elements (x^.5)
	uint bisect(double b);
	MDArray sumlast();
	void cumsum(bool safe=true);
	void normalize();
	void transpose();
	MDArray swapaxes(uint axis1, uint axis2);
	MDArray moveaxis(uint from, uint to);
	void rnd_cov(uint dim, RandomGen * rg);
	void multiply_inplace(T m);
	void multiply_inplace(MDArray & m);
	inline T dot(MDArray & m);
//	inline vector dot(vector & v);
	inline void mult3(MDArray & m);
	double det();
	double det_old();
//	double determinant2();

	void inv();
	void inv_old();

	//Operators
	friend std::ostream& operator<<  (std::ostream& output, const MDArray& a);
	MDArray& operator=(const MDArray& a);
	inline T & operator[](std::vector & indices);
	inline T & operator[](uint a);
	MDArray operator/(T a);
	MDArray operator+(MDArray & a);
	MDArray operator-(MDArray & a);
	std::vector operator*(std::vector & v);
	MDArray operator*(MDArray & v);

	// Misc.
	void clear();
	uint size();
	bool empty() const;
	void randomize( RandomGen * rg, double maxrnd=1.0, bool thin=false);
	std::vector flat_iterator();
	void flat_array(T* v);
	void clip(double minimum, double maximum);
	void copy(const MDArray & array);
	void copy_cast(const MDArray& array);

	void eye(uint dim, T r = 1);
	void keep_eye();
	void makeRotationMatrix(double angle, MDArray & v);
	void makeRefMatrix(MDArray & u, MDArray & v);
	void makeRotationMatrix(MDArray & u, MDArray & v);

	// Calculate eigen values and vectors of a symmetric matrix
	std::pair, std::vector > > eigen();

    // String representation
	std::string tostring(
        const uint precision=2,
        const uint width=0,
        const std::string sep_field=" ",
        const std::string sep_record="\n",
        const std::string sep_record_outer="\n"
        ) const;

	// Persistence
	friend class boost::serialization::access;
    template
    void serialize(Archive & ar, const unsigned int version);

    friend class MDArray;

protected:
	void initialize(bool reset = true);
	void flat_iterator(std::vector & v);
	void set(std::vector & indices, T new_value, uint index);
	inline T & get(std::vector & indices, uint index);
	MDArray& get_view(const std::vector & indices, uint index);
	void sumlast(MDArray & sumArray, uint sumDim, uint currentDim);
	void cumsum(uint currentDim, uint dimension, bool safe);
	void transpose(double **a, int n);
	void permuteaxes(const std::vector & permutation, std::vector & new_index, MDArray & new_array);
	void CoFactor(double **a, int n, double **b);
	double determinant(double **a, int n);

	MDArray LU(bool & neg, __CLPK_integer *pivots=NULL);

	std::vector*> A;
	std::vector values;
	std::vector ownIndex;
	std::vector shape;
};

// String representation

template
  std::string MDArray::tostring(
        const uint precision,
        const uint width,
        const std::string sep_field,
        const std::string sep_record,
        const std::string sep_record_outer
    ) const
{
    // Create local recursive print function
    struct Local {
         static void recursive_print(
                MDArray a,
                std::ostringstream & os,
                std::string sep_field,
                std::string sep_record,
                std::string sep_record_outer
                )
         {
	   std::vector shape = a.get_shape();
	   int len = shape.size();
	   if (len == 1)
	     {
                // We've reached the last dimension
                int dim = shape[0];
                for (int i=0; i0) { os << std::setw(width); }
    os << std::setprecision(precision); // max precision digits after .
    os << std::fixed; // force use of precision digits after .

    if (empty())
        os << "Empty" << sep_record;
    else
        Local::recursive_print(*this, os, sep_field, sep_record, sep_record_outer);

    return os.str();
}

// *** 	Getting/setting shape ***

template
  void MDArray::set_shape(const std::vector & new_shape, bool reset) {
	clear();
	shape = new_shape;
	initialize(reset);
}

// Syntactic sugar
template
void MDArray::set_shape(uint a, uint b, uint c, uint d) {
  std::vector sh;
  sh.push_back(a);
  if (b < INF) {
    sh.push_back(b);
    if (c < INF)
      sh.push_back(c);
    if (d < INF)
      sh.push_back(d);
    
  }
  
  set_shape(sh);
 }

//*** Getters ***

template
  std::vector MDArray::get_slice(uint from, uint to) {
  std::vector ret;
	for(uint i = from; i != to; i++) {
		ret.push_back(values[i]);
	}
	return ret;
}

template
  std::vector MDArray::get_values_flat() {
  std::vector b = flat_iterator();
  std::vector v;
	for (uint i=0; i
inline T & MDArray::operator[](uint a) {
	assert(get_shape().size() == 1); // Otherwise use the other operators or get_view
	assert(a < values.size());
	return values[a];
}

template
inline T & MDArray::get(uint a, uint b) {
	assert(a < A.size());
	assert(b < A[a]->values.size());
	T & ref = A[a]->values[b];
	return ref;
}

template
inline T & MDArray::get(uint a, uint b, uint c) {
	return this->get_view(a).get(b,c);
}

template
  inline T & MDArray::operator[](std::vector & indices) {
	if (indices.size() == 2) {
		return A[indices.front()]->values[indices.back()];
	}
	else if (indices.empty()) {
		assert(!values.empty());
		return values[0];
	}
	else if (indices.size() == 1) {
		assert(indices.front() < values.size() );
		return values[indices.front()];
	}
	else {
		return get(indices, 0);
	}
}

template
  inline T & MDArray::get(std::vector & indices, uint index) {
	if ((index + 1) == indices.size()) {
		assert(index < indices.size());
		assert(indices[index] < values.size());
		return values[indices[index]];
	} else {
		assert(indexget(indices, index + 1);
	}
}

template
  MDArray& MDArray::get_view(const std::vector & indices) {
	assert(indices.size() <= shape.size());
	if(indices.empty())
		return *this;
	else
		return get_view(indices, 0);
}


template
  MDArray& MDArray::get_view(const std::vector & indices, uint index) {
	if (index == indices.size()) {
		return *this;
	} else {
		assert(index < indices.size());
		assert(indices[index] < A.size());
		return A[indices[index]]->get_view(indices, index + 1);
	}
}

template
MDArray& MDArray::get_view(uint a) {
	assert(a
void MDArray::set(uint a, T new_value) {
	assert(a < values.size());
	values[a] = new_value;
}


template
void MDArray::set(uint a, uint b, T new_value) {
	assert(a < A.size());
	assert(b < A[a]->size());
	A[a]->values[b] = new_value;
}

template
void MDArray::set(uint a, uint b, uint c, T new_value) {
	this->get_view(a).set(b,c,new_value);
}

template
void MDArray::set(uint a, MDArray & new_value) {
	assert(a < A.size());
	A[a]->copy(new_value);
}

template
  void MDArray::set(std::vector & indices, T new_value, uint index) {
	if (index + 1 == indices.size()) {
		assert(!values.empty());
		assert(index < indices.size());
		assert(values.size()> indices[index]);
		values[indices[index]] = new_value;
	} else {
		assert(index < indices.size());
		assert(indices[index] < A.size());
		A[indices[index]]->set(indices, new_value, index + 1);
	}
}

template
  void MDArray::set_values(const std::vector & a) {
  std::vector b = flat_iterator();
	assert(b.size() == a.size());

	for (uint i=0; i
  void MDArray::set_values(T * a) {
  std::vector b = flat_iterator();
  for (uint i=0; i
void MDArray::cumsum(bool safe) {
	uint d = shape.size();
	cumsum(0, d, safe);
}

template
void MDArray::cumsum(uint currentDim, uint dimension, bool safe) {
	if (dimension == currentDim + 1) {
		for (uint i = 1; i < values.size(); i++) {
			values[i] += values[i - 1];
		}
		if (safe) {
			assert(!values.empty());
			uint i=values.size()-1;
			values[i] = INF;
		}
	} else {
		for (uint i = 0; i < A.size(); i++) {
			A[i]->cumsum(currentDim + 1, dimension, safe);
		}
	}
}


// I'm not sure that this works...
// I need to test this! /MP
template
MDArray MDArray::sumlast() {
	assert(!shape.empty());
	uint sumDim = shape.size() - 1;
	MDArray sumArray;
	std::vector sh = shape;
	assert(!sh.empty());
	sh.pop_back();
	sumArray.set_shape(sh);
	sumlast(sumArray, sumDim, 0);
	return sumArray;
}

template
void MDArray::sumlast(MDArray & sumArray, uint sumDim, uint currentDim) {
	if (sumDim == currentDim) {
		assert(!values.empty());
		T sum(0);
		for (uint i = 0; i < values.size(); i++) {
			sum += values[i];
		}
		std::vector indx = ownIndex;
		sumArray.set(indx, sum);
	}

	for (uint i = 0; i < A.size(); i++) {
		A[i]->sumlast(sumArray, sumDim, currentDim + 1);
	}
}

template
void MDArray::log_all() {
	if (shape.size() == 1) {
		for (uint i = 0; i < values.size(); i++) {
			double v = values[i];
			if (v>0)
				values[i] = log(v);
			else
				values[i] = -INF;
		}
	} else {
		for (uint i = 0; i < A.size(); i++) {
			A[i]->log_all();
		}
	}
}

template
void MDArray::exp_all() {
	if (shape.size() == 1) {
		for (uint i = 0; i < values.size(); i++) {
			values[i] = exp(values[i]);
		}
	} else {
		for (uint i = 0; i < A.size(); i++) {
			A[i]->exp_all();
		}
	}
}

template
void MDArray::sqr_all() {
	if (shape.size() == 1) {
		for (uint i = 0; i < values.size(); i++) {
			values[i] = values[i] * values[i];
		}
	} else {
		for (uint i = 0; i < A.size(); i++) {
			A[i]->sqr_all();
		}
	}
}

template
void MDArray::sqrt_all() {
	if (shape.size() == 1) {
		for (uint i = 0; i < values.size(); i++) {
			values[i] = srqt(values[i]);
		}
	} else {
		for (uint i = 0; i < A.size(); i++) {
			A[i]->sqrt_all();
		}
	}
}

template
void MDArray::normalize() {
	if (shape.size() == 1) {
		T sum(0);
		for (uint i = 0; i < values.size(); i++) {
			sum += values[i];
		}

		for (uint i = 0; i < values.size(); i++) {
			if (sum != 0)
				values[i] /= sum;
		}
	} else {
		for (uint i = 0; i < A.size(); i++) {
			A[i]->normalize();
		}
	}
}

template
void MDArray::div_inplace(T m) {
	if (shape.size() == 1) {
		for (uint i = 0; i < values.size(); i++) {
			values[i] /= m;
		}
	} else {
		for (uint i = 0; i < A.size(); i++) {
			A[i]->div_inplace(m);
		}
	}
}



template
void MDArray::div_inplace(MDArray & denum) {
	if (shape.size() == 1) {
	  std::vector & indx = ownIndex;
		for (uint i = 0; i < values.size(); i++) {
			T d = denum.get(indx);
			values[i] /= d;
		}
	} else {
		for (uint i = 0; i < A.size(); i++) {
			A[i]->div_inplace(denum);
		}
	}
}

template
void MDArray::add_inplace(MDArray & a) {
	if (shape.size() == 1) {
		for (uint i = 0; i < values.size(); i++) {
			values[i] += a.values[i];
		}
	} else {
		for (uint i = 0; i < A.size(); i++) {
			MDArray * new_a = a.A[i];
			A[i]->add_inplace(*new_a);
		}
	}
}

template
  void MDArray::add_inplace(std::vector > & a) {
	for (uint i = 0; i < A.size(); i++) {
		MDArray * ref = A[i];
		for (uint j = 0; j < ref->values.size(); j++) {
			ref->values[j] += a[i][j];
		}
	}
}

template
  void MDArray::add_inplace(std::vector & a) {
	for (uint i = 0; i < values.size(); i++) {
		values[i] += a[i];
	}
}


template
void MDArray::sub_inplace(MDArray & a) {
	if (shape.size() == 1) {
		for (uint i = 0; i < values.size(); i++) {
			values[i] -= a.values[i];
		}
	} else {
		for (uint i = 0; i < A.size(); i++) {
			MDArray * new_a = a.A[i];
			A[i]->sub_inplace(*new_a);
		}
	}
}

template
MDArray MDArray::operator+(MDArray & a) {
	MDArray r(*this);
	r.add_inplace(a);
	return r;
}

template
MDArray MDArray::operator-(MDArray & a) {
	MDArray r(*this);
	r.sub_inplace(a);
	return r;
}

template
MDArray MDArray::operator/(T a) {
	MDArray r(*this);
	r.div_inplace(a);
	return r;
}

template
void MDArray::add_inplace(T s) {
	if (shape.size() == 1) {
		for (uint i = 0; i < values.size(); i++) {
			values[i] += s;
		}
	} else {
		for (uint i = 0; i < A.size(); i++) {
			A[i]->add_inplace(s);
		}
	}
}

template
  void MDArray::rnd_cov(uint dim, RandomGen * rg) {
	/*
	 Return a random covariance matrix with shape (dim x dim).
	 From U{http://www.sci.wsu.edu/math/faculty/genz/papers/mvn/node5.html}:

	 These random covariance matrices were generated with a method described in an
	 article by Marsaglia and Olkin, for m = 3, 4, ..., 10. This method
	 consists of the following steps. First, a random lower triangular matrix is
	 generated with entries chosen uniformly from [-1,1]. Then, the rows of this
	 matrix are normalized so that the sum of the squares of the elements in each
	 row add to one. Finally this lower triangular matrix is multiplied by it's
	 transpose, to produce a random covariance matrix.

	 Note:
	 Lower triangular matrix:
	 A matrix which is only defined at (i,j) when i greater than or equal to j.

	 Reference:
	 Marsaglia, G. and Olkin, I. (1984), Generating Correlation Matrices, SIAM
	 Journal of Scientific and Statistical Computing 5, pp. 470-475.
	 */

  std::vector sh_c;
	sh_c.push_back(dim);
	sh_c.push_back(dim);
	MDArray c(sh_c);

	for (uint i = 0; i < dim; i++) {
		for (uint j = 0; j < dim; j++) {
			if (i >= j) {
				double d = rg->get_rand();
				double r = 2.0 * (d - 0.5);
				c.set(i, j, r);
			}
		}
	}
	MDArray d(c);
	d.sqr_all();
	for (uint i = 0; i < dim; i++) {
		MDArray & values = d.get_view(i);
		std::vector & v_values = values.get_values();
		double s = sumvect(v_values);
		MDArray view = c.get_view(i);
		view.multiply_inplace(1.0 / sqrt(s));
		c.set(i, view);
	}
	MDArray cov(c);
	c.transpose();
	cov.multiply_inplace(c);
	copy(cov);
}

template
void MDArray::multiply_inplace(T m) {
	if (shape.size() == 1) {
		for (uint i = 0; i < values.size(); i++) {
			values[i] *= m;
		}
	} else {
		for (uint i = 0; i < A.size(); i++) {
			A[i]->multiply_inplace(m);
		}
	}
}

template
void MDArray::multiply_inplace(MDArray & m) {
	assert(shape.size() == 2);
	assert(m.get_shape().size() == 2);

	uint dim = shape.front();

	MDArray cp(shape);

	for (uint i = 0; i < dim; i++) {
		for (uint j = 0; j < dim; j++) {
			T v = 0;
			for (uint k = 0; k < dim; k++) {
				v += get(i, k) * m.get(k, j);
			}
			cp.set(i, j, v);
		}
	}
	copy(cp);
}

template
void MDArray::transpose() {
	assert(shape.size() == 2);
	uint dim = shape.front();

	for (uint i = 0; i < dim; i++) {
		for (uint j = i + 1; j < dim; j++) {
			T temp = get(i, j);
			set(i, j, get(j, i));
			set(j, i, temp);
		}
	}
}



template
  void printv(std::vector v) {
  std::cout << "{";
  for(uint i=0; i
MDArray MDArray::swapaxes(uint axis1, uint axis2) {
	const uint dims = shape.size();
	assert(axis1 < dims && axis2 < dims);

	if(axis1==axis2) {
		MDArray new_array(*this);
		return new_array;
	}

	// Calculate the new shape vector
	std::vector new_shape(shape);
	new_shape[axis1] = shape[axis2];
	new_shape[axis2] = shape[axis1];

	// Construct the new MDArray
	MDArray new_array(new_shape);

	// Calculate the permutation of the axis
	std::vector permutation;
	for(uint i=0; i new_index(dims);
	permuteaxes(permutation, new_index, new_array);

	return new_array;
}

template
MDArray MDArray::moveaxis(uint from, uint to) {
	const uint dims = shape.size();
	assert(from < dims && to < dims);

	if(from==to) {
		MDArray new_array(*this);
		return new_array;
	}

	// Calculate the inverse permutation of the axis
	std::vector inv_permutation;
	for(uint i=0; i permutation(dims);
	for(uint i=0; i new_shape;
	for(std::vector::iterator axis=inv_permutation.begin(); axis!=inv_permutation.end(); axis++) {
		new_shape.push_back(shape[*axis]);
	}

	// Construct the new MDArray
	MDArray new_array(new_shape);

	// Swap the axis
	std::vector new_index(dims);
	permuteaxes(permutation, new_index, new_array);

	return new_array;
}


// Recursive method to permute the axes of this and return the result in new_array
// It assumes that permutation that 'permutation' is a correct permutation!
template
  void MDArray::permuteaxes(const std::vector & permutation, std::vector & new_index, MDArray & new_array) {
	uint depth = ownIndex.size();
	uint new_depth = permutation[depth];

	// If we are at full depth, copy the value to the new index in the new array
	if (shape.size() == 1) {
		for (uint i = 0; i < values.size(); i++) {
			new_index[new_depth] = i;
			new_array[new_index] = values[i];
		}
	}
	// If we are not at a full depth, set the new index correct and call permute on all sub arrays
	else {
		for (uint i = 0; i < A.size(); i++) {
			new_index[new_depth] = i;
			A[i]->permuteaxes(permutation, new_index, new_array);
		}
	}
}


template
double MDArray::det_old() {
	assert(!shape.empty());
	int n = shape.front();

	double **m = NULL;
	m = (double**) malloc((n) * sizeof(double*));
	for (int i = 0; i < n; i++) {
		m[i] = (double*) malloc((n) * sizeof(double));
	}

	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			double v = get(i, j);
			m[i][j] = v;
		}
	}

	double d = determinant(m, n);

	for (int i = 0; i < n; i++)
		free(m[i]);
	free(m);

	return d;
}



// Recursive definition of determinate using expansion by minors.
template
double MDArray::determinant(double **a, int n) {
	int i, j, j1, j2;
	double det = 0;
	double **m = NULL;

	if (n < 1) { /* Error */
		assert(false);

	} else if (n == 1) { /* Shouldn't get used */
		det = a[0][0];
	} else if (n == 2) {
		det = a[0][0] * a[1][1] - a[1][0] * a[0][1];
	} else {
		det = 0;
		for (j1 = 0; j1 < n; j1++) {
			m = (double**) malloc((n - 1) * sizeof(double *));
			for (i = 0; i < n - 1; i++)
				m[i] = (double*) malloc((n - 1) * sizeof(double));
			for (i = 1; i < n; i++) {
				j2 = 0;
				for (j = 0; j < n; j++) {
					if (j == j1)
						continue;
					m[i - 1][j2] = a[i][j];
					j2++;
				}
			}
			det += pow(-1.0, 1.0 + j1 + 1.0) * a[0][j1] * determinant(m, n - 1);
			for (i = 0; i < n - 1; i++)
				free(m[i]);
			free(m);
		}
	}
	return (det);
}


template
void MDArray::inv_old() {
	assert(!shape.empty());
	int n = shape.front();

	double **m = NULL;
	double **m2 = NULL;
	m = (double**) malloc((n) * sizeof(double*));
	m2 = (double**) malloc((n) * sizeof(double*));
	for (int i = 0; i < n; i++) {
		m[i] = (double*) malloc((n) * sizeof(double));
		m2[i] = (double*) malloc((n) * sizeof(double));
	}

	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			double v = get(i, j);
			m[i][j] = v;
		}
	}

	CoFactor(m, n, m2);
	transpose(m2, n);
	double d = determinant(m, n);

	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			double v = m2[i][j] / d;
			set(i, j, v);
		}
	}
	for (int i = 0; i < n; i++) {
		free(m[i]);
		free(m2[i]);

	}
	free(m);
	free(m2);
}


// Find the cofactor matrix of a square matrix
template
void MDArray::CoFactor(double **a, int n, double **b) {
	int i, j, ii, jj, i1, j1;
	double det;
	double **c;

	c = (double**) malloc((n - 1) * sizeof(double *));
	for (i = 0; i < n - 1; i++)
		c[i] = (double*) malloc((n - 1) * sizeof(double));

	for (j = 0; j < n; j++) {
		for (i = 0; i < n; i++) {

			// Form the adjoint a_ij
			i1 = 0;
			for (ii = 0; ii < n; ii++) {
				if (ii == i)
					continue;
				j1 = 0;
				for (jj = 0; jj < n; jj++) {
					if (jj == j)
						continue;
					c[i1][j1] = a[ii][jj];
					j1++;
				}
				i1++;
			}

			// Calculate the determinate
			det = determinant(c, n - 1);

			// Fill in the elements of the cofactor
			b[i][j] = pow(-1.0, i + j + 2.0) * det;
		}
	}
	for (i = 0; i < n - 1; i++)
		free(c[i]);
	free(c);
}

//   Transpose of a square matrix, do it in place
template
void MDArray::transpose(double **a, int n) {
	int i, j;
	double tmp;

	for (i = 1; i < n; i++) {
		for (j = 0; j < i; j++) {
			tmp = a[i][j];
			a[i][j] = a[j][i];
			a[j][i] = tmp;
		}
	}
}

template
  inline std::vector MDArray::operator*(std::vector & m) {
	assert(shape.size() == 2);
	uint dim = shape.front();

	std::vector r(dim);

	for (uint i = 0; i < dim; i++) {
		T v = 0;
		std::vector & vref = A[i]->values;
		for (uint k = 0; k < dim; k++) {
			v += vref[k] * m[k];
		}
		r[i] = v;
	}
	return r;
}

template
inline MDArray MDArray::operator*(MDArray & m) {
	assert(shape.size() == 2);
	uint dim = shape.front();

	MDArray r;
	r.set_shape(dim);

	for (uint i = 0; i < dim; i++) {
		T v = 0;
		std::vector & vref = A[i]->values;
		for (uint k = 0; k < dim; k++) {
			v += vref[k] * m[k];
		}
		r[i] = v;
	}
	return r;
}




template
inline T MDArray::dot(MDArray & m) {
	T v(0);
	for (uint i = 0; i < m.values.size(); i++) {
		v += values[i] * m.values[i];
	}
	return v;
}

// Multiplication of 3x3 matrices
template
inline void MDArray::mult3(MDArray & m) {
     assert(shape.size() == 2);
     uint dim=shape.front();
     assert(dim == 3 || dim == 1);

     // M*v
     if(dim==1) {
       std::vector vref = A[0]->values; //Need a copy

          for(uint i=0; i cp(shape);

          for (uint i = 0; i < dim; i++) {
	    std::vector & vref = A[i]->values;
               for (uint j = 0; j < dim; j++) {
                    T sum = 0;
                    for (uint k = 0; k < dim; k++) {
                         sum += vref[k] * m.get(k,j);
                    }
                    cp.set(i,j,sum);
               }
          }

          copy(cp);
     }
}

// *** Operators ***

template
  std::ostream& operator<<(std::ostream& output, const MDArray& a) {
	if (a.A.empty()) {
		for (uint i = 0; i < a.values.size(); i++) {
			output << a.values[i] << " ";
		}
	} else {
		for (uint i = 0; i < a.A.size(); i++) {
		  output << "[" << *(a.A[i]) << "]" << std::endl;
		}
	}
	return output;
}

template
MDArray& MDArray::operator= (const MDArray& a) {
	if (this != &a) {
		copy(a);
	}
	return *this;
}

// *** Misc. ***

template
bool MDArray::empty() const {
	return shape.empty();
}

template
void MDArray::copy(const MDArray & array) {
	clear();
	shape = array.shape;
	ownIndex = array.ownIndex;
	values = array.values;
	for (uint i = 0; i < array.A.size(); i++) {
		MDArray* newA = new MDArray ;
		newA->copy(*array.A[i]);
		A.push_back(newA);
	}
}

template
void MDArray::copy_cast(const MDArray& array) {
	clear();
	shape = array.shape;
	ownIndex = array.ownIndex;

	for (uint i=0; i* newA = new MDArray ;
		newA->copy_cast(*array.A[i]);
		A.push_back(newA);
	}
}

template
void MDArray::clear() {
	if (shape.size() > 2) {
		for (uint i = 0; i < A.size(); i++) {
			A[i]->clear();
		}
	}

	for (uint i = 0; i < A.size(); i++) {
		delete A[i];
	}
	A.clear();
	values.clear();
}

template
void MDArray::clip(double minimum, double maximum) {
	if (shape.size() == 1) {
		for (uint i = 0; i < values.size(); i++) {
			values[i] = max(minimum, values[i]);
			values[i] = min(maximum, values[i]);
		}
	} else {
		for (uint i = 0; i < A.size(); i++) {
			A[i]->clip(minimum, maximum);
		}
	}
}

 template
   void MDArray::initialize(bool reset) {
   assert(!shape.empty());
   
   if (shape.size() > 1) {
     std::vector new_shape(shape.size() - 1);
     for (uint i = 1; i < shape.size(); i++) {
       new_shape[i - 1] = shape[i];
     }
     
     for (uint i = 0; i < shape.front(); i++) {
       MDArray* a = new MDArray ;
       a->ownIndex = ownIndex;
       a->ownIndex.push_back(i);
       a->set_shape(new_shape); // also calls initialize
       A.push_back(a);
     }
   }
   
   else if (shape.size() == 1) {
     values.resize(shape.front());
   }
   else {
     assert(shape.empty());
     values.resize(1);
   }
 }
 
template
uint MDArray::size() {
	if (shape.empty())
		return 0;

	uint sz(1);
	for (uint i = 0; i < shape.size(); i++) {
		sz *= shape[i];
	}
	return sz;
}

template
  void MDArray::randomize( RandomGen * rg, double maxrnd, bool thin) {
	if (shape.size() == 1) {
		for (uint i = 0; i < values.size(); i++) {

		  double d = rg->get_rand()*maxrnd;
			if (thin) {
				double x = rg->get_rand();

				if (x<0.7)
					d=0.01*d;
			}


			values[i] = d;
		}
	} else {
		for (uint i = 0; i < A.size(); i++) {
		  A[i]->randomize(rg, maxrnd, thin);
		}
	}
}


// Locate the proper insertion point for item in list to maintain sorted order.
// If item is already present in list, the insertion point will be AFTER any existing entries.
template
uint MDArray::bisect(double b) {
	// TODO: This should run in log time for long vectors
	assert(!values.empty());

	for (uint i = 0; i < values.size(); i++) {
		if (values[i] > b)
			return i;
	}
	assert(false);
	return 0;
}

template
  std::vector MDArray::flat_iterator() {
  std::vector v;
	flat_iterator(v);
	return v;
}

template
  void MDArray::flat_iterator(std::vector & v) {
	if (shape.size() == 1) {
		for (uint i = 0; i < values.size(); i++) {
			v.push_back(&values[i]);
		}
	} else {
		for (uint i = 0; i < A.size(); i++) {
			A[i]->flat_iterator(v);
		}
	}
}


template
void MDArray::flat_array(T* v) {
	assert(shape.size() == 2);
	assert(shape[0] = shape[1]);

	uint N = shape[0];
	for (uint i=0; i
  void MDArray::set_wildcard(const std::vector & index, T value, int depth) {
	if (shape.size() == 1) {
		for (uint i = 0; i < values.size(); i++) {
			if (index[depth] == (int)-1 || index[depth] == (int)i)
				values[i] = value;
		}
	} else {
		for (uint i = 0; i < A.size(); i++) {
			if (index[depth] == (int)-1 || index[depth] == (int)i)
				A[i]->set_wildcard(index, value, depth+1);
		}
	}
}


// In a 2-dim matrix M, repeat copies 'a' to M[i] for all i
template
  void MDArray::repeat(uint s, const std::vector & a) {
	set_shape(s, a.size());

	for (uint i=0; i
T MDArray::get_max() {
	T m = -INF;
	if (m>0) { m=0; } // manages the unsigned int case
	get_max(m);
	return m;
}

template
void MDArray::get_max(T & m) {
	if (shape.size() == 1) {
		for (uint i = 0; i < values.size(); i++) {
			m = std::max(m, values[i]);
		}
	} else {
		for (uint i = 0; i < A.size(); i++) {
			A[i]->get_max(m);
		}
	}
}

template
void MDArray::eye(uint dim, T r) {
	clear();
	std::vector sh;
	sh.push_back(dim);
	sh.push_back(dim);
	set_shape(sh);

	for (uint i = 0; i < dim; i++) {
		assert(i < A.size());
		assert(i < A[i]->values.size());
		A[i]->values[i] = r;
	}
}

template
void MDArray::keep_eye() {
	assert(!empty());
	uint dim = shape.front();
	for (uint i = 0; i < dim; i++) {
		for (uint j = 0; j < dim; j++) {
			assert(i < A.size());
			assert(j < A[i]->values.size());
			if (i != j)
				A[i]->values[j] = 0;
		}
	}
}


// Calculate eigen values and vectors of a general matrix
template
  std::pair, std::vector > > MDArray::eigen() {
	// N': left eigenvectors of A are not computed
	char JOBVL = 'N';

	// 'V': right eigenvectors of A are computed.
	char JOBVR = 'V';

	assert(shape.size() == 2);
	__CLPK_integer N = shape[0];

	__CLPK_doublereal eigenVectorsL[N*N];
	__CLPK_doublereal eigenVectorsR[N*N];
	__CLPK_doublereal eigenValues[N];
	__CLPK_doublereal eigenValues_img[N];

	__CLPK_doublereal A[N*N];
	flat_array(A);
	__CLPK_integer LDA = N;

	__CLPK_doublereal *WR = eigenValues;
	__CLPK_doublereal *WI = eigenValues_img;
	__CLPK_doublereal *VR = eigenVectorsR;
	__CLPK_doublereal *VL = eigenVectorsL;

	__CLPK_integer INFO;
	__CLPK_integer LWORK = -1;

	__CLPK_doublereal WORK_tmp;
	dgeev_(&JOBVL, &JOBVR, &N, A, &LDA, WR, WI, VL, &N, VR, &N, &WORK_tmp, &LWORK, &INFO);
	LWORK = (int)WORK_tmp;
	__CLPK_doublereal *WORK = new __CLPK_doublereal[LWORK];
	dgeev_(&JOBVL, &JOBVR, &N, A, &LDA, WR, WI, VL, &N, VR, &N, WORK, &LWORK, &INFO);
	std::vector eigenVal;
	std::vector< MDArray > eigenVec;

	for (int i=0; i vec;
		vec.set_shape(N);
		for (int j=0; j
void MDArray::makeRotationMatrix(double angle, MDArray & v) {
	set_shape(3, 3);
	assert(v.get_shape().size() == 1 && v.get_shape()[0] == 3);

	double ux = v[0];
	double uy = v[1];
	double uz = v[2];

	double a00 = ux*ux + cos(angle)*(1.0-ux*ux);
	double a10 = ux*uy*(1.0-cos(angle))+uz*sin(angle);
	double a20 = uz*ux*(1.0-cos(angle)) - uy*sin(angle);

	double a01 = ux*uy*(1.0-cos(angle)) - uz*sin(angle);
	double a11 = uy*uy + cos(angle)*(1.0-uy*uy);
	double a21 = uy*uz*(1.0-cos(angle)) + ux*sin(angle);

	double a02 = uz*ux*(1.0-cos(angle)) + uy*sin(angle);
	double a12 = uy*uz*(1.0-cos(angle)) - ux*sin(angle);
	double a22 = uz*uz + cos(angle)*(1.0 - uz*uz);

	set(0,0, a00);
	set(0,1, a01);
	set(0,2, a02);

	set(1,0, a10);
	set(1,1, a11);
	set(1,2, a12);

	set(2,0, a20);
	set(2,1, a21);
	set(2,2, a22);
}


// LU decomposition of a general matrix
template
  MDArray MDArray::LU(bool & neg, __CLPK_integer *pivots) {

	uint nRow = shape[0];
	uint nCol = shape[1];
	if (nRow != nCol) {
		throw MocapyExceptions("Error (LU): Cannot compute LU decomposition for non-square matrix");
	}


	__CLPK_integer M = nRow;
	__CLPK_integer N = nCol;
	__CLPK_integer LDA = M;


	__CLPK_doublereal A[N*N];
	flat_array(A);

	__CLPK_integer info;

	int minMN = M;
	if (N0) {
	  //	  std::cout << *this << "\n";
	  //	  throw MocapyExceptions("Zero determinant");

	  MDArray newMatrix = *this;
	  return newMatrix;
	} else {
	  neg=false;
	  /* Take the product of the diagonal elements */
	  for (int c1 = 0; c1 < minMN; c1++) {
	    if (pivots[c1] != (c1+1)) neg = !neg;
	  }
	  
	  if (newPivots)
	    delete[] pivots;
	  
	  MDArray newMatrix = *this;
	  newMatrix.set_values(A);
	  return newMatrix;	 
	}

}


template
double MDArray::det() {
  uint nRow = shape[0];

  // Expansion by minors (faster for small matrices)
  if (nRow <=4)
    return det_old();

  // Compute determinant using LU decomposition
  bool neg;
  MDArray newMatrix = LU(neg);
  
  double d=1;
  
  for (uint i=0;i
void MDArray::inv() {
  int n = shape[1];

  if (n <= 4) // Faster for small matrices
    return inv_old();
  

  // Use LU decomposition
  int m = n;
  int info, lwork;
  int *ipiv = NULL;
  double *work = NULL;
  int err = 0;
  
  ipiv = (int*) malloc(m * sizeof *ipiv);
  if (ipiv == NULL) {
    fputs("out of memory\n", stderr);
    return ;
  }
  
  work = (double*) malloc(sizeof *work);
  if (work == NULL) {
    fputs("out of memory\n", stderr);
    err = 1;
    goto bailout;
  }   


  __CLPK_doublereal a[n*n];
  flat_array(a);
  
  dgetrf_(&m, &n, a, &m, ipiv, &info);   

  if (info != 0) {
    fprintf(stderr, "dgetrf: info = %d\n", info);
    err = 1;
    goto bailout;
  }
  
  // query for workspace size 
  lwork = -1;
  dgetri_(&n, a, &n, ipiv, work, &lwork, &info);
  
  if (info != 0 || work[0] <= 0.0) {
    fprintf(stderr, "dgetri (workspace): info = %d\n", info);
    err = 1;
    goto bailout;
  }
  
  lwork = (int) work[0];
  
  work = (double*) realloc(work, lwork * sizeof *work);
  if (work == NULL) {
    fputs("out of memory\n", stderr);
    err = 1;
    goto bailout;
  } 
  
  dgetri_(&n, a, &n, ipiv, work, &lwork, &info);
  
  if (info != 0) {
    fprintf(stderr, "dgetri: info = %d\n", info);
    err = 1;
  }
  
 bailout:
  
  free(ipiv);
  free(work);
  set_values(a);
  return ;
}

// Return a (left multiplying) matrix that mirrors p onto q.
template
void MDArray::makeRefMatrix(MDArray & u, MDArray & v) {

     assert(v.get_shape().size() == 1 && v.get_shape()[0] == 3);
     assert(u.get_shape().size() == 1 && u.get_shape()[0] == 3);

     set_shape(3,3);
     eye(3);

     MDArray uv = u-v;

     uv.div_inplace(sqrt(uv[0]*uv[0]+uv[1]*uv[1]+uv[2]*uv[2]));

     MDArray B;
     B.set_shape(3,3);
     for (uint i = 0; i < uv.size(); i++) {
          for (uint j = 0; j < uv.size(); j++) {
               double val = uv[i] * uv[j];
               B.set(i, j, val);
          }
     }

     B.multiply_inplace(2.0);

     //A-B;
     set(0,0, 1-B.get(0,0));
     set(0,1,  -B.get(0,1));
     set(0,2,  -B.get(0,2));

     set(1,0,  -B.get(1,0));
     set(1,1, 1-B.get(1,1));
     set(1,2,  -B.get(1,2));

     set(2,0,  -B.get(2,0));
     set(2,1,  -B.get(2,1));
     set(2,2, 1-B.get(2,2));

}

//  Return a left multiplying matrix that rotates u onto v.
template
void MDArray::makeRotationMatrix(MDArray & u, MDArray & v) {

     assert(v.get_shape().size() == 1 && v.get_shape()[0] == 3);
     assert(u.get_shape().size() == 1 && u.get_shape()[0] == 3);

     MDArray mu = u;
     mu.multiply_inplace(-1.0);

     MDArray refMat1;
     refMat1.set_shape(3,3);
     refMat1.makeRefMatrix(v,mu);

     MDArray refMat2;
     refMat2.set_shape(3,3);
     refMat2.makeRefMatrix(u,mu);
     refMat1.mult3(refMat2);

     copy(refMat1);

}

template template< class Archive>
void MDArray::serialize(Archive & ar, const unsigned int version) {
	ar & A;
	ar & values;
	ar & ownIndex;
	ar & shape;
}
}

#endif /* MDARRAY_H_ */


 

 

 

 

 

你可能感兴趣的:(算法,机器学习)