Search code examples
c++arraysmatrixvectordeque

Generalizing a function for matrices of different types (e.g., deque of vectors, array of vectors, and vice versa)


I have created a version that works for vectors, but I am currently at a standstill regarding how to adapt it to work with other types of matrices. I don't know if I should, and if I can give the function pointers or iterators that point to the beginning and the end of the matrices, but I don't know if that works for arrays like int array[]?

#include <iostream>
#include <cmath>
#include <vector>
#include <deque>
#include <iterator>
#include <iomanip>

template<typename T,typename T1,typename F>
std::vector<std::vector<T>> GeneralizedKroneckerProduct(std::vector<std::vector<T>>M1, std::vector<std::vector<T>>M2, F &f ){
    int m=M1.size();
    int n=M1.at(0).size();
    int p=M2.size();
    int q=M2.at(0).size();
    std::vector<std::vector<T1>>result(m*p,std::vector<T1>(n*q));
    for(int i=0; i<m;i++){
        for(int j=0; j<n;j++){
            for(int k=0; k<p;k++){
                for(int z=0; z<q;z++){
                    result.at(i*p+k).at(j*q+z)=f(M1.at(i).at(j),M2.at(k).at(z));
                }
            }
        }
    }
    return result;
}

int main ()
{
    std::cout<<"Enter dimensions of the first matrix: ";
    int m=0,n=0;
    std::cin>>m>>n;
    std::cout<<"Enter elements of the first matrix: ";
    std::vector<std::vector<int>>A;
    std::vector<int>temp;
    int number;
    for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){
            std::cin>>number;
            temp.push_back(number);
        }
        A.push_back(temp);
        temp.clear();
    }
    std::cout<<"Enter dimensions of the second matrix: ";
    int p=0,q=0;
    std::cin>>p>>q;
    std::cout<<"Enter elements of the second matrix: ";
    std::vector<std::vector<int>>B;
    for(int i=0;i<p;i++){
        for(int j=0;j<q;j++){
            std::cin>>number;
            temp.push_back(number);
        }
        B.push_back(temp);
        temp.clear();
    }

    auto f=[](int x, int y){return x*y;};
    auto result=GeneralizedKroneckerProduct<int,int,decltype(f)>(A, B,f);
    std::cout<<"Their Kronecker product is: "<<std::endl;
    for(const auto &row:result){
        for(const auto &number:row){
            std::cout<<std::setw(5)<<number<<" ";
        }
        std::cout<<std::endl;
    }

    return 0;
}

Solution

  • I fixed it this is the final version

    #include <iostream>
    #include <cmath>
    #include <stdexcept>
    #include <vector>
    #include <deque>
    #include <iterator>
    #include <iomanip>
    
    int NumDigits(int n){
        int b=0;
        if(n<1)b++;
        return n==0?1:1+b+int(std::log10(std::abs(n))+1e-10);
    }
    
    template<typename T,typename T1,typename F>
    auto GeneralizedKroneckerProduct( T &P1,  T1 &P2, const F &f ){
        int br1=0,br2=0;
        /*
        if(std::end(P1)-std::begin(P1)==0)
        br1++;
        if(std::end(P2)-std::begin(P2)==0)
        br2++;
        */
         if(std::distance(std::begin(P1),std::end(P1))==0)
        br1++;
        if(std::distance(std::begin(P2),std::end(P2))==0)
        br2++;
        if(br1>0 && br2==0)
        throw::std::domain_error("First parameter does not have matrix form");
        else if(br1==0 && br2>0)
        throw::std::domain_error("Second parameter does not have matrix form");
        if(br1>0 && br2>0)
        throw::std::domain_error("Parameters do not have matrix form");
        /*auto m=std::end(P1)-std::begin(P1);
        auto n=std::end(P1[0])-std::begin(P1[0]);
        auto p=std::end(P2)-std::begin(P2);
        auto q=std::end(P2[0])-std::begin(P2[0]);
        */
        auto m=std::distance(std::begin(P1),std::end(P1));
        auto n=std::distance(std::begin(P1[0]),std::end(P1[0]));
        auto p=std::distance(std::begin(P2),std::end(P2));
        auto q=std::distance(std::begin(P2[0]),std::end(P2[0]));
    
        
        for(int i=1;i<m;i++){
            if (std::distance(std::begin(P1[i]),std::end(P1[i]))!=n)
            br1++;
        }
        for(int i=1;i<p;i++){
            if (std::distance(std::begin(P2[i]),std::end(P2[i]))!=q)
            br2++;
        }
        if(br1>0 && br2==0)
        throw::std::domain_error("First parameter does not have matrix form");
        else if(br1==0 && br2>0)
        throw::std::domain_error("Second parameter does not have matrix form");
        if(br1>0 && br2>0)
        throw::std::domain_error("Parameters do not have matrix form");
        
        using Tip=typename std::remove_reference<decltype(f(P1[0][0],P2[0][0]))>::type;
        std::vector<std::vector<Tip>>result(m*p,std::vector<Tip>(n*q));
    
        try{
        for(int i=0; i<m;i++){
            for(int j=0; j<n;j++){
                for(int k=0; k<p;k++){
                    for(int z=0; z<q;z++){
                        result[i*p+k][j*q+z]=f(P1[i][j],P2[k][z]);
            
        }
        }
        }
        }}catch(...){
            throw::std::runtime_error("Unexpected problems during calculation");
        }
        return result;
    }
    
    int main ()
    {
        std::cout<<"Enter dimensions of the first matrix: ";
        int m=0,n=0;
        std::cin>>m>>n;
        std::cout<<"Enter elements of the first matrix: ";
        std::vector<std::deque<double>>A(m,std::deque<double>(n));
        std::vector<int>temp;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                std::cin>>A[i][j];
            }
        }
        std::cout<<"Enter dimensions of the second matrix: ";
        int p=0,q=0;
        std::cin>>p>>q;
        std::cout<<"Enter elements of the second matrix: ";
        std::deque<std::vector<double>>B(p,std::vector<double>(q));
        for(int i=0;i<p;i++){
            for(int j=0;j<q;j++){
                std::cin>>B[i][j];
            }
        }
    
        auto f=[](double x, double y){return x*y;};
        auto result=GeneralizedKroneckerProduct(A, B,f);
        std::cout<<"Their Kronecker product is: "<<std::endl;
        int max=-1;
        for(const auto &row:result){
            for(const auto &number:row){
                if(max<NumDigits(number))
                max=NumDigits(number);
            
        }}
        for(const auto &row:result){
            for(const auto &number:row){
                std::cout<<std::setw(max)<<number<<" ";
            
        }
        std::cout<<std::endl;
    
        }
    
        return 0;
    }