Task: Cholesky decomposition


C++: #include <cassert>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <vector>

template <typename scalar_type> class matrix {
public:
    matrix(size_t rows, size_t columns)
        : rows_(rows), columns_(columns), elements_(rows * columns) {}

    matrix(size_t rows, size_t columns, scalar_type value)
        : rows_(rows), columns_(columns), elements_(rows * columns, value) {}

    matrix(size_t rows, size_t columns,
        const std::initializer_list<std::initializer_list<scalar_type>>& values)
        : rows_(rows), columns_(columns), elements_(rows * columns) {
        assert(values.size() <= rows_);
        size_t i = 0;
        for (const auto& row : values) {
            assert(row.size() <= columns_);
            std::copy(begin(row), end(row), &elements_[i]);
            i += columns_;
        }
    }

    size_t rows() const { return rows_; }
    size_t columns() const { return columns_; }

    const scalar_type& operator()(size_t row, size_t column) const {
        assert(row < rows_);
        assert(column < columns_);
        return elements_[row * columns_ + column];
    }
    scalar_type& operator()(size_t row, size_t column) {
        assert(row < rows_);
        assert(column < columns_);
        return elements_[row * columns_ + column];
    }
private:
    size_t rows_;
    size_t columns_;
    std::vector<scalar_type> elements_;
};

template <typename scalar_type>
void print(std::ostream& out, const matrix<scalar_type>& a) {
    size_t rows = a.rows(), columns = a.columns();
    out << std::fixed << std::setprecision(5);
    for (size_t row = 0; row < rows; ++row) {
        for (size_t column = 0; column < columns; ++column) {
            if (column > 0)
                out << ' ';
            out << std::setw(9) << a(row, column);
        }
        out << '\n';
    }
}

template <typename scalar_type>
matrix<scalar_type> cholesky_factor(const matrix<scalar_type>& input) {
    assert(input.rows() == input.columns());
    size_t n = input.rows();
    matrix<scalar_type> result(n, n);
    for (size_t i = 0; i < n; ++i) {
        for (size_t k = 0; k < i; ++k) {
            scalar_type value = input(i, k);
            for (size_t j = 0; j < k; ++j)
                value -= result(i, j) * result(k, j);
            result(i, k) = value/result(k, k);
        }
        scalar_type value = input(i, i);
        for (size_t j = 0; j < i; ++j)
            value -= result(i, j) * result(i, j);
        result(i, i) = std::sqrt(value);
    }
    return result;
}

void print_cholesky_factor(const matrix<double>& matrix) {
    std::cout << "Matrix:\n";
    print(std::cout, matrix);
    std::cout << "Cholesky factor:\n";
    print(std::cout, cholesky_factor(matrix));
}

int main() {
    matrix<double> matrix1(3, 3,
       {{25, 15, -5},
        {15, 18, 0},
        {-5, 0, 11}});
    print_cholesky_factor(matrix1);
    
    matrix<double> matrix2(4, 4,
       {{18, 22, 54, 42},
        {22, 70, 86, 62},
        {54, 86, 174, 134},
        {42, 62, 134, 106}});
    print_cholesky_factor(matrix2);

    return 0;
}



Go: package main

import (
    "fmt"
    "math"
)




type symmetric struct {
    order int
    ele   []float64
}

type lower struct {
    order int
    ele   []float64
}



func (s *symmetric) print() {
    const eleFmt = "%10.5f "
    row, diag := 1, 0
    for i, e := range s.ele {
        fmt.Printf(eleFmt, e)
        if i == diag {
            for j, col := diag+row, row; col < s.order; j += col {
                fmt.Printf(eleFmt, s.ele[j])
                col++
            }
            fmt.Println()
            row++
            diag += row
        }
    }
}



func (l *lower) print() {
    const eleFmt = "%10.5f "
    row, diag := 1, 0
    for i, e := range l.ele {
        fmt.Printf(eleFmt, e)
        if i == diag {
            for j := row; j < l.order; j++ {
                fmt.Printf(eleFmt, 0.)
            }
            fmt.Println()
            row++
            diag += row
        }
    }
}



func (a *symmetric) choleskyLower() *lower {
    l := &lower{a.order, make([]float64, len(a.ele))}
    row, col := 1, 1
    dr := 0 
    dc := 0 
    for i, e := range a.ele {
        if i < dr {
            d := (e - l.ele[i]) / l.ele[dc]
            l.ele[i] = d
            ci, cx := col, dc
            for j := i + 1; j <= dr; j++ {
                cx += ci
                ci++
                l.ele[j] += d * l.ele[cx]
            }
            col++
            dc += col
        } else {
            l.ele[i] = math.Sqrt(e - l.ele[i])
            row++
            dr += row
            col = 1
            dc = 0
        }
    }
    return l
}

func main() {
    demo(&symmetric{3, []float64{
        25,
        15, 18,
        -5, 0, 11}})
    demo(&symmetric{4, []float64{
        18,
        22, 70,
        54, 86, 174,
        42, 62, 134, 106}})
}

func demo(a *symmetric) {
    fmt.Println("A:")
    a.print()
    fmt.Println("L:")
    a.choleskyLower().print()
}