/*
 * Marek Burza, 4E2
 * operacje na macierzach BOOST::uBLAS (Basic Linear Algebra Subprograms)
 * na podstawie: http://www.boost.org/doc/libs/1_35_0/libs/numeric/ublas/doc/operations_overview.htm
 */

#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <iostream>
//pliki nagłówkowe potrzebne dla generatora liczb pseudolosowych
#include <cstdlib>
#include <ctime>

//ustawienie dla wygody obowiązującej przestrzeni nazw na tę z biblioteki
using namespace boost::numeric::ublas;

int main()
{
    std::cout<<"==================================="<<std::endl;

    //rozmiar macierzy i wektora
    std::size_t n = 3;

    //macierze liczb całkowitych o rozmiarze nxn
    matrix<int> A (n,n);
    matrix<int> B (n,n);
    matrix<int> C (n,n);

    //macierz identycznościowa o rozmiarze n+1
    identity_matrix<int> O (n+1);

    //wektory liczb całkowitych o rozmiarze n
    vector<int> u (n);
    vector<int> v (n);
    vector<int> w (n);

    //inicjalizacjia generatora liczb pseudolosowych czasem bieżącym
    srand(time(NULL));

    //wypełnienie macierzy losowymi liczbami całkowitymi 0-99
    for(unsigned int i=0;i<(unsigned int)n;i++)
    {
	for(unsigned int j=0;j<(unsigned int)n;j++)
	{
	    A(i,j)=(int)rand()%100;
	    B(i,j)=(int)rand()%100;
	    C(i,j)=(int)rand()%100;
	}

	u(i)=(int)rand()%100;
	v(i)=(int)rand()%100;
	w(i)=(int)rand()%100;
    }
    
    //wyświetlenie zawartości macierzy i wektorów za pomocą przeciążonego operatora ''<<''
    std::cout<<"Macierz A: "<<std::endl;
    std::cout<<A<<std::endl;
    std::cout<<"Macierz B: "<<std::endl;
    std::cout<<B<<std::endl;
    std::cout<<"Macierz C: "<<std::endl;
    std::cout<<C<<std::endl;
    std::cout<<"Macierz O: "<<std::endl;
    std::cout<<O<<std::endl;

    std::cout<<"Wektor  u: "<<std::endl;
    std::cout<<u<<std::endl;
    std::cout<<"Wektor  v: "<<std::endl;
    std::cout<<v<<std::endl;
    std::cout<<"Wektor  w: "<<std::endl;
    std::cout<<w<<std::endl;

    std::cout<<"Rozmiar wektora  w: "<<std::endl;
    std::cout<<w.size()<<std::endl;

    std::cout<<"Rozmiar x macierzy O: "<<std::endl;
    std::cout<<O.size1()<<std::endl;
    std::cout<<"Rozmiar y macierzy O: "<<std::endl;
    std::cout<<O.size2()<<std::endl;


    std::cout<<"==================================="<<std::endl;
    std::cout<<"OPERACJE NA WEKTORACH I MACIERZACH"<<std::endl;
    std::cout<<"==================================="<<std::endl<<""<<std::endl;
    std::cout<<"Operacje podstawowe:"<<std::endl<<""<<std::endl;
    
    std::cout<<"Nieprawidłowa operacja powoduje rzucenie wyjątku:"<<std::endl;
    
    try
    {
        //doawanie macierzy o różnych rozmiarach powoduje błąd
        std::cout<<"dodawanie A+O: "<<std::endl;
        std::cout<<A+O<<std::endl;
    }
    catch (std::exception &e)
    {
	std::cout << "Exception: " << e.what() << std::endl<<""<<std::endl;
    }

    std::cout<<"dodawanie A+B: "<<std::endl;
    std::cout<<A+B<<std::endl;

    std::cout<<"odejmowanie A-B: "<<std::endl;
    std::cout<<A-B<<std::endl;

    std::cout<<"mnożenie macierzy A*B: "<<std::endl;
    std::cout<<prod(A,B)<<std::endl;

 
    std::cout<<"mnożenie macierzy przez wektor A*u: "<<std::endl;
    std::cout<<prod(A,u)<<std::endl;

    std::cout<<"mnożenie macierzy przez skalar A*2: "<<std::endl;
    std::cout<<A*2<<std::endl;

    std::cout<<"dzielenie macierzy przez skalar A/2: "<<std::endl;
    std::cout<<A/2<<std::endl;

    std::cout<<"==================================="<<std::endl;
    std::cout<<"Operatory jednoargumentowe:"<<std::endl<<""<<std::endl;

    C+=A;
    std::cout<<"dodawanie macierzy A do C i zapisanie w C, C+=A: "<<std::endl;
    std::cout<<C<<std::endl;
    
    C-=A;
    std::cout<<"odejmowanie macierzy A od C i zapisanie w C, C-=A: "<<std::endl;
    std::cout<<C<<std::endl;

    C*=2;
    std::cout<<"mnożenie macierzy C przez 2 i zapisanie w C, C*=2: "<<std::endl;
    std::cout<<C<<std::endl;

    C/=2;
    std::cout<<"dzielenie macierzy C przez 2 i zapisanie w C, C/=2: "<<std::endl;
    std::cout<<C<<std::endl;

    std::cout<<"==================================="<<std::endl;
    std::cout<<"Operacje zaawansowane:"<<std::endl<<""<<std::endl;

    std::cout<<"iloczyn zewnętrzny, u*v: "<<std::endl;
    std::cout<<outer_prod(u, v)<<std::endl;

    std::cout<<"iloczyn skalarny, u*v: "<<std::endl;
    std::cout<<inner_prod(u, v)<<std::endl;

    std::cout<<"iloczyn 'po elementach', u*v: "<<std::endl;
    std::cout<<element_prod(u, v)<<std::endl;

    std::cout<<"iloraz 'po elementach', u/v: "<<std::endl;
    std::cout<<element_div(u, v)<<std::endl;
    //prec_prod, prec_inner_prod, prec_outer_proed - iloczyny obliczane z podwójną precyzją (double)

    std::cout<<"==================================="<<std::endl;
    std::cout<<"Przekształcenia:"<<std::endl<<""<<std::endl;

    std::cout<<"transpozycja macierzy A: "<<std::endl;
    std::cout<<trans(A)<<std::endl;

    std::cout<<"sprzężenie zespolone (trywialne) macierzy A: "<<std::endl;
    std::cout<<conj(A)<<std::endl;

    std::cout<<"sprzężenie hermitowskie macierzy A: "<<std::endl;
    std::cout<<herm(A)<<std::endl;

    std::cout<<"część rzeczywista macierzy A: "<<std::endl;
    std::cout<<real(A)<<std::endl;

    std::cout<<"część urojona macierzy A: "<<std::endl;
    std::cout<<imag(A)<<std::endl;

    std::cout<<"==================================="<<std::endl;
    std::cout<<"Normy:"<<std::endl<<""<<std::endl;

    std::cout<<"norma Czebyszewa wektora u: "<<std::endl;
    std::cout<<norm_inf(u)<<std::endl;
    std::cout<<"norma pierwsza wektora u: "<<std::endl;
    std::cout<<norm_1(u)<<std::endl;
    std::cout<<"norma euklidesowa wektora u: "<<std::endl;
    std::cout<<norm_2(u)<<std::endl;
    std::cout<<"indeks elementu wektora u mającego największą wartość bezwzględną: "<<std::endl;
    std::cout<<index_norm_inf(u)<<std::endl;
    std::cout<<"norma Czebyszewa macierzy A: "<<std::endl;
    std::cout<<norm_inf(A)<<std::endl;
    std::cout<<"norma pierwsza macierzy A: "<<std::endl;
    std::cout<<norm_1(A)<<std::endl;
    std::cout<<"norma frobeniusza macierzy A: "<<std::endl;
    std::cout<<norm_frobenius(A)<<std::endl;

    std::cout<<"==================================="<<std::endl;

    return 0;
}
