/*
author:
	seth from http://www.bierdatenbank.de
tab stops:
	2 (otherwise hardly readable!)
*/
#ifndef __seth_vektor_h
#define __seth_vektor_h

#include <ctime>
#include <float.h>
#include <iostream>
#include <iomanip.h>
#include <math.h>
#include <stdio.h>
#include <fstream>

class vektor{
	friend class matrix;
	private:
		int dim;											// dimension, d.h. anzahl(komponenten)
		double *elem;									// komponenten
		double max(double, double);		// liefer max(a,b) a,b double
		double min(double, double);		// liefer min(a,b) a,b double
	public:
		int transp;															// gibt an, ob matrix transponiert
		vektor(int=1, int=0);										// constructor
		vektor(const vektor&);									// copy-constructor
		vektor(char* filename);									// constructor fuer einlesen aus datei
		~vektor();															// destructor
		void deallocate();											// deallokierer; speicher freigeben
		int set(int, double);										// setze komponente
		double get(int);												// liefer komponente
		int get_dim();													// liefer dimension
		double max();									// liefer max(v) v vektor
		double min();									// liefer min(v) v vektor
		double skp(const vektor&);							// skalarprodukt (kurz)
		double skalarprodukt(const vektor&);		// skalarprodukt
		double norm(int=2);											// vektor-norm
		double pnorm(int=2);										// vektor-p-norm
		double maximumnorm();										// maximumnorm
		vektor tridiag(double, double, double);	// A*x, mit A tridiagonalmatrix
		vektor transpose();											// transponiere vektor (geht auch direkt ueber public int transp)
		void ausgabe(int=0);										// gib komponenten auf bildschirm aus; parameter bestimmt ausgabe-art
		vektor  operator-();										// unitaerer vektor operator -v
		vektor  operator+(const vektor&);				// v+v
		vektor  operator-(const vektor&);				// v-v
		vektor& operator+=(const vektor&);			// v+=v
		vektor& operator-=(const vektor&);			// v-=v
		vektor  operator*(double);							// v*s
		friend vektor operator*(double, const vektor&); // s*v
		vektor& operator*=(double);							// v*=s
		ostream& operator<<(ostream&);					// ausgabe-kram
};

void ausgabe_format(int=1);									// bestimme ausgabe-format

inline ostream& operator<<(ostream& strm, vektor& v){
	v.ausgabe();
	return strm;
};

double vektor::max(double a, double b){
	return (a>b)?a:b;
}

double vektor::min(double a, double b){
	return (a<b)?a:b;
}

vektor::vektor(int dimension, int transponiert){
	if(dimension>0){
		dim=dimension;
		transp=transponiert;
		elem=new double[dim];
		for(int i=0;i<dim;++i) elem[i]=0;
	}else cout <<"error: dimension muss positiv sein"<<endl;
}

vektor::vektor(const vektor& v){
	dim=v.dim;
	transp=v.transp;
	elem=new double[dim];
	for(int i=0;i<dim;++i) elem[i]=v.elem[i];
}

// constructor fuer einlesen aus datei
vektor::vektor(char* filename){
	int error=1;
	std::ifstream infile; //nur einlesen
	double komp;
	infile.open(filename,ios::in);
	if(infile >>dim) // lese dimension ein
		if(dim>0) error=0;
	if(!error){
		elem=new double[dim]; // erstelle entsprechenden vektor
		int index=0;
		while(infile >>komp && index<dim) elem[index++]=komp; // einlesen der datei in vektor
	}else cout <<"datei konnte nicht geoeffnet werden oder enthaelt keine zulaessigen dimension in der ersten zeile";
	infile.close();
}

vektor::~vektor(){
//	delete[] elem;
}

// deallokierer; speicher freigeben
void vektor::deallocate(){
	delete[] elem;
}

int vektor::set(int i, double d){
	int res=1;
	if(i<0 || i>=dim){
		cout <<"error: komponentenindex > dimension!"<<endl;
		res=0;
	}	else elem[i]=d;
	return res;
}

double vektor::get(int i){
	if(i<0 || i>=dim){
		cout <<"error: komponentenindex > dimension!"<<endl;
		return 0;
	}
	return elem[i];
}

int vektor::get_dim(){
	return dim;
}

double vektor::skp(const vektor& v){
	return (*this).skalarprodukt(v);
}

double vektor::max(){
	double res=0;
	for(int i=0;i<dim;++i) res=max(res, fabs(elem[i]));
	return res;
}

double vektor::min(){
	double res=DBL_MAX;
	for(int i=0;i<dim;++i) res=min(res, fabs(elem[i]));
	return res;
}

double vektor::skalarprodukt(const vektor& v){
	double s=0;
	if(dim==v.dim){
		for(int i=0;i<dim;++i) s+=elem[i]*v.elem[i];
	}else	cout <<"error: dimensionen bei skalarprodukt muessen gleich sein."<<endl;
	return s;
}

double vektor::norm(int p){
	return (*this).pnorm(p);
}

double vektor::pnorm(int p){
	double res=0;
	for(int i=0;i<dim;++i) res+=pow(fabs((*this).elem[i]),p);
	res=pow(res,(1.0/p));
	return res;
}

double vektor::maximumnorm(){
	double res=0;
	for(int i=0;i<dim;++i) res=max(res, fabs((*this).elem[i]));
	return res;
}

vektor vektor::tridiag(double x, double y, double z){
	vektor res(dim);
	for(int i=0;i<dim;++i){
		if(i-1>=0) res.elem[i]+=elem[i-1]*x;
		res.elem[i]+=elem[i]*y;
		if(i+1<dim) res.elem[i]+=elem[i+1]*z;
	}
	return res;
}

vektor vektor::transpose(){
	vektor v(*this);
	v.transp=1-v.transp;
	return v;
}

void ausgabe_format(int mode){
	if(mode==0){
		cout.unsetf(ios::scientific);
	}else if(mode==1){
		cout.setf(ios::scientific,  ios::floatfield);	// scientific-notation
		cout.setf(ios::adjustfield, ios::right);			// rechtsbuendig
		cout.setf(ios::showpoint);										// dezimalpunkt und abschließende nullen ausgeben
		cout.precision(4);														// genauigkeit der gleitkommawerte=2
	}
}

void vektor::ausgabe(int mode){
	// zeilenweises ausgeben der matrix
	if(mode==0){
		cout <<"[";
		for(int i=0;i<dim;++i){
			if(elem[i]==-0) elem[i]=0; // so ein kaes!
			if(i>0) cout <<" ";
			if(elem[i]>=0) cout <<" ";
			if(elem[i]!=0) printf("%5.4f", elem[i]);
			else cout <<"   0  ";
		}
		cout <<"]"<<endl;
	}	else if(mode==1){
		ausgabe_format(1);
		cout <<"[";
		for(int i=0;i<dim;++i) cout <<setw(11)<<elem[i]<<" ";
		cout <<"\b]";
		if(transp==0) cout <<"t"; // vektor wird bei ausgabe immer als zeile ausgegeben
		cout <<endl;
	}
}

vektor vektor::operator-(){
	vektor c(dim);
	for(int i=0;i<dim;++i) c.elem[i]=elem[i]*(-1);
	return c;
}

vektor vektor::operator+(const vektor& v){
	vektor c(dim);
	if(dim==v.dim){
		for(int i=0;i<dim;++i) c.elem[i]=elem[i]+v.elem[i];
	}else	cout <<"error: dimensionen bei addition muessen gleich sein."<<endl;
	return c;
}

vektor vektor::operator-(const vektor& v){
	vektor c(dim);
	if(dim==v.dim){
		for(int i=0;i<dim;++i) c.elem[i]=elem[i]-v.elem[i];
	}else	cout <<"error: dimensionen bei subtraction muessen gleich sein."<<endl;
	return c;
}

vektor& vektor::operator+=(const vektor& v){
	*this=*this+v;
	return *this;
}

vektor& vektor::operator-=(const vektor& v){
	*this=*this-v;
	return *this;
}

vektor vektor::operator*(double d){
	vektor c(dim);
	for(int i=0;i<dim;++i) c.elem[i]=elem[i]*d;
	return c;
}

vektor operator*(double d, const vektor& v){
	vektor c(v.dim);
	for(int i=0;i<v.dim;++i) c.elem[i]=d*v.elem[i];
	return c;
}

vektor& vektor::operator*=(double d){
	*this=*this*d;
	return *this;
}

ostream& vektor::operator<<(ostream& strm){
	ausgabe();
	return strm;
}

#endif

