0

I tried to implement strassens algorithm for two 2x2 matrices in order to make a recursive matrix multiplication algorithm however the implementation doesn't compile giving me errors like:

"strassen was not declared in this scope" and "unqualified-id"

Here's the code:

#include <iostream>
#include <cstdlib>

using namespace std;

int[][] strassen(int A[][2], int B[][2])
{
    int s1 = B[0][1] - B[1][1];
    int s2 = A[0][0] + A[0][1];
    int s3 = A[1][0] + A[1][1];
    int s4 = B[1][0] - B[0][0];
    int s5 = A[0][0] + A[1][1];
    int s6 = B[0][0] + B[1][1];
    int s7 = A[0][1] - A[1][1];
    int s8 = B[1][0] + B[1][1];
    int s9 = A[0][0] - A[1][0];
    int s10 = B[0][0] + B[0][1];

    int p1 = A[0][0] * s1;
    int p2 = s2 * B[1][1];
    int p3 = s3 * B[0][0];
    int p4 = A[1][1] * s4;
    int p5 = s5 * s6;
    int p6 = s7 * s8;
    int p7 = s9 * s10;

int C[2][2];

C[0][0] = p5 + p4 - p2 + p6;
C[0][1] = p1 + p2;
C[1][0] = p3 + p4;
C[1][1] = p5 + p1 - p3 - p7;

return C[][];
}

int main()
{
    int A[2][2] = {{1,3},{7,5}};
    int B[2][2] = {{6,8},{4,2}};
    int C[][2] = strassen(A,B);
    cout<<C[0][0]<<endl<<C[0][1]<<endl<<C[1][0]<<endl<<C[1][1]<<endl;
    return 0;
}

Could you tell me why I'm getting the compile time errors. I also need to know how to malloc space for a 2D array, as my current implementation of C will go out of scope as soon as the function exits returning garbage values.

Rama
  • 3,222
  • 2
  • 11
  • 26
zaidjan1295
  • 39
  • 1
  • 8
  • 2
    You should *always* post your compiler/linker errors *verbatim*. – Jesper Juhl Apr 03 '17 at 19:20
  • 3
    "return C[][];" - what exactly did you intend to achieve by that? – Jesper Juhl Apr 03 '17 at 19:21
  • 3
    Forget the `malloc` thing! Don't use it in C++! – dtell Apr 03 '17 at 19:22
  • The problem is that you created a function that requires A[][] which is a dereferenced pointer but try to pass a pointer in main to it. I bet your compiler tells something like "candidate strassen(...) can't be used..." – dtell Apr 03 '17 at 19:24
  • 1
    Since you have compilation errors in the definition of `strassen`, it is never defined. You need to fix errors in order of occurrence. – molbdnilo Apr 03 '17 at 19:27
  • It looks like you want to return `C`, but that would be a mistake because it's a local variable. You'd need to *dynamically* allocate memory to avoid that... or use a nested `std::vector`, which is way easier. (or `std::array` if you know the size ahead of time) – AndyG Apr 03 '17 at 19:28
  • Why all the C style arrays? Why not `std::vector`? – Jesper Juhl Apr 03 '17 at 19:29
  • Why are you reinventing the wheel? Can't you use a matrix library? – Rama Apr 03 '17 at 19:33

2 Answers2

1

As mentioned in many comments your solution is typical C style which can create many problems (especially when you are a beginner). C++ provides powerful, memory save and easy to use workarounds for a lot of cases where C can get complicated.

Don't get me wrong: C is a great language but when you decided to use C++, use it!

For your case std::array is perfect since you use arrays of clearly defined size. It works like this: You define the size and the type of its content with std::array<type,size>.

The following code implements your attempt using std::array:

#include <iostream>
// #include <cstdlib> // use C libraries only when really needed
#include <array> 

using namespace std;

array<array<int,2>,2> strassen(array<array<int,2>,2> A, array<array<int,2>,2> B){
    int s1 = B[0][1] - B[1][1];
    int s2 = A[0][0] + A[0][1];
    int s3 = A[1][0] + A[1][1];
    int s4 = B[1][0] - B[0][0];
    int s5 = A[0][0] + A[1][1];
    int s6 = B[0][0] + B[1][1];
    int s7 = A[0][1] - A[1][1];
    int s8 = B[1][0] + B[1][1];
    int s9 = A[0][0] - A[1][0];
    int s10 = B[0][0] + B[0][1];

    int p1 = A[0][0] * s1;
    int p2 = s2 * B[1][1];
    int p3 = s3 * B[0][0];
    int p4 = A[1][1] * s4;
    int p5 = s5 * s6;
    int p6 = s7 * s8;
    int p7 = s9 * s10;

    array<array<int,2>,2> C;

    C[0][0] = p5 + p4 - p2 + p6;
    C[0][1] = p1 + p2;
    C[1][0] = p3 + p4;
    C[1][1] = p5 + p1 - p3 - p7;

    return C;
}

int main(){
    array<array<int,2>,2> A  {{{{1,3}},{{7,5}}}};
    array<array<int,2>,2> B  {{{{6,8}},{{4,2}}}};
    array<array<int,2>,2> C = strassen(A,B);
    cout<<C[0][0]<<endl<<C[0][1]<<endl<<C[1][0]<<endl<<C[1][1]<<endl;
}

As you did with C style arrays, two dimensional arrrays are realized as array of array thus std::array<std::array<T,size>,size>>.

For the strange looking number of braces in the initialization of A and B see the top answer to Why can't simple initialize (with braces) 2D std::array? [duplicate].

Please note that the way I initialized the arrays in main() requires the -std=c++11 compiler flag. Compile with something like gcc -std=c++11 -o strassen strassen.c

Community
  • 1
  • 1
dtell
  • 2,488
  • 1
  • 14
  • 29
0

There are a couple of reasons why your code doesn't compile: You are getting the error of function out of scope because the function strassen is not compiling, and it is not compiling because you are returning an array declared inside the function.

A good rule of thumb is to never return arrays nor pass them as arguments, use references instead, it saves memory and time.

Heres is a solution without using dynamic memory (although I think it would be easier to do it that way)

#include <iostream>

using namespace std;

void strassen(int (&A)[2][2], int (&B)[2][2], int (&C)[2][2])
{
    int s1 = B[0][1] - B[1][1];
    int s2 = A[0][0] + A[0][1];
    int s3 = A[1][0] + A[1][1];
    int s4 = B[1][0] - B[0][0];
    int s5 = A[0][0] + A[1][1];
    int s6 = B[0][0] + B[1][1];
    int s7 = A[0][1] - A[1][1];
    int s8 = B[1][0] + B[1][1];
    int s9 = A[0][0] - A[1][0];
    int s10 = B[0][0] + B[0][1];

    int p1 = A[0][0] * s1;
    int p2 = s2 * B[1][1];
    int p3 = s3 * B[0][0];
    int p4 = A[1][1] * s4;
    int p5 = s5 * s6;
    int p6 = s7 * s8;
    int p7 = s9 * s10;

    C[0][0] = p5 + p4 - p2 + p6;
    C[0][1] = p1 + p2;
    C[1][0] = p3 + p4;
    C[1][1] = p5 + p1 - p3 - p7;

}

int main()
{
    int A[2][2] = {{1,3},{7,5}};
    int B[2][2] = {{6,8},{4,2}};
    int C[2][2];

    strassen(A,B,C);

    cout<<C[0][0]<<endl<<C[0][1]<<endl<<C[1][0]<<endl<<C[1][1]<<endl;

    return 0;
}

Note that you are passing C as a reference to the function so the changes that you make to it inside the function will also affect it outside the function

Sacha
  • 245
  • 2
  • 10
  • what does it mean when we pass intergers to a function but use "&" in the declaration. Like you have, passed in A,B,C are parameters but when you've defined the function you've used (&A),(&B),(&C). Also why are they in parenthesis. – zaidjan1295 Apr 04 '17 at 14:18
  • That symbol implies that you are not copying the parameters but rather sending a reference to them, the variables in the function will reference the exact same memory space as the variables that you passed as paremeters. They are in parenthesis to specify that you are not sending an array of references but a reference to an array. – Sacha Apr 04 '17 at 18:01
  • if you are a sending a reference (i.e an adress), why didnt you dereference A,B,C when you did all the corresponding math? – zaidjan1295 Apr 05 '17 at 13:27
  • Because references don't need dereferencing, pointers do. That's the main diference between references and pointers. A reference is a variable that references another variable, not a variable that stores a reference. – Sacha Apr 05 '17 at 17:10
  • aren't arrays supposed to be passed by reference anyway. So why do you need to categorically write (&A), etc ? – zaidjan1295 Apr 05 '17 at 20:04
  • Arrays aren't really passed by reference, but arrays are just another name for pointers, so when you pass an array to a function you are actually passing the pointer as an argument( this contradicts what i said earlier, it was what i was told in class, but I just did a empirical test and it proved it wrong ). Yes it is redundant to make a reference out of a pointer – Sacha Apr 07 '17 at 15:03