...by Daniel Szego
quote
"Simplicity is the ultimate sophistication."
Leonardo da Vinci

Tuesday, July 24, 2018

Creating matrix operators with solidity

Solidity is not really meant to store a large amount of data. However it might happen despite that requirements are to store matrixes in our smart contract. If that happens, one of the possibility is to store them as hash tables realized by mappings:

contract Matrix{
    
    mapping(uint => mapping(uint => uint)) _matrix;
    uint public maxi;
    uint public maxj;

    function elementAt(uint i, uint j) public returns (uint) {
        return _matrix[i][j];
    }
    
    function setElement(uint i, uint j, uint _value) public {
        _matrix[i][j] = _value;
        if (i > maxi) {
            maxi = i;
        }
        if (j > maxj) {
            maxj = j;
        }
    }
}

In this way accessing or modifying matrix operators are easy. However, if we have to create operations on the top of the matrixes like, adding or subtracting them, it might become pretty costly very fast, because we have to iterate on the matrixes with nested loops and even if the matrix is spare, meaning that only a couple of elements are filled out, both the iteration and the modification costs money. 

contract MatrixOperator{
    
    function add(Matrix _matrix1, Matrix _matrix2) public {
        // get max elements
        uint maxi = _matrix1.maxi();
        if (_matrix2.maxi() > _matrix1.maxi()){
            maxi = _matrix2.maxi();
        }

        uint maxj = _matrix1.maxj();
        if (_matrix2.maxj() > _matrix1.maxj()){
            maxj = _matrix2.maxj();
        }

        for (uint i=0; i < maxi; i++) {
            for (uint j=0; j < maxj; j++) {
                if ((_matrix1.elementAt(i,j)>0) && (_matrix2.elementAt(i,j)>0)) {
        _matrix1.setElement(i,j,_matrix1.elementAt(i,j) + _matrix2.elementAt(i,j));
                }
            }
        }    
    }
    
    function sub(Matrix _matrix1, Matrix _matrix2) public {
        // get max elements
        uint maxi = _matrix1.maxi();
        if (_matrix2.maxi() > _matrix1.maxi()){
            maxi = _matrix2.maxi();
        }

        uint maxj = _matrix1.maxj();
        if (_matrix2.maxj() > _matrix1.maxj()){
            maxj = _matrix2.maxj();
        }

        for (uint i=0; i < maxi; i++) {
            for (uint j=0; j < maxj; j++) {
                if ((_matrix1.elementAt(i,j)>0) && (_matrix2.elementAt(i,j)>0)) {
        _matrix1.setElement(i,j,_matrix1.elementAt(i,j) - _matrix2.elementAt(i,j));
                }
            }
        }    
    }
}

In practical scenarios, working with matrixes bigger than 10 is pretty much unpractical. Even with matrixes smaller than 10, you have to calculate with a gas cost of 5000 - 20000 for each modified value.