Direct Delta Mush Skinning and Variants Eq. 1

An example from Direct Delta Mush Skinning and Variants Eq. 1

The original equation:

placeholder

I❤️LA implementation:

v_i = ∑_j w_i,j M_j u_i

where

w ∈ ℝ^(n×m)
M_j ∈ ℝ^(4×4)
u_i ∈ ℝ^4

I❤️LA compiled to C++/Eigen:

/*
v_i = ∑_j w_i,j M_j u_i

where

w ∈ ℝ^(n×m)
M_j ∈ ℝ^(4×4)
u_i ∈ ℝ^4
*/
#include <Eigen/Core>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <iostream>
#include <set>

struct delta_mush_1ResultType {
    std::vector<Eigen::Matrix<double, 4, 1>> v;
    delta_mush_1ResultType(const std::vector<Eigen::Matrix<double, 4, 1>> & v)
    : v(v)
    {}
};

delta_mush_1ResultType delta_mush_1(
    const Eigen::MatrixXd & w,
    const std::vector<Eigen::Matrix<double, 4, 4>> & M,
    const std::vector<Eigen::Matrix<double, 4, 1>> & u)
{
    const long n = w.rows();
    const long m = w.cols();
    const long dim_0 = M.size();
    const long dim_1 = u.size();
    assert( w.rows() == n );
    assert( dim_0 == m );
    assert( dim_1 == n );

    std::vector<Eigen::Matrix<double, 4, 1>> v(dim_1);
    for( int i=1; i<=dim_1; i++){
        Eigen::MatrixXd sum_0 = Eigen::MatrixXd::Zero(4, 1);
        for(int j=1; j<=M.size(); j++){
            sum_0 += w(i-1, j-1) * M.at(j-1) * u.at(i-1);
        }
        v.at(i-1) = sum_0;
    }

    return delta_mush_1ResultType(v);
}


void generateRandomData(Eigen::MatrixXd & w,
    std::vector<Eigen::Matrix<double, 4, 4>> & M,
    std::vector<Eigen::Matrix<double, 4, 1>> & u)
{
    const int n = rand()%10;
    const int dim_1 = n;
    const int m = rand()%10;
    const int dim_0 = m;
    w = Eigen::MatrixXd::Random(n, m);
    M.resize(dim_0);
    for(int i=0; i<dim_0; i++){
        M[i] = Eigen::MatrixXd::Random(4, 4);
    }
    u.resize(dim_1);
    for(int i=0; i<dim_1; i++){
        u[i] = Eigen::VectorXd::Random(4);
    }
}


int main(int argc, char *argv[])
{
    srand((int)time(NULL));
    Eigen::MatrixXd w;
    std::vector<Eigen::Matrix<double, 4, 4>> M;
    std::vector<Eigen::Matrix<double, 4, 1>> u;
    generateRandomData(w, M, u);
    delta_mush_1ResultType func_value = delta_mush_1(w, M, u);
    std::cout<<"vector return value:"<<std::endl;
    for(int i=0; i<func_value.v.size(); i++){
        std::cout<<"i:"<<i<<", value:\n"<<func_value.v.at(i)<<std::endl;
    }
    return 0;
}

I❤️LA compiled to Python/NumPy/SciPy:

"""
v_i = ∑_j w_i,j M_j u_i

where

w ∈ ℝ^(n×m)
M_j ∈ ℝ^(4×4)
u_i ∈ ℝ^4
"""
import numpy as np
import scipy
import scipy.linalg
from scipy import sparse
from scipy.integrate import quad
from scipy.optimize import minimize


class delta_mush_1ResultType:
    def __init__( self, v):
        self.v = v


def delta_mush_1(w, M, u):
    w = np.asarray(w, dtype=np.float64)
    M = np.asarray(M, dtype=np.float64)
    u = np.asarray(u, dtype=np.float64)

    n = w.shape[0]
    m = w.shape[1]
    dim_0 = M.shape[0]
    dim_1 = u.shape[0]
    assert w.shape == (n, m)
    assert M.shape == (dim_0, 4, 4)
    assert u.shape == (dim_1, 4, )
    assert dim_0 == m 
    assert dim_1 == n 

    v = np.zeros((dim_1, 4, ))
    for i in range(1, dim_1+1):
        sum_0 = np.zeros((4, ))
        for j in range(1, len(M)+1):
            sum_0 += w[i-1, j-1] * M[j-1] @ u[i-1]
        v[i-1] = sum_0
    return delta_mush_1ResultType(v)


def generateRandomData():
    n = np.random.randint(10)
    dim_1 = n
    m = np.random.randint(10)
    dim_0 = m
    w = np.random.randn(n, m)
    M = np.random.randn(dim_0, 4, 4)
    u = np.random.randn(dim_1, 4, )
    return w, M, u


if __name__ == '__main__':
    w, M, u = generateRandomData()
    print("w:", w)
    print("M:", M)
    print("u:", u)
    func_value = delta_mush_1(w, M, u)
    print("return value: ", func_value.v)

I❤️LA compiled to MATLAB:

function output = delta_mush_1(w, M, u)
% output = delta_mush_1(w, M, u)
%
%    v_i = ∑_j w_i,j M_j u_i
%    
%    where
%    
%    w ∈ ℝ^(n×m)
%    M_j ∈ ℝ^(4×4)
%    u_i ∈ ℝ^4
    if nargin==0
        warning('generating random input data');
        [w, M, u] = generateRandomData();
    end
    function [w, M, u] = generateRandomData()
        n = randi(10);
        dim_1 = n;
        m = randi(10);
        dim_0 = m;
        w = randn(n, m);
        M = randn(dim_0,4,4);
        u = randn(dim_1,4);
    end

    n = size(w, 1);
    m = size(w, 2);
    dim_0 = size(M, 1);
    dim_1 = size(u, 1);
    assert( isequal(size(w), [n, m]) );
    assert( isequal(size(M), [dim_0, 4, 4]) );
    assert( isequal(size(u), [dim_1, 4]) );
    assert( dim_0 == m );
    assert( dim_1 == n );

    v = zeros(dim_1, 4);
    for i = 1:dim_1
        sum_0 = zeros(4,1);
        for j = 1:size(M, 1)
            sum_0 = sum_0 + w(i, j) * squeeze(M(j,:,:)) * u(i,:)';
        end
        v(i,:) = (sum_0)';
    end
    output.v = v;
end

I❤️LA compiled to LaTeX:

\documentclass[12pt]{article}
\usepackage{mathdots}
\usepackage[bb=boondox]{mathalfa}
\usepackage{mathtools}
\usepackage{amssymb}
\usepackage{libertine}
\DeclareMathOperator*{\argmax}{arg\,max}
\DeclareMathOperator*{\argmin}{arg\,min}
\usepackage[paperheight=8in,paperwidth=4in,margin=.3in,heightrounded]{geometry}
\let\originalleft\left
\let\originalright\right
\renewcommand{\left}{\mathopen{}\mathclose\bgroup\originalleft}
\renewcommand{\right}{\aftergroup\egroup\originalright}
\begin{document}

\begin{center}
\resizebox{\textwidth}{!} 
{
\begin{minipage}[c]{\textwidth}
\begin{align*}
\mathit{v}_{ \mathit{i} } & = \sum_\mathit{j} \mathit{w}_{\mathit{i}, \mathit{j}}\mathit{M}_{ \mathit{j} }\mathit{u}_{ \mathit{i} } \\
\intertext{where} 
\mathit{w} & \in \mathbb{R}^{ \mathit{n} \times \mathit{m} } \\
\mathit{M}_{\mathit{j}} & \in \mathbb{R}^{ 4 \times 4 } \\
\mathit{u}_{\mathit{i}} & \in \mathbb{R}^{ 4} \\
\\
\end{align*}
\end{minipage}
}
\end{center}

\end{document}

I❤️LA LaTeX output: