---------------
Matrix<double,0> m0 {1};       // zero wymiarw: skalar
Matrix<double,1> m1 {1,2,3,4}; // jeden wymiar: wektor (4 elementy)
Matrix<double,2> m2 {          // dwa wymiary (4*3 elementy)
  {00,01,02,03}, // wiersz 0
  {10,11,12,13}, // wiersz 1
  {20,21,22,23}  // wiersz 2
};

Matrix<double,3> m3(4,7,9);     // trzy wymiary (4*7*9 elementw), wszystkie zainicjowane 0
Matrix<complex<double>,17> m17; // 17 wymiarw (na razie brak elementw)
---------------
Matrix<double,2> md;         // OK
Matrix<string,2> ms;         // OK: tylko nie prbuj wykonywa operacji arytmetycznych

Matrix<Matrix<int,2>,2> mm { // macierz 32 macierzy 22
                             // macierz jest moliw "liczb"
    {// wiersz 0
        {{1, 2}, {3, 4}}, // kolumna 0
        {{4, 5}, {6, 7}}, // kolumna 1
    },
    {// wiersz 1
        {{8, 9}, {0, 1}}, // kolumna 0
        {{2, 3}, {4, 5}}, // kolumna 1
    },
    {// wiersz 2
        {{1, 2}, {3, 4}}, // kolumna 0
        {{4, 5}, {6, 7}}, // kolumna 1
    }
};
---------------
Matrix<char,2> mc1(2,3,4); // bd: za duo rozmiarw wymiarw
Matrix<char,2> mc2 {
    {'1','2','3'}          // bd: brak inicjatora dla drugiego wymiaru
};

Matrix<char,2> mc2 {
    {'1','2','3'},
    {'4','5'}              // bd: brak jednego elementu w trzeciej kolumnie
};
---------------
Matrix<double,1> m1(100);     // jeden wymiar: wektor (100 elementw)
Matrix<double,2> m2(50,6000); // dwa wymiary: 50*6000 elementw

auto d1 = m1.order();  // 1
auto d2 = m2.order();  // 2

auto e1 = m1.extent(0);  // 100
auto e2 = m1.extent(1);  // bd: m1 to macierz jednowymiarowa

auto e3 = m2.extent(0);  // 50
auto e4 = m2.extent(1);  // 6000

auto s1 = m1.size();     // 100
auto s2 = m2.size();     // 50*6000
---------------
Matrix<double,2>m{ // dwa wymiary (4*3 elementy)
    {00,01,02,03}, // wiersz 0
    {10,11,12,13}, // wiersz 1
    {20,21,22,23}  // wiersz 2
};

double d1 = m(1,2);         // d==12
double d2 = m[1][2];        // d==12
Matrix<double,1> m1 = m[1]; // wiersz 1: {10,11,12,13}
double d3 = m1[2];          // d==12
---------------
template<typename M>
    Enable_if<Matrix_type<M>(),ostream&>
operator<<(ostream& os, const M& m)
{
    os << '{';
    for (size_ti=0;i!=rows(m); ++i) {
        os << m[i];
        if (i+1!=rows(m)) os << ',';
    }
    return os << '}';
}
---------------
template<typename T, size_t N>
class Matrix {
public:
    static constexpr size_t order = N;
    using value_type = T;
    using iterator = typename std::vector<T>::iterator;
    using const_iterator = typename std::vector<T>::const_iterator;

    Matrix() = default;
    Matrix(Matrix&&) = default;                                // przenoszcy
    Matrix& operator=(Matrix&&) = default;
    Matrix(const Matrix&) = default;                           // kopiujcy
    Matrix& operator=(const Matrix&) = default;
    ~Matrix() = default;

    template<typename U>
        Matrix(const Matrix_ref<U,N>&);                        // konstruuje z Matrix_ref
    template<typename U>
        Matrix& operator=(const Matrix_ref<U,N>&);             // przypisuje z Matrix_ref

    template<typename... Exts>                                 // okrela rozmiar
        explicit Matrix(Exts... exts);

    Matrix(Matrix_initializer<T,N>);                           // inicjuje z listy
    Matrix& operator=(Matrix_initializer<T,N>);                // przypisuje z listy

    template<typename U>
        Matrix(initializer_list<U>) = delete;                  // uywaj {} tylko dla elementw
    template<typename U>
        Matrix& operator=(initializer_list<U>) = delete;

    static constexpr size_t order() { return N; }              // liczba wymiarw
    size_t extent(size_t n) const { return desc.extents[n]; }  // liczba elementw w wymiarze n
    size_t size() const { return elems.size(); }               // suma wszystkich elementw
    const Matrix_slice<N>& descriptor() const { return desc; } // wycinek definiujcy indeksowanie

    T* data() { return elems.data(); }                         // "paski" dostp do elementw
    const T*data() const { return elems.data(); }

    //...

private:
    Matrix_slice<N> desc; // wycinek definiujcy rozmiar w N wymiarach
    vector<T> elems;      // elementy
};
---------------
template<typename T, size_t N>
    template<typename... Exts>
    Matrix<T,N>::Matrix(Exts... exts)
        :desc{exts...},  // kopiuje rozmiary
        elems(desc.size) // alokuje desc.size elementw i inicjuje je domylnie
    {}
---------------
template<typename T, size_t N>
Matrix<T, N>::Matrix(Matrix_initializ er<T,N> init)
{
    desc.extents = Matrix_impl::derive_extents(init); // dedukuje rozmiar z listy inicjacyjnej (29.4.4)
    elems.reserve(desc.size);                         // robi miejsce dla wycinkw
    Matrix_impl::inser t_flat(init,elems);            // inicjacja z listy inicjacyjnej (29.4.4)
    assert(elems.size() == desc.size);
}
---------------
enum class Piece { none, cross, naught };

Matrix<Piece ,2> board1 {
    {Piece::none , Piece::none , Piece::none},
    {Piece::none , Piece::none , Piece::none},
    {Piece::none , Piece::none , Piece::cross}
};
Matrix<Piece ,2> board2(3,3);  // OK
Matrix<Piece ,2> board3 {3,3}; // bd: konstruktor z initializer_list<int> jest usunity
---------------
template<typename T, size_t N>
    template<typename U>
    Matrix<T,N>::Matrix(const Matrix_ref<U,N>& x)
        :desc{x.desc}, elems{x.begin(),x.end()} // kopiuje desc i elementy
    {
        static_assert(Convertible<U,T>(),"Konstruktor macierzy: niezgodne typy elementw");
    }
---------------
template<typename T, size_t N>
    template<typename U>
    Matrix<T,N>& Matrix<T,N>::operator=(const Matrix_ref<U,N>& x)
    {
        static_assert(Convertible<U,T>(),"Matrix =: niezgodne typy elementw");

        desc = x.desc;
        elems.assign(x.begin(),x.end());
        return *this;
    }

---------------
template<typename T, size_t N>
class Matrix {
public:
    //...
    template<typename... Args> // m(i,j,k) indeksowanie liczbami cakowitymi
        Enable_if<Matrix_impl::Requesting_element<Args...>(), T&>
        operator()(Args... args);
    template<typename... Args>
        Enable_if<Matrix_impl::Requesting_element<Args...>(), const T&>
        operator()(Args... args) const;
    template<typename... Args> // m(s1,s2,s3) indeksowanie wycinkami
        Enable_if<Matrix_impl::Requesting_slice<Args...>(), Matrix_ref<T, N>>
        operator()(const Args&... args);
    template<typename... Args>
        Enable_if<Matrix_impl::Requesting_slice<Args...>(), Matrix_ref<const T,N>>
        operator()(const Args&... args) const;

    Matrix_ref<T,N-1> operator[](size_t i) { return row(i); } // m[i] dostp do wiersza
    Matrix_ref<const T,N-1> operator[](size_t i) const { return row(i); }

    Matrix_ref<T,N-1> row(size_t n); // dostp do wiersza
    Matrix_ref<const T,N-1> row(size_t n) const;

    Matrix_ref<T,N-1> col(size_t n); // dostp do kolumny
    Matrix_ref<const T,N-1> col(size_t n) const;

    //...
};
---------------
template<typename T, size_t N>
Matrix_ref<T,N-1> Matrix<T,N>::operator[](size_t n)
{
    return row(n);  // 29.4.5
}
---------------
Matrix<int,2> m2 {
    {01,02,03},
    {11,12,13}
};

m(1,2) = 99;        // nadpisuje element znajdujcy si w wierszu 1 i kolumnie 2, czyli 13
auto d1 = m(1);     // bd: za mao indeksw
auto d2 = m(1,2,3); // bd: za duo indeksw
---------------
Matrix<int> m2 {
    {01,02,03},
    {11,12,13},
    {21,22,23}
};

auto m22 = m(slice{1,2},slice{0,3});
---------------
{
    {11,12,13},
    {21,22,23}
}
---------------
m(slice{1,2},slice{0,3}) = {
    {111,112,113},
    {121,122,123}
}
---------------
{
    {01,02,03},
    {111,112,113},
    {121,122,123}
}
---------------
Matrix<int> m3 {
    {01,02,03},
    {11,12,13},
    {21,22,23}
};

auto m31 = m(slice{1,2},1); // m31 ma warto {{12},{22}}
auto m32 = m(slice{1,2},0); // m32 ma warto {{11},{21}}
auto x = m(1,2);            // x==13
---------------
Matrix<int,2> mi {{1,2,3}, {4,5,6 }};   // 23
Matrix<int,2> m2 {mi};                  // kopiowanie
mi*=2;                                  // skalowanie: {{2,4,6},{8,10,12}}
Matrix<int,2> m3 = mi+m2;               // dodawanie: {{3,6,9},{12,15,18}}
Matrix<int,2> m4 {{1,2}, {3,4}, {5,6}}; // 32
Matrix<int,2> v = mi*m4;                // mnoenie: {{18,24,30},{38,52,66},{58,80,102}}
---------------
template<typename T, size_t N>
class Matrix {
    //...

    template<typename F>
        Matrix& apply(F f);              // f(x) dla kadego elementu x

    template<typename M, typename F>
        Matrix& apply(const M& m, F f);  // f(x,mx) dla odpowiednich elementw

    Matrix& operator=(const T& value);   // przypisanie ze skalarem

    Matrix& operator+=(const T& value);  // skalarne dodawanie
    Matrix& operator-=(const T& value);  // skalarne odejmowanie
    Matrix& operator*=(const T& value);  // skalarne mnoenie
    Matrix& operator/=(const T& value);  // skalarne dzielenie
    Matrix& operator%=(const T& value);  // skalarne modulo

    template<typename M> // dodawanie macierzy
        Matrix& operator+=(const M& x);
    template<typename M> // odejmowanie macierzy
        Matrix& operator-=(const M& x);

    //...
};

// binarne operatory +, -, * s dostarczone jako funkcje nieskadowe
---------------
template<typename T, size_t N>
Matrix<T,N>& Matrix<T,N>::operator+=(const T& val)
{
    return apply([&](T& a) { a+=val; } ); // uycie lambdy (11.4)
}
---------------
template<typename T, size_t N>
    template<typename F>
    Matrix<T,N>& Matrix<T,N>::apply(F f)
    {
        for (auto& x : elems) f(x); // w tej ptli uywane s iteratory krokowe
        return *this;
    }
---------------
m.apply(abs).apply(sqrt); // m[i] = sqrt(abs(m[i])) dla wszystkich i
---------------
template<typename T, size_t N>
Matrix<T,N> operator+(const Matrix<T,N>& m, const T& val)
{
    Matrix<T,N> res = m;
    res+=val;
    return res;
}
---------------
template<typename T, size_t N>
    template<typename M>
    Enable_if<Matrix_type<M>(),Matrix<T,N>&> Matrix<T,N>::operator+=(const M& m)
    {
        static_assert(m.order()==N,"+=: niezgodne wymiary macierzy");
        assert(same_extents(desc,m.descriptor())); // upewnienie si, e rozmiary pasuj
        return apply(m, [](T& a,Value_type<M>&b) { a+=b; });
    }
---------------
template<typename T, size_t N>
    template<typename M, typename F>
    Enable_if<Matrix_type<M>(),Matrix<T,N>&> Matrix<T,N>::apply(M& m, F f)
    {
        assert(same_extents(desc,m.descriptor()));// upewnienie si, e rozmiary pasuj
        for (auto i = begin(), j = m.begin(); i!=end(); ++i, ++j)
            f(*i,*j);
        return *this;
    }
---------------
template<typename T, size_t N>
Matrix<T,N> operator+(const Matrix<T,N>& a, const Matrix<T,N>& b)
{
    Matrix<T,N> res = a;
    res+=b;
    return res;
}
---------------
template<typename T, typename T2, size_t N,
    typename RT = Matrix<Common_type<Value_type<T>,Value_type<T2>>,N>>
Matrix<RT,N> operator+(const Matrix<T,N>& a, const Matrix<T2,N>& b)
{
    Matrix<RT,N> res = a;
    res+=b;
    return res;
}
---------------
template<>
struct common_type<Quad,long double> {
    using type = Quad;
};
---------------
template<typename T, size_t N>
Matrix<T,N> operator+(const Matrix_ref<T,N>& x, const T& n)
{
    Matrix<T,N> res = x;
    res+=n;
    return res;
}
---------------
template<typename T>
Matrix<T,2> operator*(const Matrix<T,1>& u, const Matrix<T,1>& v)
{
    const size_t n = u.extent(0);
    const size_t m = v.extent(0);
    Matrix<T,2> res(n,m); // macierz nm
    for (size_ti=0;i!=n; ++i)
        for (size_tj=0;j!=m; ++j)
            res(i,j) = u[i]*v[j];
    return res;
}
---------------
template<typename T>
Matrix<T,1> operator*(const Matrix<T,2>& m, const Matrix<T,1>& v)
{
    assert(m.extent(1)==v.extent(0));

    const size_t n = m.extent(0);
    Matrix<T,1> res(n);
    for (size_ti=0;i!=n; ++i)
        for (size_tj=0;j!=n; ++j)
            res(i) += m(i,j)*v(j);
    return res;
}
---------------
template<typename T>
Matrix<T,2> operator*(const Matrix<T,2>& m1, const Matrix<T,2>& m2)
{
    const size_t n = m1.extent(0);
    const size_t m = m1.extent(1);
    assert(m==m2.extent(0)); // kolumny musz odpowiada wierszom

    const size_t p = m2.extent(1);
    Matrix<T,2> res(n,p);
    for (size_ti=0;i!=n; ++i)
        for (size_tj=0;j!=p; ++j)
            for (size_tk=0;k!=m; ++k)
                res(i,j) += m1(i,k)*m2(k,j);
    return res;
}
---------------
res(i,j) = dot_product(m1[i],m2.column(j))
---------------
template<typename T>
T dot_product(const Matrix_ref<T,1>& a, const Matrix_ref<T,1>& b)
{
    return inner_product(a.begin(),a.end(),b.begin(),0.0);
}
---------------
struct slice {
    slice() :start(-1), length(-1), stride(1) { }
    explicit slice(size_t s) :start(s), length(-1), stride(1) { }
    slice(size_t s, size_t l, size_t n = 1) :start(s), length(l), stride(n) { }

    size_t operator()(size_t i) const { return start+i*stride;}

    static slice all;

    size_t star t; // pierwszy indeks
    size_t length; // liczba indeksw (mona wykorzysta do sprawdzania zakresu)
    size_t stride; // odlego midzy elementami w sekwencji
};
---------------
template<size_t N>
struct Matrix_slice {
    Matrix_slice() = default;                              // pusta macierz: brak elementw

    Matrix_slice(size_t s, initializer_list<size_t> exts); // rozmiar
    Matrix_slice(size_t s, initializer_list<size_t> exts, 
    (initializer_list<size_t> strs);                      // rozmiar i krok

    template<typename... Dims>                             // rozmiar N
        Matrix_slice(Dims... dims);

    template<typename... Dims,
             typename = Enable_if<All(Convertible<Dims,size_t>()...)>>
    size_t operator()(Dims... dims) const; // oblicza miejsce elementu z indeksw

    size_t size;             // liczba wszystkich elementw
    size_t start;            // przesunicie pocztkowe
    array<size_t,N> extents; // liczba elementw w kadym wymiarze
    array<size_t,N> strides; // przesunicia midzy elementami w kadym wymiarze
};
---------------
template<size_t N>
    template<typename... Dims>
    size_t Matrix_slice<N>::operator()(Dims... dims) const
    {
        static_assert(sizeof...(Dims) == N, "");

        size_t args[N] { size_t(dims)... }; // Kopiuje argumenty do tablicy
        
        return inner_product(args,args+N,strides.begin(),size_t(0));
}
---------------
template<>
struct Matrix_slice<1> {

    //...

    size_t operator()(size_t i) const
    {
        return i;
    }
}

template<>
struct Matrix_slice<2> {

    //...

    size_t operator()(size_t i, size_t j) const
    {
        return i*strides[0]+j;
    }
}
---------------
template<typename T, size_t N>
class Matrix_ref {
public:
    Matrix_ref(const Matrix_slice<N>& s, T* p) :desc{s}, ptr{p} {}
    //... wikszo taka sama jak w Matrix...
private:
    Matrix_slice<N> desc; // ksztat macierzy
    T* ptr;               // pierwszy element macierzy
};
---------------
Matrix_ref<double,1> user()
{
    Matrix<double,2> m = {{1,2}, {3,4}, {5,6}};
    return m.row(1);
}

auto mr = user(); // kopot
---------------
template<typename T, size_t N>
class Matrix_base {
    //... wsplny kod...
};

template<typename T, size_t N>
class Matrix : public Matrix_base<T,N> {
    //... kod specyficzny dla klasy Matrix...
private:
    Matrix_slice<N> desc; // ksztat macierzy
    vector<T> elements;
};

template<typename T, size_t N>
class Matrix_ref : public Matrix_base<T,N> {
    //... kod specyficzny dla klasy Matrix_ref...
private:
    Matrix_slice<N> desc; // ksztat macierzy
    T* ptr;
};
---------------
template<typename T, size_t N>
using Matrix_initializer = typename Matrix_impl::Matrix_init<T, N>::type;
---------------
template<typename T, size_t N>
struct Matrix_init {
    using type = initializer_list<typename Matrix_init<T,N-1>::type>;
};
---------------
template<typename T>
struct Matrix_init<T,1> {
    using type = initializer_list<T>;
};
---------------
template<typename T>
struct Matrix_init<T,0>;  // celowo niezdefiniowane
---------------
template<typename T, size_t N>
Matrix<T,N>::Matrix(Matrix_initializer<T,N> init)
{
    desc.extents = Matrix_impl::derive_extents(init);  // dedukuje rozmiar z listy inicjacyjnej (29.4.4)
    elems.reserve(desc.size);                          // robi miejsce dla wycinkw
    Matrix_impl::insert_flat(init,elems);              // inicjuje z listy inicjacyjnej (29.4.4)
    assert(elems.size() == desc.size);
}
---------------
template <std::size_t N, typename List>
std::array<std::size_t,N> derive_extents(const List& list)
{
    std::array<std::size_t,N> a;
    auto f = a.begin();
    add_extents<N>(f,list); // dodaje rozmiary do a
    return a;
}
---------------
template <std::size_t N, typename I, typename List>
Enable_if<(N>1),void> add_extents(I& first, const List& list)
{
    assert(check_non_jagged<N>(list));
    *first++ = list.size(); // zapisuje ten rozmiar
    add_extents<N-1>(first,*list.begin());
}

template <std::size_t N, typename I, typename List>
Enable_if<(N==1),void> add_extents(I& first, const List& list)
{
    *first++ = list.size();
}
---------------
template <size_t N, typename List>
bool check_non_jagged(const List& list)
{
    auto i = list.begin();
    for (auto j = i+1; j!=list.end(); ++j)
        if (derive_extents<N-1>(*i) != derive_extents<N-1>(*j))
            return false;
    return true;
}
---------------
template<typename T, typename Vec>
void insert_flat(initializer_list<T> list, Vec& vec)
{
    add_list(list.begin(),list.end(),vec);
}
---------------
template<typename T, typename Vec>  // zagniedone listy inicjacyjne
void add_list(const initializer_list<T>* first, const initializer_list<T>* last, Vec& vec)
{
    for (;first!=last;++first)
        add_list(first->begin(),first->end(),vec);
}
---------------
template<typename T, typename Vec>
void add_list(const T* first, const T* last, Vec& vec)
{
    vec.insert(vec.end(),first,last);
}
---------------
template<typename T, size_t N>
Matrix_ref<T,N-1> Matrix<T,N>::row(size_t n)
{
    assert(n<rows());
    Matrix_slice<N-1> row;
    Matrix_impl::slice_dim<0>(n,desc,row);
    return {row,data()};
}
---------------
template<typename T>
T& Matrix<T,1>::row(size_t i)
{
    return elems[i];
}

template<typename T>
T& Matrix<T,0>::row(size_t n) = delete;
---------------
template<typename T, size_t N>
Matrix_ref<T,N-1> Matrix<T,N>::column(size_t n)
{
    assert(n<cols());
    Matrix_slice<N-1> col;
    Matrix_impl::slice_dim<1>(n,desc,col);
    return {col,data()};
}
---------------
template<typename T, size_t N> // indeksowanie przy uyciu liczb cakowitych
    template<typename... Args>
    Enable_if<Matrix_impl::Requesting_element<Args...>(),T&>
    Matrix<T,N>::operator()(Args... args)
    {
        assert(Matrix_impl::check_bounds(desc, args...));
        return*(data() + desc(args...));
    }
---------------
template<size_t N, typename... Dims>
bool check_bounds(const Matrix_slice<N>& slice, Dims... dims)
{
    size_t indexes[N] {size_t(dims)...};
    return equal(indexes, indexes+N, slice.extents, less<size_t> {});
}
---------------
return*(data() + desc(args...));
---------------
Enable_if<Matrix_impl::Requesting_element<Args...>(),T&>
---------------
Matrix_impl::Requesting_element<Args...>()
---------------
template<typename... Args>
constexpr bool Requesting_element()
{
    return All(Convertible<Args,size_t>()...);
}
---------------
constexpr bool All() { return true; }

template<typename... Args>
constexpr bool All(bool b, Args... args)
{
    return b && All(args...);
}
---------------
template<typename... Args>
constexpr bool Requesting_slice()
{
    return All((Convertible<Args,size_t>() || Same<Args,slice>())...)
              && Some(Same<Args,slice>()...);
}
---------------
template<typename T, size_t N> // indeksowanie przy uyciu wycinkw
    template<typename... Args>
        Enable_if<Matrix_impl::Requesting_slice<Args...>(), Matrix_ref<T,N>>
    Matrix<T,N>::operator()(const Args&... args)
    {
        matrix_slice<N> d;
        d.start = matrix_impl::do_slice(desc,d,args...);
        return {d,data()};
    }
---------------
template<size_t N, typename T, typename... Args>
size_t do_slice(const Matrix_slice<N>& os, Matrix_slice<N>& ns, const T& s, const Args&
(... args)
{
    size_t m = do_slice_dim<sizeof...(Args)+1>(os,ns,s);
    size_t n = do_slice(os,ns,args...);
    return m+n;
}
---------------
template<size_t N>
size_t do_slice(const Matrix_slice<N>& os, Matrix_slice<N>& ns)
{
    return 0;
}
---------------
template<typename T>
class Matrix<T,0> {
public:
    static constexpr size_t order = 0;
    using value_type = T;

    Matrix(const T& x) : elem(x) { }
    Matrix& operator=(const T& value) { elem = value; return *this; }

    T& operator()() { return elem; }
    const T& operator()() const { return elem; }

    operator T&() { return elem; }
    operator const T&() { return elem; }
private:
    T elem;
};
---------------
a1,1x1+...+a1,nxn=b1
...
an,1x1+...+an,nxn=bn
---------------
Ax =b
---------------
an,nXn = bn
---------------
using Mat2d = Matrix<double,2>;
using Vec = Matrix<double,1>;
---------------
Vec classical_gaussian_elimination(Mat2d A, Vec b)
{
    classical_elimination(A, b);
    return back_substitution(A, b);
}
---------------
void classical_elimination(Mat2d& A, Vec& b)
{
    const size_t n = A.dim1();

    // przegldanie od 1. kolumny do przedostatniej, wstawiajc zera we wszystkich elementach pod przektn:
    for (size_tj=0;j!=n-1; ++j) {
        const double pivot = A(j, j);
        if (pivot==0) throw Elim_failure(j);
        // wstawia zera do wszystkich elementw pod przektn i-tego wiersza:
        for (size_t i = j+1; i!=n; ++i) {
            const double mult = A(i,j) / pivot;
            A[i](slice(j)) = scale_and_add(A[j](slice(j)), -mult,A[i](slice(j)));
            b(i) -= mult*b(j); // dokonuje odpowiedniej zmiany w b
        }
    }
}
---------------
Vec back_substitution(const Mat2d& A, const Vec& b)
{
    const size_t n = A.dim1();
    Vec x(n);

    for (size_t i = n-1; i>=0; --i) {
        double s = b(i)-dot_product(A[i](slice(i+1)),x(slice(i+1)));
        if (double m = A(i,i))
            x(i) = s/m;
        else
            throw Back_subst_failure(i);
    }
    return x;
}
---------------
void elim_with_partial_pivot(Mat2d& A, Vec& b)
{
    const size_t n = A.dim1();

    for (size_tj=0;j!=n; ++j) {
        size_t pivot_row = j;
        // szuka odpowiedniego elementu centralnego:
        for (size_t k = j+1; k!=n; ++k)
            if (abs(A(k,j)) > abs(A(pivot_row,j)))
                pivot_row = k;

        // zamiana wierszy, jeli zostanie znaleziony lepszy element centralny:
        if (pivot_row!=j) {
            A.swap_rows(j,pivot_row);
            std::swap(b(j),b(pivot_row));
        }

        // eliminacja:
        for (size_t i = j+1; i!=n; ++i) {
            const double pivot = A(j,j);
            if (pivot==0) error("Nie ma rozwizania: pivot==0");
            const double mult = A(i,j)/pivot;
            A[i](slice(j)) = scale_and_add(A[j](slice(j)), -mult, A[i](slice(j)));
            b(i) -= mult*b(j);
        }
    }
}
---------------
void solve_random_system(size_t n)
{
    Mat2d A = random_matrix(n); // generuje losow macierz Mat2d
    Vec b = random_vector(n);   // generuje losow macierz Vec

    cout << "A = " << A << endl;
    cout << "b = " << b << endl;

    try {
        Vecx=classical_gaussian_elimination(A, b);
        cout << "Rozwizanie eliminacji klasycznej to x = " << x << endl;
            Vec v = A * x;
        cout << " A * x ="<< v <<endl;
    }
    catch(const exception& e) {
        cerr << e.what() << endl;
    }
}
---------------
if (A*x!=b) error("nie udao si");
---------------
if (!equal(A*x,b)) error("nie udao si");
---------------
Matrix<double,1> U=M*V+W;
---------------
using Mat2d = Matrix<double,2>;
using Vec = Matrix<double,1>;
---------------
struct MVmul {
    const Mat2d& m;
    const Vec& v;

    MVmul(const Mat2d& mm, const Vec &vv) :m{mm}, v{vv} { }

    operator Vec(); // oblicza i zwraca wynik
};

inline MVmul operator*(const Mat2d& mm, const Vec& vv)
{
    return MVmul(mm,vv);
}
---------------
struct MVmulVadd {
    const Mat2d& m;
    const Vec& v;
    const Vec& v2;

    MVmulVadd(const MVmul& mv, const Vec& vv) :m(mv.m), v(mv.v), v2(vv) { }

    operator Vec(); // oblicza i zwraca wynik
};

inline MVmulVadd operator+(const MVmul& mv, const Vec& vv)
{
    return MVmulVadd(mv,vv);
}
---------------
template<>
class Matrix<double,1> {       // specjalizacja (tylko dla tego przykadu)
    //...
public:
    Matrix(const MVmulVadd& m) // inicjacja wynikiem m
    {
        // alokacja elementw itd.
        mul_add_and_assign(this,&m.m,&m.v,&m.v2);
    }

    Matrix& operator=(const MVmulVadd& m) // przypisuje wynik m do *this
    {
        mul_add_and_assign(this,&m.m,&m.v,&m.v2);
        return *this;
    }
    //...
};
---------------
U.operator=(MVmulVadd(MVmul(M,V),W))