#include <stdio.h>
#include <stdlib.h>
#include <check.h>
#include <complex.h>
#include <math.h>

#include "libharkio3.h"

// Set up good matrices for int32, float32, complex.
#define numoks 5
harkio_Matrix *goodMatrixInt[numoks];
harkio_Matrix *goodMatrixFloat[numoks];
harkio_Matrix *goodMatrixComplex[numoks];

int iC[numoks];
float fC[numoks];
COMPLEX_TYPE cC[numoks];

// for power index
int iCpow[numoks];
float fCpow[numoks];
COMPLEX_TYPE cCpow[numoks];

int okrows[numoks] = { 100, 100,    1, 100, 1};
int okcols[numoks] = { 100, 100,  100,   1, 1};

int ngrows[] = {-1, -1, -1,  0,  0,  0,  1,  1};
int ngcols[] = { 0, -1,  1,  0, -1,  1,  0, -1};
int numngs = 8;

int wrongcols[] = {-10, -10,  -10,   0,    0, 1000, 1000, 1000};
int wrongrows[] = {-10,   0, 1000, -10, 1000,  -10,    0, 1000};
int numwrongs = 8;

int reshaperows[] = {25, 50, 10, 5, 1};
int reshapecols[] = {400, 200, 10, 20, 1};

char *types[3] = {"int32", "float32", "complex"};
int numtypes = 3;

void setup(void)
{
    int m, i, j;
    // fprintf(stderr, "setup\n");
    for (m=0; m<numoks; m++) {
        goodMatrixInt[m]     = harkio_Matrix_new("int32",    okrows[m],  okcols[m]);
        goodMatrixFloat[m]   = harkio_Matrix_new("float32",  okrows[m],  okcols[m]);
        goodMatrixComplex[m] = harkio_Matrix_new("complex",  okrows[m],  okcols[m]);
        for (i=0; i<okrows[m]; i++) {
            for (j=0; j<okcols[m]; j++) {
                harkio_Matrix_setValueInt32(
                    goodMatrixInt[m], i, j, 1 + rand() % 100);
                harkio_Matrix_setValueFloat32(
                    goodMatrixFloat[m], i, j, 1 + rand() % 100 / 1.0);
                harkio_Matrix_setValueComplex(
                    goodMatrixComplex[m], i, j, 1 + rand() % 100 / 1.0 + (1 + rand() % 100 / 1.0) * _Complex_I);
            }
        }

        iC[m] = 1 + rand() % 100;
        fC[m] = 1 + rand() % 100 / 1.0;
        cC[m] = 1 + rand() % 100 / 1.0 + (1 + rand() % 100 / 1.0) * _Complex_I;

        iCpow[m] = (float)rand() / RAND_MAX * 10 - 5;
        fCpow[m] = (float)rand() / RAND_MAX * 10.0 - 5.0;
        cCpow[m] = (float)rand() / RAND_MAX * 10.0 - 5.0 + ((float)rand() / RAND_MAX * 10.0 - 5.0) * _Complex_I;
    }
    // fprintf(stderr, "setup done\n");
}

void setup4cosh(void)
{
    int m, i, j;
    // fprintf(stderr, "setup\n");
    for (m=0; m<numoks; m++) {
        goodMatrixInt[m]     = harkio_Matrix_new("int32",    okrows[m],  okcols[m]);
        goodMatrixFloat[m]   = harkio_Matrix_new("float32",  okrows[m],  okcols[m]);
        goodMatrixComplex[m] = harkio_Matrix_new("complex",  okrows[m],  okcols[m]);
        for (i=0; i<okrows[m]; i++) {
            for (j=0; j<okcols[m]; j++) {
                harkio_Matrix_setValueInt32(
                    goodMatrixInt[m], i, j, (float)rand() / RAND_MAX * 10 - 5);
                harkio_Matrix_setValueFloat32(
                    goodMatrixFloat[m], i, j, (float)rand() / RAND_MAX * 10.0 - 5.0);
                harkio_Matrix_setValueComplex(
                    goodMatrixComplex[m], i, j, (float)rand() / RAND_MAX * 10.0 - 5.0 + ((float)rand() / RAND_MAX * 10.0 - 5.0) * _Complex_I);
            }
        }
    }
    // fprintf(stderr, "setup done\n");
}

void teardown(void)
{
    int i;
    // fprintf(stderr, "teardown\n");
    for (i=0; i<numoks; i++) {
        harkio_Matrix_delete(&goodMatrixInt[i]);
        harkio_Matrix_delete(&goodMatrixFloat[i]);
        harkio_Matrix_delete(&goodMatrixComplex[i]);
    }
    // fprintf(stderr, "teardown done\n");
}

// new test
START_TEST(test_new)
{
    int i, itype;
    harkio_Matrix *m;

    // normal case
    for (i=0; i<numoks; i++) {
        for (itype=0; itype<numtypes; itype++) {
            m = harkio_Matrix_new(types[itype], okrows[i], okcols[i]);
            ck_assert(NULL != m);
            ck_assert_str_eq(m->type, types[itype]);
            ck_assert_int_eq(m->rows, okrows[i]);
            ck_assert_int_eq(m->cols, okcols[i]);
            ck_assert_str_eq(harkio_Matrix_getTag(m), "HARK1.3");
            harkio_Matrix_delete(&m);
        }
    }

    // wrong type
    ck_assert(NULL == harkio_Matrix_new("wrongtype", okrows[0], okcols[0]));
    ck_assert(NULL == harkio_Matrix_new("",          okrows[0], okcols[0]));

    // wrong size
    for (i=0; i<numngs; i++) {
        for (itype=0; itype<numtypes; itype++) {
            m = harkio_Matrix_new(types[itype], ngrows[i], ngcols[i]);
            ck_assert(NULL == m);
        }
    }
}
END_TEST

START_TEST(test_eye)
{
    harkio_Matrix *m;
    int i, j, k, itype;

    for (itype=0; itype<numtypes; itype++) {
        for (k=0; k<numoks; k++) {
            // eye
            m = harkio_Matrix_eye(types[itype], okrows[k]);
            ck_assert_str_eq(types[itype], m->type);
            ck_assert_int_eq(okrows[k], m->rows);
            ck_assert_int_eq(okrows[k], m->cols);
            for (i=0; i<m->rows; i++) {
                for (j=0; j<m->cols; j++) {
                    int ivalue;
                    float fvalue;
                    COMPLEX_TYPE cvalue;
                    if (strcmp(types[itype], "int32") == 0) {
                        harkio_Matrix_getValueInt32(m, i, j, &ivalue);
                        if (i == j) ck_assert_int_eq(1, ivalue);
                        else       ck_assert_int_eq(0, ivalue);
                    } else if (strcmp(types[itype], "float32") == 0) {
                        harkio_Matrix_getValueFloat32(m, i, j, &fvalue);
                        if (i == j) ck_assert(fabs(1 - fvalue) < 0.0001);
                        else       ck_assert(fabs(0 - fvalue) < 0.0001);
                    } else if (strcmp(types[itype], "complex") == 0) {
                        harkio_Matrix_getValueComplex(m, i, j, &cvalue);
                        if (i == j) ck_assert(1 == cvalue);
                        else       ck_assert(0 == cvalue);
                    }
                }
            }
            harkio_Matrix_delete(&m);
        }
    }

    // wrong type
    ck_assert(NULL == harkio_Matrix_eye("wrongtype", okrows[0]));
    ck_assert(NULL == harkio_Matrix_eye("",          okrows[0]));

    // wrong size
    for (itype=0; itype<numtypes; itype++) {
        m = harkio_Matrix_eye(types[itype], -1);
        ck_assert(NULL == m);
        m = harkio_Matrix_eye(types[itype],  0);
        ck_assert(NULL == m);
    }
}
END_TEST

START_TEST(test_zeros)
{
    harkio_Matrix *m;
    int i, j, k, itype;

    for (itype=0; itype<numtypes; itype++) {
        for (k=0; k<numoks; k++) {

            // zeros
            m = harkio_Matrix_zeros(types[itype], okrows[k], okcols[k]);
            ck_assert_str_eq(types[itype], m->type);
            ck_assert_int_eq(okrows[k], m->rows);
            ck_assert_int_eq(okcols[k], m->cols);
            for (i=0; i<m->rows; i++) {
                for (j=0; j<m->cols; j++) {
                    int ivalue;
                    float fvalue;
                    COMPLEX_TYPE cvalue;
                    if (strcmp(types[itype], "int32") == 0) {
                        harkio_Matrix_getValueInt32(m, i, j, &ivalue);
                        ck_assert_int_eq(0, ivalue);
                    } else if (strcmp(types[itype], "float32") == 0) {
                        harkio_Matrix_getValueFloat32(m, i, j, &fvalue);
                        ck_assert(fabs(fvalue) < 0.0001);
                    } else if (strcmp(types[itype], "complex") == 0) {
                        harkio_Matrix_getValueComplex(m, i, j, &cvalue);
                        ck_assert(0 == cvalue);
                    }
                }
            }
            harkio_Matrix_delete(&m);
        }
    }
    // wrong type
    ck_assert(NULL == harkio_Matrix_zeros("wrongtype", okrows[0], okcols[0]));
    ck_assert(NULL == harkio_Matrix_zeros("",          okrows[0], okcols[0]));

    // wrong size
    for (i=0; i<numngs; i++) {
        for (itype=0; itype<numtypes; itype++) {
            m = harkio_Matrix_zeros(types[itype], ngrows[i], ngcols[i]);
            ck_assert(NULL == m);
        }
    }
}
END_TEST

START_TEST(test_ones)
{
    harkio_Matrix *m;
    int i, j, k, itype;

    for (itype=0; itype<numtypes; itype++) {
        for (k=0; k<numoks; k++) {

            // ones
            m = harkio_Matrix_ones(types[itype], okrows[k], okcols[k]);
            ck_assert_str_eq(types[itype], m->type);
            ck_assert_int_eq(okrows[k], m->rows);
            ck_assert_int_eq(okcols[k], m->cols);
            for (i=0; i<m->rows; i++) {
                for (j=0; j<m->cols; j++) {
                    int ivalue;
                    float fvalue;
                    COMPLEX_TYPE cvalue;
                    if (strcmp(types[itype], "int32") == 0) {
                        harkio_Matrix_getValueInt32(m, i, j, &ivalue);
                        ck_assert_int_eq(1, ivalue);
                    } else if (strcmp(types[itype], "float32") == 0) {
                        harkio_Matrix_getValueFloat32(m, i, j, &fvalue);
                        ck_assert(fabs(1 - fvalue) < 0.0001);
                    } else if (strcmp(types[itype], "complex") == 0) {
                        harkio_Matrix_getValueComplex(m, i, j, &cvalue);
                        ck_assert(1 == cvalue);
                    }
                }
            }
            harkio_Matrix_delete(&m);
        }
    }
    // wrong type
    ck_assert(NULL == harkio_Matrix_ones("wrongtype", okrows[0], okcols[0]));
    ck_assert(NULL == harkio_Matrix_ones("",          okrows[0], okcols[0]));

    // wrong size
    for (i=0; i<numngs; i++) {
        for (itype=0; itype<numtypes; itype++) {
            m = harkio_Matrix_ones(types[itype], ngrows[i], ngcols[i]);
            ck_assert(NULL == m);
        }
    }
}
END_TEST

START_TEST(test_delete)
{
    harkio_Matrix *m = harkio_Matrix_new("int32", 10, 10);

    harkio_Matrix_delete(&m);
    ck_assert(m == NULL);

    harkio_Matrix_delete(&m);
    ck_assert(m == NULL);

    harkio_Matrix_delete(NULL);
}
END_TEST

START_TEST(test_vstack)
{
    setup();

    harkio_Matrix* mInt = harkio_Matrix_copy(goodMatrixInt[0]);
    ck_assert_ptr_eq(harkio_Matrix_vstack(mInt, goodMatrixInt[1]), mInt);
    ck_assert_int_eq(mInt->rows, okrows[0] + okrows[1]);
    ck_assert_int_eq(mInt->cols, okcols[0]);

    harkio_Matrix* mFlt = harkio_Matrix_copy(goodMatrixFloat[0]);
    ck_assert_ptr_eq(harkio_Matrix_vstack(mFlt, goodMatrixFloat[1]), mFlt);
    ck_assert_int_eq(mFlt->rows, okrows[0] + okrows[1]);
    ck_assert_int_eq(mFlt->cols, okcols[0]);

    harkio_Matrix* mCmp = harkio_Matrix_copy(goodMatrixComplex[0]);
    ck_assert_ptr_eq(harkio_Matrix_vstack(mCmp, goodMatrixComplex[1]), mCmp);
    ck_assert_int_eq(mCmp->rows, okrows[0] + okrows[1]);
    ck_assert_int_eq(mCmp->cols, okcols[0]);

    int i, j;
    for (j = 0; j < okcols[0]; j++) {
        int nSrc, nOrg;
        float fSrc, fOrg;
        COMPLEX_TYPE cSrc, cOrg;
        for (i = 0; i < okrows[0]; i++) {
            harkio_Matrix_getValueInt32(mInt, i, j, &nSrc);
            harkio_Matrix_getValueInt32(goodMatrixInt[0], i, j, &nOrg);
            ck_assert_int_eq(nSrc, nOrg);

            harkio_Matrix_getValueFloat32(mFlt, i, j, &fSrc);
            harkio_Matrix_getValueFloat32(goodMatrixFloat[0], i, j, &fOrg);
            ck_assert(fSrc == fOrg);

            harkio_Matrix_getValueComplex(mCmp, i, j, &cSrc);
            harkio_Matrix_getValueComplex(goodMatrixComplex[0], i, j, &cOrg);
            ck_assert(cSrc == cOrg);
        }
        for (i = 0;i < okrows[1]; i++) {
            harkio_Matrix_getValueInt32(mInt, okrows[0] + i, j, &nSrc);
            harkio_Matrix_getValueInt32(goodMatrixInt[1], i, j, &nOrg);
            ck_assert_int_eq(nSrc, nOrg);

            harkio_Matrix_getValueFloat32(mFlt, okrows[0] + i, j, &fSrc);
            harkio_Matrix_getValueFloat32(goodMatrixFloat[1], i, j, &fOrg);
            ck_assert(fSrc == fOrg);

            harkio_Matrix_getValueComplex(mCmp, okrows[0] + i, j, &cSrc);
            harkio_Matrix_getValueComplex(goodMatrixComplex[1], i, j, &cOrg);
            ck_assert(cSrc == cOrg);
        }
    }

    // error case
    ck_assert_ptr_eq(harkio_Matrix_vstack(NULL, goodMatrixInt[1]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_vstack(goodMatrixFloat[0], NULL), NULL);
    ck_assert_ptr_eq(harkio_Matrix_vstack(goodMatrixComplex[0], goodMatrixComplex[3]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_vstack(goodMatrixInt[0], goodMatrixFloat[0]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_vstack(goodMatrixFloat[0], goodMatrixComplex[0]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_vstack(goodMatrixComplex[0], goodMatrixInt[0]), NULL);

    teardown();
    harkio_Matrix_delete(&mInt);
    harkio_Matrix_delete(&mFlt);
    harkio_Matrix_delete(&mCmp);
}
END_TEST

START_TEST(test_setgetValueInt)
{
    int i, j;
    harkio_Matrix *m;
    int rows = 100, cols = 300;
    int tmp1, tmp2;

    m = harkio_Matrix_new("int32", rows, cols);
    for (i=0; i<m->rows; i++) {
        for (j=0; j<m->cols; j++) {
            tmp1 = rand() % 100;
            ck_assert_int_eq(harkio_Matrix_setValueInt32(m, i, j, tmp1), EXIT_SUCCESS);
            ck_assert_int_eq(harkio_Matrix_getValueInt32(m, i, j, &tmp2), EXIT_SUCCESS);
            ck_assert_int_eq(tmp1, tmp2);
        }
    }

    // wrong positions
    for (i=0; i<numwrongs; i++) {
        fprintf(stderr, "wrong pos %d, %d\n", wrongrows[i], wrongcols[i]);
        ck_assert_int_eq(harkio_Matrix_setValueInt32(m, wrongrows[i], wrongcols[i],  tmp1), EXIT_FAILURE);
        ck_assert_int_eq(harkio_Matrix_getValueInt32(m, wrongrows[i], wrongcols[i], &tmp1), EXIT_FAILURE);
    }

    harkio_Matrix_delete(&m);
}
END_TEST

START_TEST(test_setgetValueFloat)
{
    int i, j;
    harkio_Matrix *m;
    int rows = 100, cols = 300;
    float tmp1, tmp2;

    m = harkio_Matrix_new("float32", rows, cols);
    for (i=0; i<m->rows; i++) {
        for (j=0; j<m->cols; j++) {
            tmp1 = rand() % 100 / 100;
            ck_assert_int_eq(harkio_Matrix_setValueFloat32(m, i, j, tmp1), EXIT_SUCCESS);
            ck_assert_int_eq(harkio_Matrix_getValueFloat32(m, i, j, &tmp2), EXIT_SUCCESS);
            ck_assert(tmp1 == tmp2);
        }
    }
    // wrong positions
    for (i=0; i<numwrongs; i++) {
        ck_assert_int_eq(harkio_Matrix_setValueFloat32(m, wrongrows[i], wrongcols[i],  tmp1), EXIT_FAILURE);
        ck_assert_int_eq(harkio_Matrix_getValueFloat32(m, wrongrows[i], wrongcols[i], &tmp1), EXIT_FAILURE);
    }

    harkio_Matrix_delete(&m);
}
END_TEST

START_TEST(test_setgetValueComplex)
{
    int i, j;
    harkio_Matrix *m;
    int rows = 100, cols = 300;
    COMPLEX_TYPE tmp1, tmp2;

    m = harkio_Matrix_new("complex", rows, cols);
    for (i=0; i<m->rows; i++) {
        for (j=0; j<m->cols; j++) {
            tmp1 = rand() % 100 + rand() % 100 * _Complex_I;
            ck_assert_int_eq(harkio_Matrix_setValueComplex(m, i, j, tmp1), EXIT_SUCCESS);
            ck_assert_int_eq(harkio_Matrix_getValueComplex(m, i, j, &tmp2), EXIT_SUCCESS);
            ck_assert(tmp1 == tmp2);
        }
    }

    // wrong positions
    for (i=0; i<numwrongs; i++) {
        ck_assert_int_eq(harkio_Matrix_setValueComplex(m, wrongrows[i], wrongcols[i],  tmp1), EXIT_FAILURE);
        ck_assert_int_eq(harkio_Matrix_getValueComplex(m, wrongrows[i], wrongcols[i], &tmp1), EXIT_FAILURE);
    }

    harkio_Matrix_delete(&m);

}
END_TEST

START_TEST(test_size)
{
    int i, itypes;
    harkio_Matrix *m;
    int size[2];

    for (i=0; i<numoks; i++) {
        for (itypes=0; itypes<numtypes; itypes++) {
            m = harkio_Matrix_new(types[itypes], okrows[i], okcols[i]);
            harkio_Matrix_size(m, size);
            ck_assert_int_eq(m->rows, size[0]);
            ck_assert_int_eq(m->cols, size[1]);
            ck_assert_int_eq(m->rows, okrows[i]);
            ck_assert_int_eq(m->cols, okcols[i]);
            harkio_Matrix_delete(&m);
        }
    }
}
END_TEST

START_TEST(test_compare)
{
    harkio_Matrix *m1, *m2;
    int itype;

    for (itype=0; itype<numtypes; itype++) {
        // same size, same value
        m1 = harkio_Matrix_ones(types[itype], 100, 200);
        m2 = harkio_Matrix_ones(types[itype], 100, 200);
        ck_assert_int_eq(EXIT_SUCCESS, harkio_Matrix_isEqual(m1, m2));
        harkio_Matrix_delete(&m1);
        harkio_Matrix_delete(&m2);

        // same size, different value
        m1 = harkio_Matrix_zeros(types[itype], 100, 200);
        m2 = harkio_Matrix_ones(types[itype], 100, 200);
        ck_assert_int_eq(EXIT_FAILURE, harkio_Matrix_isEqual(m1, m2));
        harkio_Matrix_delete(&m1);
        harkio_Matrix_delete(&m2);

        // different size
        m1 = harkio_Matrix_ones(types[itype], 101, 200);
        m2 = harkio_Matrix_ones(types[itype], 100, 200);
        ck_assert_int_eq(EXIT_FAILURE, harkio_Matrix_isEqual(m1, m2));
        harkio_Matrix_delete(&m1);
        harkio_Matrix_delete(&m2);

        // NULL, normal
        m1 = harkio_Matrix_ones(types[itype], 100, 200);
        ck_assert_int_eq(EXIT_FAILURE, harkio_Matrix_isEqual(m1, NULL));
        harkio_Matrix_delete(&m1);

        // normal, NULL
        m1 = harkio_Matrix_ones(types[itype], 100, 200);
        ck_assert_int_eq(EXIT_FAILURE, harkio_Matrix_isEqual(NULL, m1));
        harkio_Matrix_delete(&m1);

        // NULL, NULL
        ck_assert_int_eq(EXIT_FAILURE, harkio_Matrix_isEqual(NULL, NULL));
    }
}
END_TEST

/*
START_TEST (test_add_fast)
{
    int i, j;
    harkio_Matrix *m, *n, *o;

    int ivalue1; float fvalue1; COMPLEX_TYPE cvalue1;
    int ivalue2; float fvalue2; COMPLEX_TYPE cvalue2;
    int ivalue3; float fvalue3; COMPLEX_TYPE cvalue3;

    setup();

    o = harkio_Matrix_copy(goodMatrixInt[0]);
    m = harkio_Matrix_add_fast(o, goodMatrixInt[1]);
    for(i=0; i<goodMatrixInt[0]->rows; i++){
        for(j=0; j<goodMatrixInt[0]->cols; j++){
            harkio_Matrix_getValueInt32(goodMatrixInt[0], i, j, &ivalue1);
            harkio_Matrix_getValueInt32(goodMatrixInt[1], i, j, &ivalue2);
            harkio_Matrix_getValueInt32(m, i, j, &ivalue3);
            ck_assert_int_eq(ivalue1 + ivalue2, ivalue3);
        }
    }
    harkio_Matrix_delete(&m);
    harkio_Matrix_delete(&o);

    o = harkio_Matrix_copy(goodMatrixFloat[0]);
    m = harkio_Matrix_add_fast(o, goodMatrixFloat[1]);
    for(i=0; i<goodMatrixFloat[0]->rows; i++){
        for(j=0; j<goodMatrixInt[0]->cols; j++){
            harkio_Matrix_getValueFloat32(goodMatrixFloat[0], i, j, &fvalue1);
            harkio_Matrix_getValueFloat32(goodMatrixFloat[1], i, j, &fvalue2);
            harkio_Matrix_getValueFloat32(m, i, j, &fvalue3);
            ck_assert(fabs(fvalue1 + fvalue2 - fvalue3) < 0.00001);
        }
    }
    harkio_Matrix_delete(&m);
    harkio_Matrix_delete(&o);

    o = harkio_Matrix_copy(goodMatrixComplex[0]);
    m = harkio_Matrix_add_fast(o, goodMatrixComplex[1]);
    for(i=0; i<goodMatrixComplex[0]->rows; i++){
        for(j=0; j<goodMatrixComplex[0]->cols; j++){
            harkio_Matrix_getValueComplex(goodMatrixComplex[0], i, j, &cvalue1);
            harkio_Matrix_getValueComplex(goodMatrixComplex[1], i, j, &cvalue2);
            harkio_Matrix_getValueComplex(m, i, j, &cvalue3);
            ck_assert(cvalue1 + cvalue2 == cvalue3);
        }
    }
    harkio_Matrix_delete(&m);
    harkio_Matrix_delete(&o);

    // size mismatch
    ck_assert_ptr_eq(harkio_Matrix_add_fast(goodMatrixInt[1], goodMatrixInt[2]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_add_fast(goodMatrixFloat[1], goodMatrixFloat[2]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_add_fast(goodMatrixComplex[1], goodMatrixComplex[2]), NULL);

    ck_assert_ptr_eq(harkio_Matrix_add_fast(goodMatrixInt[1], NULL), NULL);
    ck_assert_ptr_eq(harkio_Matrix_add_fast(NULL, goodMatrixInt[1]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_add_fast(NULL, NULL), NULL);

    // wrong type
    m = harkio_Matrix_new("wrong", 100, 100);
    n = harkio_Matrix_new("wrong", 100, 100);
    ck_assert_ptr_eq(harkio_Matrix_add_fast(m, n), NULL);
    harkio_Matrix_delete(&m);
    harkio_Matrix_delete(&n);

    teardown();
}
END_TEST
*/

START_TEST(test_add)
{
    int i, j;
    harkio_Matrix *m, *n;

    int ivalue1;
    float fvalue1;
    COMPLEX_TYPE cvalue1;
    int ivalue2;
    float fvalue2;
    COMPLEX_TYPE cvalue2;
    int ivalue3;
    float fvalue3;
    COMPLEX_TYPE cvalue3;

    setup();

    m = harkio_Matrix_add(goodMatrixInt[0], goodMatrixInt[1]);
    for (i=0; i<goodMatrixInt[0]->rows; i++) {
        for (j=0; j<goodMatrixInt[0]->cols; j++) {
            harkio_Matrix_getValueInt32(goodMatrixInt[0], i, j, &ivalue1);
            harkio_Matrix_getValueInt32(goodMatrixInt[1], i, j, &ivalue2);
            harkio_Matrix_getValueInt32(m, i, j, &ivalue3);
            ck_assert_int_eq(ivalue1 + ivalue2, ivalue3);
        }
    }
    harkio_Matrix_delete(&m);

    m = harkio_Matrix_add(goodMatrixFloat[0], goodMatrixFloat[1]);
    for (i=0; i<goodMatrixFloat[0]->rows; i++) {
        for (j=0; j<goodMatrixInt[0]->cols; j++) {
            harkio_Matrix_getValueFloat32(goodMatrixFloat[0], i, j, &fvalue1);
            harkio_Matrix_getValueFloat32(goodMatrixFloat[1], i, j, &fvalue2);
            harkio_Matrix_getValueFloat32(m, i, j, &fvalue3);
            ck_assert(fabs(fvalue1 + fvalue2 - fvalue3) < 0.00001);
        }
    }
    harkio_Matrix_delete(&m);

    m = harkio_Matrix_add(goodMatrixComplex[0], goodMatrixComplex[1]);
    for (i=0; i<goodMatrixComplex[0]->rows; i++) {
        for (j=0; j<goodMatrixComplex[0]->cols; j++) {
            harkio_Matrix_getValueComplex(goodMatrixComplex[0], i, j, &cvalue1);
            harkio_Matrix_getValueComplex(goodMatrixComplex[1], i, j, &cvalue2);
            harkio_Matrix_getValueComplex(m, i, j, &cvalue3);
            ck_assert(cvalue1 + cvalue2 == cvalue3);
        }
    }
    harkio_Matrix_delete(&m);

    // size mismatch
    ck_assert_ptr_eq(harkio_Matrix_add(goodMatrixInt[1], goodMatrixInt[2]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_add(goodMatrixFloat[1], goodMatrixFloat[2]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_add(goodMatrixComplex[1], goodMatrixComplex[2]), NULL);

    ck_assert_ptr_eq(harkio_Matrix_add(goodMatrixInt[1], NULL), NULL);
    ck_assert_ptr_eq(harkio_Matrix_add(NULL, goodMatrixInt[1]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_add(NULL, NULL), NULL);

    // wrong type
    m = harkio_Matrix_new("wrong", 100, 100);
    n = harkio_Matrix_new("wrong", 100, 100);
    ck_assert_ptr_eq(harkio_Matrix_add(m, n), NULL);
    harkio_Matrix_delete(&m);
    harkio_Matrix_delete(&n);

    teardown();
}
END_TEST

START_TEST(test_sub)
{
    int i, j;
    harkio_Matrix *m, *n;

    int ivalue1;
    float fvalue1;
    COMPLEX_TYPE cvalue1;
    int ivalue2;
    float fvalue2;
    COMPLEX_TYPE cvalue2;
    int ivalue3;
    float fvalue3;
    COMPLEX_TYPE cvalue3;

    setup();

    m = harkio_Matrix_sub(goodMatrixInt[0], goodMatrixInt[1]);
    for (i=0; i<goodMatrixInt[0]->rows; i++) {
        for (j=0; j<goodMatrixInt[0]->cols; j++) {
            harkio_Matrix_getValueInt32(goodMatrixInt[0], i, j, &ivalue1);
            harkio_Matrix_getValueInt32(goodMatrixInt[1], i, j, &ivalue2);
            harkio_Matrix_getValueInt32(m, i, j, &ivalue3);
            ck_assert_int_eq(ivalue1 - ivalue2, ivalue3);
        }
    }
    harkio_Matrix_delete(&m);

    m = harkio_Matrix_sub(goodMatrixFloat[0], goodMatrixFloat[1]);
    for (i=0; i<goodMatrixFloat[0]->rows; i++) {
        for (j=0; j<goodMatrixInt[0]->cols; j++) {
            harkio_Matrix_getValueFloat32(goodMatrixFloat[0], i, j, &fvalue1);
            harkio_Matrix_getValueFloat32(goodMatrixFloat[1], i, j, &fvalue2);
            harkio_Matrix_getValueFloat32(m, i, j, &fvalue3);
            ck_assert(fabs(fvalue1 - fvalue2 - fvalue3) < 0.00001);
        }
    }
    harkio_Matrix_delete(&m);

    m = harkio_Matrix_sub(goodMatrixComplex[0], goodMatrixComplex[1]);
    for (i=0; i<goodMatrixComplex[0]->rows; i++) {
        for (j=0; j<goodMatrixComplex[0]->cols; j++) {
            harkio_Matrix_getValueComplex(goodMatrixComplex[0], i, j, &cvalue1);
            harkio_Matrix_getValueComplex(goodMatrixComplex[1], i, j, &cvalue2);
            harkio_Matrix_getValueComplex(m, i, j, &cvalue3);
            ck_assert(fabs((creal(cvalue1) - creal(cvalue2)) - creal(cvalue3)) < 0.0001);
            ck_assert(fabs((cimag(cvalue1) - cimag(cvalue2)) - cimag(cvalue3)) < 0.0001);
        }
    }
    harkio_Matrix_delete(&m);

    // size mismatch
    ck_assert_ptr_eq(harkio_Matrix_sub(goodMatrixInt[1], goodMatrixInt[2]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_sub(goodMatrixFloat[1], goodMatrixFloat[2]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_sub(goodMatrixComplex[1], goodMatrixComplex[2]), NULL);

    ck_assert_ptr_eq(harkio_Matrix_sub(goodMatrixInt[1], NULL), NULL);
    ck_assert_ptr_eq(harkio_Matrix_sub(NULL, goodMatrixInt[1]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_sub(NULL, NULL), NULL);

    // wrong type
    m = harkio_Matrix_new("wrong", 100, 100);
    n = harkio_Matrix_new("wrong", 100, 100);
    ck_assert_ptr_eq(harkio_Matrix_sub(m, n), NULL);
    harkio_Matrix_delete(&m);
    harkio_Matrix_delete(&n);
    teardown();
}
END_TEST


START_TEST(test_mul)
{
    int i, j;
    harkio_Matrix *m, *n;

    int ivalue1;
    float fvalue1;
    COMPLEX_TYPE cvalue1;
    int ivalue2;
    float fvalue2;
    COMPLEX_TYPE cvalue2;
    int ivalue3;
    float fvalue3;
    COMPLEX_TYPE cvalue3;

    setup();

    m = harkio_Matrix_mul(goodMatrixInt[0], goodMatrixInt[1]);
    for (i=0; i<goodMatrixInt[0]->rows; i++) {
        for (j=0; j<goodMatrixInt[0]->cols; j++) {
            harkio_Matrix_getValueInt32(goodMatrixInt[0], i, j, &ivalue1);
            harkio_Matrix_getValueInt32(goodMatrixInt[1], i, j, &ivalue2);
            harkio_Matrix_getValueInt32(m, i, j, &ivalue3);
            // ck_assert_int_eq(ivalue1 * ivalue2, ivalue3);
        }
    }
    harkio_Matrix_delete(&m);

    m = harkio_Matrix_mul(goodMatrixFloat[0], goodMatrixFloat[1]);
    for (i=0; i<goodMatrixFloat[0]->rows; i++) {
        for (j=0; j<goodMatrixInt[0]->cols; j++) {
            harkio_Matrix_getValueFloat32(goodMatrixFloat[0], i, j, &fvalue1);
            harkio_Matrix_getValueFloat32(goodMatrixFloat[1], i, j, &fvalue2);
            harkio_Matrix_getValueFloat32(m, i, j, &fvalue3);
            // ck_assert(fabs(fvalue1 * fvalue2 - fvalue3) < 0.00001);
        }
    }
    harkio_Matrix_delete(&m);

    m = harkio_Matrix_mul(goodMatrixComplex[0], goodMatrixComplex[1]);

    for (i=0; i<goodMatrixComplex[0]->rows; i++) {
        for (j=0; j<goodMatrixComplex[0]->cols; j++) {
            harkio_Matrix_getValueComplex(goodMatrixComplex[0], i, j, &cvalue1);
            harkio_Matrix_getValueComplex(goodMatrixComplex[1], i, j, &cvalue2);
            harkio_Matrix_getValueComplex(m, i, j, &cvalue3);
            cvalue1 = cvalue1 * cvalue2;
            // ck_assert(fabs(creal(cvalue1) - creal(cvalue3)) < 0.0001);
        }
    }
    harkio_Matrix_delete(&m);

    // eye check
    m = harkio_Matrix_eye("int32", 100);
    n = harkio_Matrix_mul(m, goodMatrixInt[0]);
    ck_assert_int_eq(harkio_Matrix_isEqual(n, goodMatrixInt[0]), EXIT_SUCCESS);
    harkio_Matrix_delete(&m);
    harkio_Matrix_delete(&n);

    m = harkio_Matrix_eye("float32", 100);
    n = harkio_Matrix_mul(m, goodMatrixFloat[0]);
    ck_assert_int_eq(harkio_Matrix_isEqual(n, goodMatrixFloat[0]), EXIT_SUCCESS);
    harkio_Matrix_delete(&m);
    harkio_Matrix_delete(&n);

    m = harkio_Matrix_eye("complex", 100);
    n = harkio_Matrix_mul(m , goodMatrixComplex[0]);
    ck_assert_int_eq(harkio_Matrix_isEqual(n, goodMatrixComplex[0]), EXIT_SUCCESS);
    harkio_Matrix_delete(&m);
    harkio_Matrix_delete(&n);


    // size mismatch
//    ck_assert_ptr_eq( harkio_Matrix_mul(goodMatrixInt[0]    , goodMatrixInt[1])    , NULL);
//    ck_assert_ptr_eq( harkio_Matrix_mul(goodMatrixFloat[0]  , goodMatrixFloat[1])  , NULL);
//    ck_assert_ptr_eq( harkio_Matrix_mul(goodMatrixComplex[0], goodMatrixComplex[1]), NULL);

    // type mismatch
    ck_assert_ptr_eq(harkio_Matrix_mul(goodMatrixInt[0], goodMatrixFloat[1]), NULL);

    // NULL input
    ck_assert_ptr_eq(harkio_Matrix_mul(NULL, goodMatrixInt[0]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_mul(goodMatrixInt[0], NULL), NULL);
    ck_assert_ptr_eq(harkio_Matrix_mul(NULL, NULL), NULL);

    // wrong type
    m = harkio_Matrix_new("wrong", 100, 100);
    n = harkio_Matrix_new("wrong", 100, 100);
    ck_assert_ptr_eq(harkio_Matrix_mul(m, goodMatrixInt[0]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_mul(goodMatrixInt[0], m), NULL);
    ck_assert_ptr_eq(harkio_Matrix_mul(m, n), NULL);
    harkio_Matrix_delete(&m);
    harkio_Matrix_delete(&n);

    teardown();
}
END_TEST

START_TEST(test_emul)
{
    int i, j;
    harkio_Matrix *m , *m1;

    int ivalue1;
    float fvalue1;
    COMPLEX_TYPE cvalue1;
    int ivalue2;
    float fvalue2;
    COMPLEX_TYPE cvalue2;
    int ivalue3;
    float fvalue3;
    COMPLEX_TYPE cvalue3;

    setup();

    m = harkio_Matrix_emul(goodMatrixInt[0], goodMatrixInt[1]);

    for (i=0; i<goodMatrixInt[0]->rows; i++) {
        for (j=0; j<goodMatrixInt[0]->cols; j++) {
            harkio_Matrix_getValueInt32(goodMatrixInt[0], i, j, &ivalue1);
            harkio_Matrix_getValueInt32(goodMatrixInt[1], i, j, &ivalue2);
            harkio_Matrix_getValueInt32(m, i, j, &ivalue3);
            ck_assert_int_eq(ivalue1 * ivalue2, ivalue3);
        }
    }
    harkio_Matrix_delete(&m);

    m = harkio_Matrix_emul(goodMatrixFloat[0], goodMatrixFloat[1]);

    for (i=0; i<goodMatrixFloat[0]->rows; i++) {
        for (j=0; j<goodMatrixInt[0]->cols; j++) {
            harkio_Matrix_getValueFloat32(goodMatrixFloat[0], i, j, &fvalue1);
            harkio_Matrix_getValueFloat32(goodMatrixFloat[1], i, j, &fvalue2);
            harkio_Matrix_getValueFloat32(m, i, j, &fvalue3);
            ck_assert(fabs(fvalue1 * fvalue2 - fvalue3) < 0.00001);
        }
    }
    harkio_Matrix_delete(&m);

    m = harkio_Matrix_emul(goodMatrixComplex[0], goodMatrixComplex[1]);
    for (i=0; i<goodMatrixComplex[0]->rows; i++) {
        for (j=0; j<goodMatrixComplex[0]->cols; j++) {
            harkio_Matrix_getValueComplex(goodMatrixComplex[0], i, j, &cvalue1);
            harkio_Matrix_getValueComplex(goodMatrixComplex[1], i, j, &cvalue2);
            harkio_Matrix_getValueComplex(m, i, j, &cvalue3);
            cvalue1 = cvalue1 * cvalue2;
            ck_assert(fabs(creal(cvalue1) - creal(cvalue3)) < 0.0001);
            ck_assert(fabs(cimag(cvalue1) - cimag(cvalue3)) < 0.0001);
        }
    }
    harkio_Matrix_delete(&m);

    // size mismatch
//    ck_assert_ptr_eq(harkio_Matrix_emul( goodMatrixInt[0], goodMatrixInt[1]), NULL);
//    ck_assert_ptr_eq(harkio_Matrix_emul(goodMatrixFloat[0], goodMatrixFloat[1]), NULL);
//    ck_assert_ptr_eq(harkio_Matrix_emul(goodMatrixComplex[0], goodMatrixComplex[1]), NULL);

    // type mismatch
    ck_assert_ptr_eq(harkio_Matrix_emul(goodMatrixInt[0], goodMatrixFloat[1]), NULL);

    // NULL input
    ck_assert_ptr_eq(harkio_Matrix_emul(NULL, goodMatrixInt[0]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_emul(goodMatrixInt[0], NULL), NULL);
    ck_assert_ptr_eq(harkio_Matrix_emul(NULL, NULL), NULL);

    // wrong type
    m = harkio_Matrix_new("wrong", 100, 100);
    m1 = harkio_Matrix_new("wrong", 100, 100);
    ck_assert_ptr_eq(harkio_Matrix_emul(m              , goodMatrixInt[0]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_emul(goodMatrixInt[0], m), NULL);
    ck_assert_ptr_eq(harkio_Matrix_emul(m , m1), NULL);
    harkio_Matrix_delete(&m);
    harkio_Matrix_delete(&m1);

    teardown();
}
END_TEST

START_TEST(test_ediv)
{
    int i, j;
    harkio_Matrix *m , *m1;

    int ivalue1;
    float fvalue1;
    COMPLEX_TYPE cvalue1;
    int ivalue2;
    float fvalue2;
    COMPLEX_TYPE cvalue2;
    int ivalue3;
    float fvalue3;
    COMPLEX_TYPE cvalue3;

    setup();

    m = harkio_Matrix_ediv(goodMatrixInt[0], goodMatrixInt[1]);

    for (i=0; i<goodMatrixInt[0]->rows; i++) {
        for (j=0; j<goodMatrixInt[0]->cols; j++) {
            harkio_Matrix_getValueInt32(goodMatrixInt[0], i, j, &ivalue1);
            harkio_Matrix_getValueInt32(goodMatrixInt[1], i, j, &ivalue2);
            harkio_Matrix_getValueInt32(m, i, j, &ivalue3);
            ck_assert_int_eq(ivalue1 / ivalue2, ivalue3);
        }
    }
    harkio_Matrix_delete(&m);

    m = harkio_Matrix_ediv(goodMatrixFloat[0], goodMatrixFloat[1]);

    for (i=0; i<goodMatrixFloat[0]->rows; i++) {
        for (j=0; j<goodMatrixInt[0]->cols; j++) {
            harkio_Matrix_getValueFloat32(goodMatrixFloat[0], i, j, &fvalue1);
            harkio_Matrix_getValueFloat32(goodMatrixFloat[1], i, j, &fvalue2);
            harkio_Matrix_getValueFloat32(m, i, j, &fvalue3);
            ck_assert(fabs(fvalue1 / fvalue2 - fvalue3) < 0.00001);
        }
    }
    harkio_Matrix_delete(&m);

    m = harkio_Matrix_ediv(goodMatrixComplex[0], goodMatrixComplex[1]);
    for (i=0; i<goodMatrixComplex[0]->rows; i++) {
        for (j=0; j<goodMatrixComplex[0]->cols; j++) {
            harkio_Matrix_getValueComplex(goodMatrixComplex[0], i, j, &cvalue1);
            harkio_Matrix_getValueComplex(goodMatrixComplex[1], i, j, &cvalue2);
            harkio_Matrix_getValueComplex(m, i, j, &cvalue3);
            cvalue1 = cvalue1 / cvalue2;
            ck_assert(fabs(crealf(cvalue1) - crealf(cvalue3)) < 0.0001);
            // fprintf(stderr, "%.3f + i%.3f  vs  %.3f + i%.3f",
            // crealf(cvalue1), cimagf(cvalue1), crealf(cvalue3), cimagf(cvalue3));
            ck_assert(fabs(cimagf(cvalue1) - cimagf(cvalue3)) < 0.0001);
        }
    }
    harkio_Matrix_delete(&m);

    // size mismatch
//    ck_assert_ptr_eq(harkio_Matrix_ediv( goodMatrixInt[0], goodMatrixInt[1]), NULL);
//    ck_assert_ptr_eq(harkio_Matrix_ediv(goodMatrixFloat[0], goodMatrixFloat[1]), NULL);
//    ck_assert_ptr_eq(harkio_Matrix_ediv(goodMatrixComplex[0], goodMatrixComplex[1]), NULL);

    // type mismatch
    ck_assert_ptr_eq(harkio_Matrix_ediv(goodMatrixInt[0], goodMatrixFloat[1]), NULL);

    // NULL input
    ck_assert_ptr_eq(harkio_Matrix_ediv(NULL, goodMatrixInt[0]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_ediv(goodMatrixInt[0], NULL), NULL);
    ck_assert_ptr_eq(harkio_Matrix_ediv(NULL, NULL), NULL);

    // wrong type
    m = harkio_Matrix_new("wrong", 100, 100);
    m1 = harkio_Matrix_new("wrong", 100, 100);
    ck_assert_ptr_eq(harkio_Matrix_ediv(m              , goodMatrixInt[0]), NULL);
    ck_assert_ptr_eq(harkio_Matrix_ediv(goodMatrixInt[0], m), NULL);
    ck_assert_ptr_eq(harkio_Matrix_ediv(m , m1), NULL);
    harkio_Matrix_delete(&m);
    harkio_Matrix_delete(&m1);

    teardown();
}
END_TEST


START_TEST(test_diag)
{
    int i;
    int itmp1, itmp2;
    float ftmp1, ftmp2;
    COMPLEX_TYPE ctmp1;
    COMPLEX_TYPE ctmp2;
    harkio_Matrix *idiag, *fdiag, *cdiag;
    harkio_Matrix *ivec, *fvec, *cvec;

    setup();

    // Get diagonal component function
    idiag = harkio_Matrix_getDiag(goodMatrixInt[0]);
    fdiag = harkio_Matrix_getDiag(goodMatrixFloat[0]);
    cdiag = harkio_Matrix_getDiag(goodMatrixComplex[0]);
    for (i=0; i<idiag->cols; i++) {
        // fprintf(stderr, "%d, %d\n", i, idiag->rows);
        harkio_Matrix_getValueInt32(idiag,                 0, i, &itmp1);
        harkio_Matrix_getValueInt32(goodMatrixInt[0],      i, i, &itmp2);
        ck_assert_int_eq(itmp1, itmp2);

        harkio_Matrix_getValueFloat32(fdiag,               0, i, &ftmp1);
        harkio_Matrix_getValueFloat32(goodMatrixFloat[0],  i, i, &ftmp2);
        ck_assert(fabs(ftmp1 - ftmp2) < 0.00001);

        harkio_Matrix_getValueComplex(cdiag,                0, i, &ctmp1);
        harkio_Matrix_getValueComplex(goodMatrixComplex[0], i, i, &ctmp2);
        ck_assert(fabs(crealf(ctmp1) - crealf(ctmp2)) < 0.00001);
        ck_assert(fabs(cimagf(ctmp1) - cimagf(ctmp2)) < 0.00001);
    }
    fprintf(stderr, "deleting \n");
    harkio_Matrix_delete(&idiag);
    harkio_Matrix_delete(&fdiag);
    harkio_Matrix_delete(&cdiag);
    fprintf(stderr, "done\n");


    // Make a diagonal matrix from a vector component function
    ivec = harkio_Matrix_new("int32",   1, 100);
    fvec = harkio_Matrix_new("float32", 1, 100);
    cvec = harkio_Matrix_new("complex", 1, 100);

    idiag = harkio_Matrix_makeDiag(ivec);
    ck_assert_ptr_ne(idiag, NULL);
    fdiag = harkio_Matrix_makeDiag(fvec);
    ck_assert_ptr_ne(fdiag, NULL);
    cdiag = harkio_Matrix_makeDiag(cvec);
    ck_assert_ptr_ne(cdiag, NULL);

    for (i=0; i<idiag->rows; i++) {
        harkio_Matrix_getValueInt32(idiag,   i, i, &itmp1);
        harkio_Matrix_getValueInt32(ivec,    0, i, &itmp2);
        ck_assert_int_eq(itmp1, itmp2);

        harkio_Matrix_getValueFloat32(fdiag, i, i, &ftmp1);
        harkio_Matrix_getValueFloat32(fvec,  0, i, &ftmp2);
        ck_assert(fabs(ftmp1 - ftmp2) < 0.00001);

        harkio_Matrix_getValueComplex(cdiag,  i, i, &ctmp1);
        harkio_Matrix_getValueComplex(cvec,   0, i, &ctmp2);
        ck_assert(fabs(crealf(ctmp1) - crealf(ctmp2)) < 0.00001);
        ck_assert(fabs(cimagf(ctmp1) - cimagf(ctmp2)) < 0.00001);
    }
    harkio_Matrix_delete(&idiag);
    harkio_Matrix_delete(&fdiag);
    harkio_Matrix_delete(&cdiag);
    harkio_Matrix_delete(&ivec);
    harkio_Matrix_delete(&fvec);
    harkio_Matrix_delete(&cvec);

    teardown();
}
END_TEST


START_TEST(test_sum)
{
    int length = 2;
    int i;
    harkio_Matrix **input = (harkio_Matrix**) malloc(sizeof(harkio_Matrix*) * length);
    harkio_Matrix **nullp = NULL;
    harkio_Matrix *answer = NULL;
    harkio_Matrix *result = NULL;

    // null input
    ck_assert(harkio_Matrix_sum(nullp, 0) == NULL);

    // successfull summation int32
    input[0] = harkio_Matrix_eye("int32", 10);
    input[1] = harkio_Matrix_eye("int32", 10);
    result = harkio_Matrix_sum(input, length);
    answer = harkio_Matrix_zeros("int32", 10, 10);

    for (i=0; i<10; i++)
        harkio_Matrix_setValueInt32(answer, i, i, 2);
    ck_assert_int_eq(harkio_Matrix_isEqual(result, answer), EXIT_SUCCESS);

    harkio_Matrix_delete(input + 0);
    harkio_Matrix_delete(input + 1);
    harkio_Matrix_delete(&result);
    harkio_Matrix_delete(&answer);

    // successfull summation float32
    input[0] = harkio_Matrix_eye("float32", 10);
    input[1] = harkio_Matrix_eye("float32", 10);
    result = harkio_Matrix_sum(input, length);
    answer = harkio_Matrix_eye("float32", 10);

    for (i=0; i<10; i++)
        harkio_Matrix_setValueFloat32(answer, i, i, 2);

    ck_assert_int_eq(harkio_Matrix_isEqual(result, answer), EXIT_SUCCESS);
    harkio_Matrix_isEqual(result, answer);
    harkio_Matrix_delete(input + 0);
    harkio_Matrix_delete(input + 1);
    harkio_Matrix_delete(&result);
    harkio_Matrix_delete(&answer);

    // successfull summation complex
    input[0] = harkio_Matrix_eye("complex", 10);
    input[1] = harkio_Matrix_eye("complex", 10);
    result = harkio_Matrix_sum(input, length);
    answer = harkio_Matrix_eye("complex", 10);

    for (i=0; i<10; i++)
        harkio_Matrix_setValueComplex(answer, i, i, 2);

    ck_assert_int_eq(harkio_Matrix_isEqual(result, answer), EXIT_SUCCESS);
    harkio_Matrix_isEqual(result, answer);
    harkio_Matrix_delete(input + 0);
    harkio_Matrix_delete(input + 1);
    harkio_Matrix_delete(&result);
    harkio_Matrix_delete(&answer);


    // partially null
    input[0] = harkio_Matrix_eye("int32", 10);
    input[1] = NULL;
    ck_assert(harkio_Matrix_sum(input, length) == NULL);
    harkio_Matrix_delete(input + 0);
    harkio_Matrix_delete(input + 1);

    // type mismatch
    input[0] = harkio_Matrix_eye("int32", 10);
    input[1] = harkio_Matrix_eye("float32", 10);
    ck_assert(harkio_Matrix_sum(input, length) == NULL);
    harkio_Matrix_delete(input + 0);
    harkio_Matrix_delete(input + 1);

    // size mismatch
    input[0] = harkio_Matrix_eye("int32", 10);
    input[1] = harkio_Matrix_eye("int32", 11);
    ck_assert(harkio_Matrix_sum(input, length) == NULL);
    harkio_Matrix_delete(input + 0);
    harkio_Matrix_delete(input + 1);

    // wrong type
    input[0] = harkio_Matrix_eye("wrongtype", 10);
    input[1] = harkio_Matrix_eye("wrongtype", 10);
    ck_assert(harkio_Matrix_mul(input[0], input[1]) == NULL);
    harkio_Matrix_delete(input + 0);
    harkio_Matrix_delete(input + 1);

    free(input);
    input = NULL;
}
END_TEST

START_TEST(test_readwrite)
{
    int ret;
    harkio_Matrix *a = harkio_Matrix_eye("int32", 10);
    harkio_Matrix_print(a);
    harkio_Matrix *b;

    ret = harkio_Matrix_write(a, NULL);
    ck_assert_int_eq(ret, EXIT_FAILURE);

    ret = harkio_Matrix_write(a, "test.mat");
    ck_assert_int_eq(ret, EXIT_SUCCESS);

    b = harkio_Matrix_fromFile(NULL);
    ck_assert(b == NULL);
    harkio_Matrix_delete(&b);


    b = harkio_Matrix_fromFile("test.mat");
    ck_assert(harkio_Matrix_isEqual(a, b) == EXIT_SUCCESS);

    harkio_Matrix_delete(&a);
    harkio_Matrix_delete(&b);

    // float32
    a = harkio_Matrix_zeros("float32", 15, 15);
    harkio_Matrix_print(a);
    ret = harkio_Matrix_write(a, "test_float.mat");
    ck_assert_int_eq(ret, EXIT_SUCCESS);

    b = harkio_Matrix_fromFile("test_float.mat");
    ck_assert_int_eq(harkio_Matrix_isEqual(a, b), EXIT_SUCCESS);

    size_t s;
    char* c = harkio_Matrix_writeBuffer(a, &s);
    ck_assert_ptr_ne(c, NULL);
    int errorp;
    struct zip* pzip = zip_open("test_float.zip", ZIP_CREATE, &errorp);
    struct zip_source* src = zip_source_buffer(pzip, c, s, 0);
    zip_add(pzip, "test_float.mat", src);
    zip_close(pzip);
    pzip = zip_open("test_float.zip", ZIP_CHECKCONS, &errorp);
    harkio_Matrix* d = harkio_Matrix_fromZip(pzip, "test_float.mat");
    zip_close(pzip);

    ck_assert_int_eq(harkio_Matrix_isEqual(b, d), EXIT_SUCCESS);
//    FILE* fp = fopen("test_float.mat", "rb");
//    fseek(fp, 0, SEEK_END);
//    size_t fsize = ftell(fp);
//    ck_assert_int_eq(s, fsize);
//    fseek(fp, 0, SEEK_SET);
//    char* c2 = malloc(fsize);
//    fread(c2, fsize, 1, fp);
//    ck_assert(memcmp(c+64, c2+64, s-64) == 0);
    free(c);
//    free(c2);

    harkio_Matrix_delete(&a);
    harkio_Matrix_delete(&b);
    harkio_Matrix_delete(&d);

    // complex
    a = harkio_Matrix_ones("complex", 20, 20);
    harkio_Matrix_print(a);
    ret = harkio_Matrix_write(a, "test_complex.mat");
    ck_assert_int_eq(ret, EXIT_SUCCESS);

    b = harkio_Matrix_fromFile("test_complex.mat");
    ck_assert_int_eq(harkio_Matrix_isEqual(a, b), EXIT_SUCCESS);

    c = harkio_Matrix_writeBuffer(a, &s);
    ck_assert_ptr_ne(c, NULL);

    pzip = zip_open("test_complex.zip", ZIP_CREATE, &errorp);
    src = zip_source_buffer(pzip, c, s, 0);
    zip_add(pzip, "test_complex.mat", src);
    zip_close(pzip);
    pzip = zip_open("test_complex.zip", ZIP_CHECKCONS, &errorp);
    d = harkio_Matrix_fromZip(pzip, "test_complex.mat");
    zip_close(pzip);

    ck_assert_int_eq(harkio_Matrix_isEqual(b, d), EXIT_SUCCESS);
//    fp = fopen("test_complex.mat", "rb");
//    fseek(fp, 0, SEEK_END);
//    fsize = ftell(fp);
//    ck_assert_int_eq(s, fsize);
//    fseek(fp, 0, SEEK_SET);
//    c2 = malloc(fsize);
//    fread(c2, fsize, 1, fp);
//    ck_assert(memcmp(c+64, c2+64, s-64) == 0);
    free(c);
//    free(c2);

    harkio_Matrix_delete(&a);
    harkio_Matrix_delete(&b);
    harkio_Matrix_delete(&d);
}
END_TEST

START_TEST(test_getValues)
{
    harkio_Matrix *a, *b;
    int i, j;

    // int32
    a = harkio_Matrix_new("int32", 10, 10);
    for (i=0; i<a->cols; i++) {
        for (j=0; j<a->rows; j++) {
            harkio_Matrix_setValueInt32(a, i, j, i+j);
        }
    }
    b = harkio_Matrix_getValues(a, 0, 0, 5, 5);
    for (i=0; i<a->cols; i++) {
        for (j=0; j<a->rows; j++) {
            int val;
            harkio_Matrix_getValueInt32(a, i, j, &val);
            ck_assert_int_eq(i+j, val);
        }
    }
    harkio_Matrix_delete(&a);
    harkio_Matrix_delete(&b);

    // float32
    a = harkio_Matrix_new("float32", 10, 10);
    for (i=0; i<a->cols; i++) {
        for (j=0; j<a->rows; j++) {
            harkio_Matrix_setValueFloat32(a, i, j, i+j);
        }
    }
    b = harkio_Matrix_getValues(a, 0, 0, 5, 5);
    for (i=0; i<a->cols; i++) {
        for (j=0; j<a->rows; j++) {
            float val;
            harkio_Matrix_getValueFloat32(a, i, j, &val);
            ck_assert(abs((i+j) - val) < 0.001);
        }
    }
    harkio_Matrix_delete(&a);
    harkio_Matrix_delete(&b);

    // complex
    a = harkio_Matrix_new("complex", 10, 10);
    for (i=0; i<a->cols; i++) {
        for (j=0; j<a->rows; j++) {
            harkio_Matrix_setValueComplex(a, i, j, i+j);
        }
    }
    b = harkio_Matrix_getValues(a, 0, 0, 5, 5);
    for (i=0; i<a->cols; i++) {
        for (j=0; j<a->rows; j++) {
            COMPLEX_TYPE val;
            harkio_Matrix_getValueComplex(a, i, j, &val);
            ck_assert(cabs((i+j) - val) < 0.001);
        }
    }
    harkio_Matrix_delete(&a);
    harkio_Matrix_delete(&b);


}
END_TEST


START_TEST(test_setValues)
{
    harkio_Matrix *a, *b;
    int i, j;

    // int32
    a = harkio_Matrix_zeros("int32", 10, 10);
    b = harkio_Matrix_zeros("int32", 3, 3);
    for (i=0; i<b->cols; i++) {
        for (j=0; j<b->rows; j++) {
            harkio_Matrix_setValueInt32(b, i, j, i+j);
        }
    }
    harkio_Matrix_print(a);
    harkio_Matrix_print(b);
    ck_assert_int_eq(EXIT_SUCCESS, harkio_Matrix_setValues(a, b, 0, 0));
    harkio_Matrix_print(a);
    harkio_Matrix_print(b);
    for (i=0; i<3; i++) {
        for (j=0; j<3; j++) {
            int val;
            harkio_Matrix_getValueInt32(a, i, j, &val);
            ck_assert_int_eq(i+j, val);
        }
    }
    harkio_Matrix_delete(&a);
    harkio_Matrix_delete(&b);

    // float32
    a = harkio_Matrix_zeros("float32", 10, 10);
    b = harkio_Matrix_zeros("float32", 3, 3);
    for (i=0; i<b->cols; i++) {
        for (j=0; j<b->rows; j++) {
            harkio_Matrix_setValueFloat32(b, i, j, i+j);
        }
    }
    ck_assert_int_eq(EXIT_SUCCESS, harkio_Matrix_setValues(a, b, 0, 0));
    for (i=0; i<3; i++) {
        for (j=0; j<3; j++) {
            float val;
            harkio_Matrix_getValueFloat32(a, i, j, &val);
            ck_assert(fabs(i+j - val) < HARK_EPS);
        }
    }
    harkio_Matrix_delete(&a);
    harkio_Matrix_delete(&b);

    // complex
    a = harkio_Matrix_zeros("complex", 10, 10);
    b = harkio_Matrix_zeros("complex", 3, 3);
    for (i=0; i<b->cols; i++) {
        for (j=0; j<b->rows; j++) {
            harkio_Matrix_setValueComplex(b, i, j, i+j);
        }
    }
    ck_assert_int_eq(EXIT_SUCCESS, harkio_Matrix_setValues(a, b, 0, 0));
    for (i=0; i<3; i++) {
        for (j=0; j<3; j++) {
            float _Complex val;
            harkio_Matrix_getValueComplex(a, i, j, &val);
            ck_assert(cabs(i+j - val) < HARK_EPS);
        }
    }
    harkio_Matrix_delete(&a);
    harkio_Matrix_delete(&b);
}
END_TEST

START_TEST(test_eabs)
{
    harkio_Matrix *m;
    int i, j, k;

    setup();


    for (k=0; k<numoks; k++) {
        m = harkio_Matrix_eabs(goodMatrixInt[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                int a, b;
                harkio_Matrix_getValueInt32(goodMatrixInt[k], i, j, &a);
                harkio_Matrix_getValueInt32(m               , i, j, &b);
                ck_assert_int_eq(abs(a), b);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_eabs(goodMatrixFloat[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                float a, b;
                harkio_Matrix_getValueFloat32(goodMatrixFloat[k], i, j, &a);
                harkio_Matrix_getValueFloat32(m               , i, j, &b);
                ck_assert(fabsf(fabs(a) - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_eabs(goodMatrixComplex[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                COMPLEX_TYPE a, b;
                harkio_Matrix_getValueComplex(goodMatrixComplex[k], i, j, &a);
                harkio_Matrix_getValueComplex(m               , i, j, &b);
                // fprintf(stderr, "%f+i%f, %f+i%f, %f+i%f\n",
                //     creal(a), cimag(a), creal(a*a), cimag(a*a), creal(b), cimag(b));
                ck_assert(cabsf(cabsf(a) - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST

START_TEST(test_esquare)
{
    harkio_Matrix *m;
    int i, j, k;

    setup();


    for (k=0; k<numoks; k++) {
        m = harkio_Matrix_esquare(goodMatrixInt[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                int a, b;
                harkio_Matrix_getValueInt32(goodMatrixInt[k], i, j, &a);
                harkio_Matrix_getValueInt32(m               , i, j, &b);
                ck_assert_int_eq(a * a, b);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_esquare(goodMatrixFloat[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                float a, b;
                harkio_Matrix_getValueFloat32(goodMatrixFloat[k], i, j, &a);
                harkio_Matrix_getValueFloat32(m               , i, j, &b);
                ck_assert(fabsf(a * a - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_esquare(goodMatrixComplex[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                COMPLEX_TYPE a, b;
                harkio_Matrix_getValueComplex(goodMatrixComplex[k], i, j, &a);
                harkio_Matrix_getValueComplex(m               , i, j, &b);
                // fprintf(stderr, "%f+i%f, %f+i%f, %f+i%f\n",
                //     creal(a), cimag(a), creal(a*a), cimag(a*a), creal(b), cimag(b));
                ck_assert(cabsf(a * a - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST

START_TEST(test_econj)
{
    harkio_Matrix *m;
    int i, j, k;

    setup();


    for (k=0; k<numoks; k++) {
        m = harkio_Matrix_econj(goodMatrixInt[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                int a, b;
                harkio_Matrix_getValueInt32(goodMatrixInt[k], i, j, &a);
                harkio_Matrix_getValueInt32(m               , i, j, &b);
                ck_assert_int_eq(a, b);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_econj(goodMatrixFloat[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                float a, b;
                harkio_Matrix_getValueFloat32(goodMatrixFloat[k], i, j, &a);
                harkio_Matrix_getValueFloat32(m               , i, j, &b);
                ck_assert(fabsf(a - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_econj(goodMatrixComplex[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                COMPLEX_TYPE a, b;
                harkio_Matrix_getValueComplex(goodMatrixComplex[k], i, j, &a);
                harkio_Matrix_getValueComplex(m               , i, j, &b);
                // fprintf(stderr, "%f+i%f, %f+i%f, %f+i%f\n",
                //     creal(a), cimag(a), creal(conjf(a)), cimag(conjf(a)), creal(b), cimag(b));
                ck_assert(cabsf(conjf(a) - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST

START_TEST(test_etanh)
{
    harkio_Matrix *m;
    int i, j, k;

    setup();


    for (k=0; k<numoks; k++) {
        m = harkio_Matrix_etanh(goodMatrixInt[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                int a, b;
                harkio_Matrix_getValueInt32(goodMatrixInt[k], i, j, &a);
                harkio_Matrix_getValueInt32(m               , i, j, &b);
                ck_assert_int_eq((int)tanhf((float)a), b);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_etanh(goodMatrixFloat[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                float a, b;
                harkio_Matrix_getValueFloat32(goodMatrixFloat[k], i, j, &a);
                harkio_Matrix_getValueFloat32(m               , i, j, &b);
                ck_assert(fabsf(tanhf(a) - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_etanh(goodMatrixComplex[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                COMPLEX_TYPE a, b;
                harkio_Matrix_getValueComplex(goodMatrixComplex[k], i, j, &a);
                harkio_Matrix_getValueComplex(m               , i, j, &b);
                // fprintf(stderr, "%f+i%f, %f+i%f, %f+i%f\n",
                //     creal(a), cimag(a), creal(ctanhf(a)), cimag(ctanhf(a)), creal(b), cimag(b), abs(ctanhf(a) - b));
                ck_assert(cabsf(ctanhf(a) - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST

START_TEST(test_ecosh)
{
    harkio_Matrix *m;
    int i, j, k;

    setup4cosh();

    for (k=0; k<numoks; k++) {
        m = harkio_Matrix_ecosh(goodMatrixInt[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                int a, b;
                harkio_Matrix_getValueInt32(goodMatrixInt[k], i, j, &a);
                harkio_Matrix_getValueInt32(m               , i, j, &b);
                ck_assert_int_eq((int)coshf((float)a), b);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_ecosh(goodMatrixFloat[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                float a, b;
                harkio_Matrix_getValueFloat32(goodMatrixFloat[k], i, j, &a);
                harkio_Matrix_getValueFloat32(m               , i, j, &b);
                ck_assert(fabsf(coshf(a) - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_ecosh(goodMatrixComplex[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                COMPLEX_TYPE a, b;
                harkio_Matrix_getValueComplex(goodMatrixComplex[k], i, j, &a);
                harkio_Matrix_getValueComplex(m               , i, j, &b);
                // fprintf(stderr, "%f+i%f, %f+i%f, %f+i%f\n",
                //     creal(a), cimag(a), creal(ccoshf(a)), cimag(ccoshf(a)), creal(b), cimag(b));
                ck_assert(cabsf(ccoshf(a) - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST

START_TEST(test_elog)
{
    harkio_Matrix *m;
    int i, j, k;

    setup();


    for (k=0; k<numoks; k++) {
        m = harkio_Matrix_elog(goodMatrixInt[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                int a, b;
                harkio_Matrix_getValueInt32(goodMatrixInt[k], i, j, &a);
                harkio_Matrix_getValueInt32(m               , i, j, &b);
                ck_assert_int_eq((int)logf((float)a), b);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_elog(goodMatrixFloat[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                float a, b;
                harkio_Matrix_getValueFloat32(goodMatrixFloat[k], i, j, &a);
                harkio_Matrix_getValueFloat32(m               , i, j, &b);
                ck_assert(fabsf(logf(a) - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_elog(goodMatrixComplex[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                COMPLEX_TYPE a, b;
                harkio_Matrix_getValueComplex(goodMatrixComplex[k], i, j, &a);
                harkio_Matrix_getValueComplex(m               , i, j, &b);
                // fprintf(stderr, "%f+i%f, %f+i%f, %f+i%f\n",
                //  creal(a), cimag(a), creal(clogf(a)), cimag(clogf(a)), creal(b), cimag(b));
                ck_assert(cabsf(clogf(a) - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST

START_TEST(test_elog10)
{
    harkio_Matrix *m;
    int i, j, k;

    setup();


    for (k=0; k<numoks; k++) {
        m = harkio_Matrix_elog10(goodMatrixInt[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                int a, b;
                harkio_Matrix_getValueInt32(goodMatrixInt[k], i, j, &a);
                harkio_Matrix_getValueInt32(m               , i, j, &b);
                ck_assert_int_eq((int)(log10f((double)a)), b);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_elog10(goodMatrixFloat[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                float a, b;
                harkio_Matrix_getValueFloat32(goodMatrixFloat[k], i, j, &a);
                harkio_Matrix_getValueFloat32(m               , i, j, &b);
                ck_assert(fabsf(log10f(a) - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_elog10(goodMatrixComplex[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                COMPLEX_TYPE a, b;
                harkio_Matrix_getValueComplex(goodMatrixComplex[k], i, j, &a);
                harkio_Matrix_getValueComplex(m               , i, j, &b);
                // fprintf(stderr, "%f+i%f, %f+i%f, %f+i%f\n",
                //     creal(a), cimag(a), creal(clogf(a)/logf(10.0)), cimag(clogf(a)/logf(10.0)), creal(b), cimag(b));
                ck_assert(cabsf(clogf(a)/logf(10.0) - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST

START_TEST(test_ereal)
{
    harkio_Matrix *m;
    int i, j, k;

    setup();


    for (k=0; k<numoks; k++) {
        m = harkio_Matrix_ereal(goodMatrixInt[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                int a, b;
                harkio_Matrix_getValueInt32(goodMatrixInt[k], i, j, &a);
                harkio_Matrix_getValueInt32(m               , i, j, &b);
                ck_assert_int_eq(a, b);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_ereal(goodMatrixFloat[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                float a, b;
                harkio_Matrix_getValueFloat32(goodMatrixFloat[k], i, j, &a);
                harkio_Matrix_getValueFloat32(m               , i, j, &b);
                ck_assert(fabsf(a - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_ereal(goodMatrixComplex[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                COMPLEX_TYPE a, b;
                harkio_Matrix_getValueComplex(goodMatrixComplex[k], i, j, &a);
                harkio_Matrix_getValueComplex(m               , i, j, &b);
                // fprintf(stderr, "%f+i%f, %f+i%f, %f+i%f\n",
                //     creal(a), cimag(a), creal(crealf(a)), cimag(crealf(a)), creal(b), cimag(b));
                ck_assert(cabsf(crealf(a) - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST

START_TEST(test_eimag)
{
    harkio_Matrix *m;
    int i, j, k;

    setup();


    for (k=0; k<numoks; k++) {
        m = harkio_Matrix_eimag(goodMatrixInt[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                int a, b;
                harkio_Matrix_getValueInt32(goodMatrixInt[k], i, j, &a);
                harkio_Matrix_getValueInt32(m               , i, j, &b);
                ck_assert_int_eq(0, b);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_eimag(goodMatrixFloat[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                float a, b;
                harkio_Matrix_getValueFloat32(goodMatrixFloat[k], i, j, &a);
                harkio_Matrix_getValueFloat32(m               , i, j, &b);
                ck_assert(fabsf(0.0 - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_eimag(goodMatrixComplex[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                COMPLEX_TYPE a, b;
                harkio_Matrix_getValueComplex(goodMatrixComplex[k], i, j, &a);
                harkio_Matrix_getValueComplex(m               , i, j, &b);
                // fprintf(stderr, "%f+i%f, %f+i%f, %f+i%f\n",
                //     creal(a), cimag(a), creal(cimagf(a)), cimag(cimagf(a)), creal(b), cimag(b));
                ck_assert(cabsf(cimagf(a) - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST

START_TEST(test_emulC)
{
    harkio_Matrix *m;
    int i, j, k;

    setup();

    for (k=0; k<numoks; k++) {
        // Int32
        m = harkio_Matrix_emulCInt32(goodMatrixInt[k], iC[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                int a, b;
                harkio_Matrix_getValueInt32(goodMatrixInt[k], i, j, &a);
                harkio_Matrix_getValueInt32(m               , i, j, &b);
                ck_assert_int_eq(a*iC[k], b);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_emulCFloat32(goodMatrixFloat[k], fC[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                float a, b;
                harkio_Matrix_getValueFloat32(goodMatrixFloat[k], i, j, &a);
                harkio_Matrix_getValueFloat32(m               , i, j, &b);
                ck_assert(fabsf(a*fC[k] - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_emulCComplex(goodMatrixComplex[k], cC[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                COMPLEX_TYPE a, b;
                harkio_Matrix_getValueComplex(goodMatrixComplex[k], i, j, &a);
                harkio_Matrix_getValueComplex(m               , i, j, &b);
                // fprintf(stderr, "%f+i%f, %f+i%f, %f+i%f\n",
                //     creal(a), cimag(a), creal(a*cC[k]), cimag(a*cC[k]), creal(b), cimag(b));
                ck_assert(cabsf(a*cC[k] - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST


START_TEST(test_edivC)
{
    harkio_Matrix *m;
    int i, j, k;

    setup();

    for (k=0; k<numoks; k++) {
        // Int32
        m = harkio_Matrix_edivCInt32(goodMatrixInt[k], iC[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                int a, b;
                harkio_Matrix_getValueInt32(goodMatrixInt[k], i, j, &a);
                harkio_Matrix_getValueInt32(m               , i, j, &b);
                ck_assert_int_eq(a/iC[k], b);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_edivCFloat32(goodMatrixFloat[k], fC[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                float a, b;
                harkio_Matrix_getValueFloat32(goodMatrixFloat[k], i, j, &a);
                harkio_Matrix_getValueFloat32(m               , i, j, &b);
                ck_assert(fabsf(a/fC[k] - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_edivCComplex(goodMatrixComplex[k], cC[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                COMPLEX_TYPE a, b;
                harkio_Matrix_getValueComplex(goodMatrixComplex[k], i, j, &a);
                harkio_Matrix_getValueComplex(m               , i, j, &b);
                // fprintf(stderr, "%f+i%f, %f+i%f, %f+i%f\n",
                //     creal(a), cimag(a), creal(a/cC[k]), cimag(a/cC[k]), creal(b), cimag(b));
                ck_assert(cabsf(a/cC[k] - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST

START_TEST(test_epowerC)
{
    harkio_Matrix *m;
    int i, j, k;

    setup();

    for (k=0; k<numoks; k++) {
        // Int32
        m = harkio_Matrix_epowerCInt32(goodMatrixInt[k], iCpow[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                int a, b;
                harkio_Matrix_getValueInt32(goodMatrixInt[k], i, j, &a);
                harkio_Matrix_getValueInt32(m               , i, j, &b);
                ck_assert_int_eq((int)powf((float)a,(float)iCpow[k]), b);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_epowerCFloat32(goodMatrixFloat[k], fCpow[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                float a, b;
                harkio_Matrix_getValueFloat32(goodMatrixFloat[k], i, j, &a);
                harkio_Matrix_getValueFloat32(m               , i, j, &b);
                ck_assert(fabsf(powf(a,fCpow[k]) - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_epowerCComplex(goodMatrixComplex[k], cCpow[k]);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                COMPLEX_TYPE a, b;
                harkio_Matrix_getValueComplex(goodMatrixComplex[k], i, j, &a);
                harkio_Matrix_getValueComplex(m               , i, j, &b);
                // fprintf(stderr, "%f+i%f, %f+i%f, %f+i%f\n",
                //     creal(a), cimag(a), creal(cpowf(a,cC[k])), cimag(cpowf(a,cC[k])), creal(b), cimag(b));
                ck_assert(cabsf(cpowf(a,cCpow[k]) - b) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST

START_TEST(test_reshape)
{
    harkio_Matrix *m;
    int i, k;

    setup();

    for (k=0; k<numoks; k++) {
        m = harkio_Matrix_reshape(goodMatrixInt[k], reshaperows[k], reshapecols[k]);
        ck_assert_str_eq(m->type, goodMatrixInt[k]->type);
        ck_assert_int_eq(m->rows, reshaperows[k]);
        ck_assert_int_eq(m->cols, reshapecols[k]);
        for (i=0 ; i<m->rows*m->cols ; i++) {
            ck_assert_int_eq(m->data.intdata[i], goodMatrixInt[k]->data.intdata[i]);
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_reshape(goodMatrixFloat[k], reshaperows[k], reshapecols[k]);
        ck_assert_str_eq(m->type, goodMatrixFloat[k]->type);
        ck_assert_int_eq(m->rows, reshaperows[k]);
        ck_assert_int_eq(m->cols, reshapecols[k]);
        for (i=0 ; i<m->rows*m->cols ; i++) {
            ck_assert(fabsf(m->data.floatdata[i]-goodMatrixFloat[k]->data.floatdata[i]) < 0.0001);
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_reshape(goodMatrixComplex[k], reshaperows[k], reshapecols[k]);
        ck_assert_str_eq(m->type, goodMatrixComplex[k]->type);
        ck_assert_int_eq(m->rows, reshaperows[k]);
        ck_assert_int_eq(m->cols, reshapecols[k]);
        for (i=0 ; i<m->rows*m->cols ; i++) {
            ck_assert(cabsf(m->data.complexdata[i]-goodMatrixComplex[k]->data.complexdata[i]) < 0.0001);
        }
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST


START_TEST(test_transpose)
{
    harkio_Matrix *m;
    int i, j, k;

    setup();

    for (k=0; k<numoks; k++) {
        m = harkio_Matrix_transpose(goodMatrixInt[k]);
        ck_assert_str_eq(m->type, goodMatrixInt[k]->type);
        ck_assert_int_eq(m->rows, goodMatrixInt[k]->cols);
        ck_assert_int_eq(m->cols, goodMatrixInt[k]->rows);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                int valuea, valueb;
                harkio_Matrix_getValueInt32(goodMatrixInt[k], j, i, &valuea);
                harkio_Matrix_getValueInt32(m,                i, j, &valueb);
                ck_assert_int_eq(valuea, valueb);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_transpose(goodMatrixFloat[k]);
        ck_assert_str_eq(m->type, goodMatrixFloat[k]->type);
        ck_assert_int_eq(m->rows, goodMatrixFloat[k]->cols);
        ck_assert_int_eq(m->cols, goodMatrixFloat[k]->rows);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                float valuea, valueb;
                harkio_Matrix_getValueFloat32(goodMatrixFloat[k], j, i, &valuea);
                harkio_Matrix_getValueFloat32(m,                  i, j, &valueb);
                ck_assert(fabsf(valuea - valueb) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_transpose(goodMatrixComplex[k]);
        ck_assert_str_eq(m->type, goodMatrixComplex[k]->type);
        ck_assert_int_eq(m->rows, goodMatrixComplex[k]->cols);
        ck_assert_int_eq(m->cols, goodMatrixComplex[k]->rows);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                COMPLEX_TYPE valuea, valueb;
                harkio_Matrix_getValueComplex(goodMatrixComplex[k], j, i, &valuea);
                harkio_Matrix_getValueComplex(m,                    i, j, &valueb);
                ck_assert(cabsf(valuea - valueb) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST

START_TEST(test_ctranspose)
{
    harkio_Matrix *m;
    int i, j, k;

    setup();

    for (k=0; k<numoks; k++) {
        m = harkio_Matrix_ctranspose(goodMatrixInt[k]);
        ck_assert_str_eq(m->type, goodMatrixInt[k]->type);
        ck_assert_int_eq(m->rows, goodMatrixInt[k]->cols);
        ck_assert_int_eq(m->cols, goodMatrixInt[k]->rows);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                int valuea, valueb;
                harkio_Matrix_getValueInt32(goodMatrixInt[k], j, i, &valuea);
                harkio_Matrix_getValueInt32(m,                i, j, &valueb);
                ck_assert_int_eq(valuea, valueb);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_ctranspose(goodMatrixFloat[k]);
        ck_assert_str_eq(m->type, goodMatrixFloat[k]->type);
        ck_assert_int_eq(m->rows, goodMatrixFloat[k]->cols);
        ck_assert_int_eq(m->cols, goodMatrixFloat[k]->rows);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                float valuea, valueb;
                harkio_Matrix_getValueFloat32(goodMatrixFloat[k], j, i, &valuea);
                harkio_Matrix_getValueFloat32(m,                  i, j, &valueb);
                ck_assert(fabsf(valuea - valueb) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_ctranspose(goodMatrixComplex[k]);
        ck_assert_str_eq(m->type, goodMatrixComplex[k]->type);
        ck_assert_int_eq(m->rows, goodMatrixComplex[k]->cols);
        ck_assert_int_eq(m->cols, goodMatrixComplex[k]->rows);
        for (i=0; i<m->rows; i++) {
            for (j=0; j<m->cols; j++) {
                COMPLEX_TYPE valuea, valueb;
                harkio_Matrix_getValueComplex(goodMatrixComplex[k], j, i, &valuea);
                harkio_Matrix_getValueComplex(m,                    i, j, &valueb);
                ck_assert(cabsf(conjf(valuea) - valueb) < 0.0001);
            }
        }
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST

START_TEST(test_sumRow)
{
    harkio_Matrix *m;
    int i, j, k;

    setup();

    for (k=0; k<numoks; k++) {
        m = harkio_Matrix_sumRow(goodMatrixInt[k]);
        ck_assert_str_eq(m->type, goodMatrixInt[k]->type);
        ck_assert_int_eq(m->rows, 1);
        ck_assert_int_eq(m->cols, goodMatrixInt[k]->cols);
        for (j=0; j<goodMatrixInt[k]->cols; j++) {
            int value, valuea, valueb;
            valuea = 0;
            for (i=0; i<goodMatrixInt[k]->rows; i++) {
                harkio_Matrix_getValueInt32(goodMatrixInt[k], i, j, &value);
                valuea += value;
            }
            harkio_Matrix_getValueInt32(m, 0, j, &valueb);
            ck_assert_int_eq(valuea, valueb);
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_sumRow(goodMatrixFloat[k]);
        ck_assert_str_eq(m->type, goodMatrixFloat[k]->type);
        ck_assert_int_eq(m->rows, 1);
        ck_assert_int_eq(m->cols, goodMatrixFloat[k]->cols);
        for (j=0; j<goodMatrixFloat[k]->cols; j++) {
            float value, valuea, valueb;
            valuea = 0.0;
            for (i=0; i<goodMatrixFloat[k]->rows; i++) {
                harkio_Matrix_getValueFloat32(goodMatrixFloat[k], i, j, &value);
                valuea += value;
            }
            harkio_Matrix_getValueFloat32(m, 0, j, &valueb);
            ck_assert(fabsf(valuea - valueb) < 0.0001);
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_sumRow(goodMatrixComplex[k]);
        ck_assert_str_eq(m->type, goodMatrixComplex[k]->type);
        ck_assert_int_eq(m->rows, 1);
        ck_assert_int_eq(m->cols, goodMatrixComplex[k]->cols);
        for (j=0; j<goodMatrixComplex[k]->cols; j++) {
            COMPLEX_TYPE value, valuea, valueb;
            valuea = 0.0;
            for (i=0; i<goodMatrixComplex[k]->rows; i++) {
                harkio_Matrix_getValueComplex(goodMatrixComplex[k], i, j, &value);
                valuea += value;
            }
            harkio_Matrix_getValueComplex(m, 0, j, &valueb);
            ck_assert(cabsf(valuea - valueb) < 0.0001);
        }
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST


START_TEST(test_sumCol)
{
    harkio_Matrix *m;
    int i, j, k;

    setup();

    for (k=0; k<numoks; k++) {
        m = harkio_Matrix_sumCol(goodMatrixInt[k]);
        ck_assert_str_eq(m->type, goodMatrixInt[k]->type);
        ck_assert_int_eq(m->rows, goodMatrixInt[k]->rows);
        ck_assert_int_eq(m->cols, 1);
        for (i=0; i<goodMatrixInt[k]->rows; i++) {
            int value, valuea, valueb;
            valuea = 0;
            for (j=0; j<goodMatrixInt[k]->cols; j++) {
                harkio_Matrix_getValueInt32(goodMatrixInt[k], i, j, &value);
                valuea += value;
            }
            harkio_Matrix_getValueInt32(m, i, 0, &valueb);
            ck_assert_int_eq(valuea, valueb);
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_sumCol(goodMatrixFloat[k]);
        ck_assert_str_eq(m->type, goodMatrixFloat[k]->type);
        ck_assert_int_eq(m->rows, goodMatrixFloat[k]->rows);
        ck_assert_int_eq(m->cols, 1);
        for (i=0; i<goodMatrixFloat[k]->rows; i++) {
            float value, valuea, valueb;
            valuea = 0.0;
            for (j=0; j<goodMatrixFloat[k]->cols; j++) {
                harkio_Matrix_getValueFloat32(goodMatrixFloat[k], i, j, &value);
                valuea += value;
            }
            harkio_Matrix_getValueFloat32(m, i, 0, &valueb);
            ck_assert(fabsf(valuea - valueb) < 0.0001);
        }
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_sumCol(goodMatrixComplex[k]);
        ck_assert_str_eq(m->type, goodMatrixComplex[k]->type);
        ck_assert_int_eq(m->rows, goodMatrixComplex[k]->rows);
        ck_assert_int_eq(m->cols, 1);
        for (i=0; i<goodMatrixComplex[k]->rows; i++) {
            COMPLEX_TYPE value, valuea, valueb;
            valuea = 0.0;
            for (j=0; j<goodMatrixComplex[k]->cols; j++) {
                harkio_Matrix_getValueComplex(goodMatrixComplex[k], i, j, &value);
                valuea += value;
            }
            harkio_Matrix_getValueComplex(m, i, 0, &valueb);
            ck_assert(cabsf(valuea - valueb) < 0.0001);
        }
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST


START_TEST(test_sumAll)
{
    harkio_Matrix *m;
    int i, j, k;

    int ivalue, ivaluea, ivalueb;
    float fvalue, fvaluea, fvalueb;
    COMPLEX_TYPE cvalue, cvaluea, cvalueb;

    setup();

    for (k=0; k<numoks; k++) {
        m = harkio_Matrix_sumAll(goodMatrixInt[k]);
        ck_assert_str_eq(m->type, goodMatrixInt[k]->type);
        ck_assert_int_eq(m->rows, 1);
        ck_assert_int_eq(m->cols, 1);
        ivaluea = 0;
        for (i=0; i<goodMatrixInt[k]->rows; i++) {
            for (j=0; j<goodMatrixInt[k]->cols; j++) {
                harkio_Matrix_getValueInt32(goodMatrixInt[k], i, j, &ivalue);
                ivaluea += ivalue;
            }
        }
        harkio_Matrix_getValueInt32(m, 0, 0, &ivalueb);
        ck_assert_int_eq(ivaluea, ivalueb);
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_sumAll(goodMatrixFloat[k]);
        ck_assert_str_eq(m->type, goodMatrixFloat[k]->type);
        ck_assert_int_eq(m->rows, 1);
        ck_assert_int_eq(m->cols, 1);
        fvaluea = 0.0;
        for (i=0; i<goodMatrixFloat[k]->rows; i++) {
            for (j=0; j<goodMatrixFloat[k]->cols; j++) {
                harkio_Matrix_getValueFloat32(goodMatrixFloat[k], i, j, &fvalue);
                fvaluea += fvalue;
            }
        }
        harkio_Matrix_getValueFloat32(m, 0, 0, &fvalueb);
        ck_assert(fabsf(fvaluea - fvalueb) < 0.0001);
        harkio_Matrix_delete(&m);

        m = harkio_Matrix_sumAll(goodMatrixComplex[k]);
        ck_assert_str_eq(m->type, goodMatrixComplex[k]->type);
        ck_assert_int_eq(m->rows, 1);
        ck_assert_int_eq(m->cols, 1);
        cvaluea = 0.0;
        for (i=0; i<goodMatrixComplex[k]->rows; i++) {
            for (j=0; j<goodMatrixComplex[k]->cols; j++) {
                harkio_Matrix_getValueComplex(goodMatrixComplex[k], i, j, &cvalue);
                cvaluea += cvalue;
            }
        }
        harkio_Matrix_getValueComplex(m, 0, 0, &cvalueb);
        ck_assert(cabsf(cvaluea - cvalueb) < 0.0001);
        harkio_Matrix_delete(&m);
    }

    teardown();
}
END_TEST


Suite* str_suite(void)
{
    Suite *suite = suite_create("libharkio3_matrix");


    TCase *tcase1 = tcase_create("new/delete");
    tcase_add_test(tcase1, test_new);
    tcase_add_test(tcase1, test_ones);
    tcase_add_test(tcase1, test_zeros);
    tcase_add_test(tcase1, test_eye);
    tcase_add_test(tcase1, test_delete);
    tcase_add_test(tcase1, test_vstack);
    suite_add_tcase(suite, tcase1);


    TCase *tcase2 = tcase_create("manipulation");
    tcase_add_test(tcase2, test_add);
    tcase_add_test(tcase2, test_sub);
    tcase_add_test(tcase2, test_mul);
    tcase_add_test(tcase2, test_emul);
    tcase_add_test(tcase2, test_ediv);
    tcase_add_test(tcase2, test_sum);
    tcase_add_test(tcase2, test_diag);
    // tcase_add_test(tcase2, test_clear);
    tcase_add_test(tcase2, test_sumRow);
    tcase_add_test(tcase2, test_sumCol);
    tcase_add_test(tcase2, test_sumAll);
    suite_add_tcase(suite, tcase2);


    TCase *tcase3 = tcase_create("setter / getter");
    tcase_add_test(tcase3, test_setgetValueInt);
    tcase_add_test(tcase3, test_setgetValueFloat);
    tcase_add_test(tcase3, test_setgetValueComplex);
    tcase_add_test(tcase3, test_getValues);
    tcase_add_test(tcase3, test_setValues);
    // tcase_add_test(tcase3, test_setgetData);
    suite_add_tcase(suite, tcase3);


    TCase *tcase4 = tcase_create("utilities");
    tcase_add_test(tcase4, test_size);
    tcase_add_test(tcase4, test_compare);
    tcase_add_test(tcase4, test_reshape);
    tcase_add_test(tcase4, test_transpose);
    tcase_add_test(tcase4, test_ctranspose);
    suite_add_tcase(suite, tcase4);


    TCase *tcase5 = tcase_create("read/write");
    tcase_add_test(tcase5, test_readwrite);
    suite_add_tcase(suite, tcase5);


    TCase *tcase6 = tcase_create("emaps");
    tcase_add_test(tcase6, test_eabs);
    tcase_add_test(tcase6, test_esquare);
    tcase_add_test(tcase6, test_econj);
    tcase_add_test(tcase6, test_etanh);
    tcase_add_test(tcase6, test_ecosh);
    tcase_add_test(tcase6, test_elog);
    tcase_add_test(tcase6, test_elog10);
    tcase_add_test(tcase6, test_ereal);
    tcase_add_test(tcase6, test_eimag);
    tcase_add_test(tcase6, test_emulC);
    tcase_add_test(tcase6, test_edivC);
    tcase_add_test(tcase6, test_epowerC);
    suite_add_tcase(suite, tcase6);

    return suite;
}

int main(int argc, char *argv[])
{
    int number_failed;
    Suite *suite = str_suite();
    SRunner *runner = srunner_create(suite);
    srunner_run_all(runner, CK_NORMAL);
    number_failed = srunner_ntests_failed(runner);
    srunner_free(runner);
    return number_failed;
}
