package SPVMAIUtilTest {
  use SPVM::AI::Util::FloatMatrix;
  use SPVM::AI::Util (
      mat_newf,
      mat_transposef,
      mat_strf,
      mat_addf,
      mat_subf,
      mat_scamulf,
      mat_mulf,
      mat_new_zerof,
      mat_new_identf,
  );
  use SPVM::Util (equals_farray, equals_darray);

  sub matrix_float : float () {
    my $mat = mat_newf([(float)1, 2, 3, 4, 5, 6], 2, 3);
    my $rows_length = $mat->{rows_length};
    unless ($rows_length == 2) {
      return 0;
    }
    my $columns_length = $mat->{columns_length};
    unless ($columns_length == 3) {
      return 0;
    }
    my $values = $mat->{values};
    unless ($values->[0] == 1) {
      return 0;
    }
    unless ($values->[5] == 6) {
      return 0;
    }
    unless (@$values == 6) {
      return 0;
    }
    unless ($values isa float[]) {
      return 0;
    }

    my $mat_str = mat_strf($mat);
    unless ($mat_str eq "1 3 5\n2 4 6\n") {
      return 0;
    }

    # transpose
    my $mat_trans = mat_transposef($mat);
    unless ($mat_trans != $mat) {
      return 0;
    }
    unless (equals_farray($mat_trans->{values}, [(float)1, 3, 5, 2, 4, 6])) {
      return 0;
    }
    unless ($mat_trans->{rows_length} == $columns_length && $mat_trans->{rows_length} == 3) {
      return 0;
    }
    unless ($mat_trans->{columns_length} == $rows_length && $mat_trans->{columns_length} == 2) {
      return 0;
    }
    return 1;
  }

  sub matrix_add_float : int () {
    my $mat1 = SPVM::AI::Util->mat_newf([(float)1, 2, 3, 4, 5, 6], 2, 3);
    my $mat2 = SPVM::AI::Util->mat_newf([(float)11, 12, 13, 14, 15, 16], 2, 3);
    my $mat3 = mat_addf($mat1, $mat2);

    unless ($mat3->{values} isa float[]) {
      return 0;
    }

    if ($mat3 == $mat1) {
      return 0;
    }

    if ($mat3 == $mat2) {
      return 0;
    }

    unless ($mat3->{rows_length} == 2 && $mat3->{columns_length} == 3) {
      return 0;
    }

    unless (equals_farray($mat3->{values}, [(float)12, 14, 16, 18, 20, 22])) {
      return 0;
    }

    return 1;
  }
  sub matrix_sub_float : int () {
    my $mat1 = SPVM::AI::Util->mat_newf([(float)1, 2, 3, 4, 5, 6], 2, 3);
    my $mat2 = SPVM::AI::Util->mat_newf([(float)16, 15, 14, 13, 12, 11], 2, 3);
    my $mat3 = mat_subf($mat1, $mat2);
    
    unless ($mat3->{values} isa float[]) {
      return 0;
    }

    if ($mat3 == $mat1) {
      return 0;
    }

    if ($mat3 == $mat2) {
      return 0;
    }

    unless ($mat3->{rows_length} == 2 && $mat3->{columns_length} == 3) {
      return 0;
    }

    unless (equals_farray($mat3->{values}, [(float)-15, -13, -11, -9, -7, -5])) {
      return 0;
    }

    return 1;
  }

  sub matrix_scamul_float : int () {
    my $mat1 = SPVM::AI::Util->mat_newf([(float)1, 2, 3, 4, 5, 6], 2, 3);
    my $mat2 = mat_scamulf((float)3, $mat1);

    unless ($mat2->{values} isa float[]) {
      return 0;
    }

    if ($mat2 == $mat1) {
      return 0;
    }

    unless ($mat2->{rows_length} == 2 && $mat2->{columns_length} == 3) {
      return 0;
    }

    unless (equals_farray($mat2->{values}, [(float)3, 6, 9, 12, 15, 18])) {
      return 0;
    }

    return 1;
  }

  sub matrix_new_zero_float : int () {
    my $mat1 = mat_new_zerof(2, 3);

    unless ($mat1->{values} isa float[]) {
      return 0;
    }

    unless ($mat1->{rows_length} == 2 && $mat1->{columns_length} == 3) {
      return 0;
    }


    unless (equals_farray($mat1->{values}, [(float)0, 0, 0, 0, 0, 0])) {
      return 0;
    }

    return 1;
  }
  sub matrix_new_ident_float : int () {
    my $mat1 = mat_new_identf(3);

    unless ($mat1->{values} isa float[]) {
      return 0;
    }

    unless ($mat1->{rows_length} == 3 && $mat1->{columns_length} == 3) {
      return 0;
    }


    unless (equals_farray($mat1->{values}, [(float)1, 0, 0, 0, 1, 0, 0, 0, 1])) {
      return 0;
    }

    return 1;
  }

  sub matrix_mul_float : int () {
    my $mat1 = SPVM::AI::Util->mat_newf([(float)1, 2, 3, 4, 5, 6], 2, 3);
    my $mat2 = SPVM::AI::Util->mat_newf([(float)2, 3, 4, 5, 6, 7], 3, 2);
    my $mat3 = mat_mulf($mat1, $mat2);

    unless ($mat3->{values} isa float[]) {
      return 0;
    }

    if ($mat3 == $mat1) {
      return 0;
    }

    if ($mat3 == $mat2) {
      return 0;
    }

    unless ($mat3->{rows_length} == 2 && $mat3->{columns_length} == 2) {
      return 0;
    }

    unless (equals_farray($mat3->{values}, [(float)31, 40, 58, 76])) {
      return 0;
    }

    return 1;
  }
}