// FILE. . . . . d:/hak/hlt/src/hlt/math/fuzzy/test/Test.java
// EDIT BY . . . Hassan Ait-Kaci
// ON MACHINE. . Hp-Zbook
// STARTED ON. . Tue Jun 12 08:34:40 2018

// Last modified on Sun Aug 12 14:16:09 2018 by hak

package test;

import hlt.fot.*;
import hlt.fot.fuz.*;
import hlt.math.fuzzy.*;

import hlt.language.util.ArrayList;
import hlt.language.util.IntArrayList;
import hlt.language.util.DoubleArrayList;

public class Test
{
  public static void main (String[] args)
  {
    // FuzzyMatrix.setFuzzyAlgebra("product");

    FuzzyMatrix.precision = "%4.1f ";

    // testFuzzySetOf();
    testFuzzyMatrix();
    testSquareFuzzyMatrix();
    testSignatureSimilarity();
    testSignatureSimilarity1();
  }

  public static void testFuzzyMatrix ()
  {
    double[][] d = { { 0.0, 0.1, 0.2, 0.3 }
                   , { 0.4, 0.5, 0.6, 0.7 }
                   , { 0.8, 0.9, 1.0, 1.0 }
                   };

    System.out.println("TESTING FuzzyMatrix\n");

    FuzzyMatrix D = new FuzzyMatrix(d); // shares the actual array d, not a copy
    // Could also be:
    // FuzzyMatrix D = new FuzzyMatrix(d,true); // true: to copy and ensure only degrees within [0.0,1.0]
    D.show();
    System.out.println();

    System.out.println("random 5x8 fuzzy matrix A:");

    FuzzyMatrix A = FuzzyMatrix.random(5,8);
    A.show();
    System.out.println();

    System.out.println("Its transpose B:");
    FuzzyMatrix B = A.transpose();
    B.show();
    System.out.println();

    System.out.println("A plus transpose(B) (i.e., itself):");
    A.plus(B.transpose()).show();
    System.out.println();

    System.out.println("A times transpose(A) ("+A.rownum()+"x"+A.rownum()+" matrix):");
    A.times(A.transpose()).show();
    System.out.println();

    System.out.println("transpose(A) times A ("+A.colnum()+"x"+A.colnum()+" matrix):");
    A.transpose().times(A).show();
    System.out.println();

    // System.out.println("is A times transpose(B) equal? (should be false in general):");
    // System.out.println(A.plus(A).eq(B.transpose().plus(A)));
    // System.out.println();
  }

  public static void testSquareFuzzyMatrix ()
  {
    System.out.println("TESTING SquareFuzzyMatrix\n");

    // System.out.println("the 6x6 identity I:");

    // SquareFuzzyMatrix I = SquareFuzzyMatrix.identity(6);
    // I.show();
    // System.out.println();

    // System.out.println("a 6x6 zero matrix:");
    SquareFuzzyMatrix M = new SquareFuzzyMatrix(6);
    // M.show();
    // System.out.println();

    // // See run in test1.txt
    // System.out.println("a 6x6 matrix:");
    // // System.out.println("adding to it some pairs:");
    // M.set(1,2,.2)
    //  .set(1,3,.4)
    //  .set(3,4,.8)
    //  .set(3,5,.6)
    //  .set(4,5,.9)
    //  .set(4,6,.7);

    // See run in test2.txt
    System.out.println("a 6x6 matrix:");
    // System.out.println("adding to it some pairs:");
    M.set(1,2,.3)
     .set(1,4,.5)
     .set(2,4,1.)//.set(2,4,.7)
     .set(2,5,.4)
     .set(4,6,.2);

    // M.set(1,2,1.0)
    //  .set(1,3,1.0)
    //  .set(3,4,1.0)
    //  .set(3,5,1.0)
    //  .set(4,5,1.0)
    //  .set(4,6,1.0);
    // M.set(1,2,.2)
    //  .set(1,3,.4)
    //  .set(3,4,.8)
    //  .set(3,5,.6)
    //  .set(4,5,.9)
    //  .set(4,6,.7);
    M.show();
    System.out.println();

    System.out.println("its in-place tranpose:");
    M.i_transpose();
    M.show();
    System.out.println();

    // System.out.println("and its set of degrees:");
    // System.out.println(M.computeDegrees());
    // System.out.println();

    // System.out.println("the reflexive closure of the above:");
    // M.i_reflexive_closure();
    // M.show();
    // System.out.println();

    // System.out.println("the symmetric closure of the above:");
    // M.i_symmetric_closure();
    // M.show();
    // System.out.println();

    // System.out.println("the transitive closure of the above:");
    // M.i_transitive_closure();
    // M.show();
    // System.out.println();

    // System.out.println("the similarity closure of the above (should be the same):");
    SquareFuzzyMatrix result;

    // FuzzyMatrix.setFuzzyAlgebra("luka");
    // System.out.println("its similarity closure with lukasievicz:");
    // result = M.similarity_closure();
    // result.show();
    // System.out.println();

    // System.out.println("and its set of degrees:");
    // System.out.println(result.computeDegrees());
    // System.out.println();

    // FuzzyMatrix.setFuzzyAlgebra("product");
    // System.out.println("its similarity closure with probabilistic (product):");
    // result = M.similarity_closure();
    // result.show();
    // System.out.println();

    // System.out.println("and its set of degrees:");
    // System.out.println(result.computeDegrees());
    // System.out.println();

    // FuzzyMatrix.setFuzzyAlgebra("maxmin");
    System.out.println("its similarity closure with max/min:");
    result = M.similarity_closure();
    result.show();
    System.out.println();

    DoubleArrayList degrees = result.computeDegrees();

    System.out.println("and its set of degrees:");
    System.out.println(degrees);
    System.out.println();

    System.out.println("and its fuzzy partitions:");

    for (int k=0; k<degrees.size(); k++)
      {
  	double threshold = degrees.get(k);
  	System.out.println("at or over threshold "+threshold);
  	IntArrayList[] classes = result.partition(threshold);
  	for (int i=0; i<result.colnum(); i++)
  	  System.out.println("["+i+"] = "+classes[i]);
  	System.out.println();
      }

  }

  public static void testSignatureSimilarity ()
  {
    SimilarFunctorSignature signature = new SimilarFunctorSignature();

    // Signature and similarity of example 8 page 27 of fuzfotlat.pdf
    
    Functor a = signature.functor("a",0);
    Functor b = signature.functor("b",0);
    Functor c = signature.functor("c",0);
    Functor d = signature.functor("d",0);
    Functor f = signature.functor("f",2);
    Functor g = signature.functor("g",2);
    Functor h = signature.functor("h",2);
    Functor l = signature.functor("l",3);

    double[][] data = 
                   //   a     b     c     d     f     g    l     h
      /* a */      { { 0.0,  0.7,  0.0,  0.0,  0.0,  0.0, 0.0, 0.0 }
      /* b */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.0, 0.0, 0.0 }
      /* c */      , { 0.0,  0.0,  0.0,  0.6,  0.0,  0.0, 0.0, 0.0 }
      /* d */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.0, 0.0, 0.0 }
      /* f */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.0, 0.0, 0.0 }
      /* g */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.0, 0.0, 0.0 }
      /* l */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.0, 0.0, 0.8 }
      /* h */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.0, 0.0, 0.0 }
                   };

    showPartitions(signature,data);
  }

  public static void testSignatureSimilarity1 ()
  {
    SimilarFunctorSignature signature = new SimilarFunctorSignature();

    // Signature and similarity of example 8 page 27 of fuzfotlat.pdf
    
    Functor a = signature.functor("a",0);
    Functor b = signature.functor("b",1);
    Functor e = signature.functor("e",2);
    Functor f = signature.functor("f",3);
    Functor g = signature.functor("g",4);
    Functor h = signature.functor("h",5);

    double[][] data1 = 
                   //   a     b     e     f     g     h
      /* a */      { { 0.0,  0.2,  0.4,  0.5,  0.0,  0.0 }
      /* b */      , { 0.0,  0.0,  0.0,  1.0,  0.4,  0.0 }
      /* e */      , { 0.0,  0.0,  0.0,  0.8,  0.6,  0.0 }
      /* f */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.7 }
      /* g */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.0 }
      /* h */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.0 }
                   };

    showPartitions(signature,data1);
    
    double[][] data2 = 
                   //   a     b     e     f     g     h
      /* a */      { { 0.0,  0.2,  0.4,  0.0,  0.0,  0.0 }
      /* b */      , { 0.0,  0.0,  0.0,  1.0,  0.0,  0.0 }
      /* e */      , { 0.0,  0.0,  0.0,  0.8,  0.6,  0.0 }
      /* f */      , { 0.0,  0.0,  0.0,  0.0,  0.9,  0.7 }
      /* g */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.0 }
      /* h */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.0 }
                   };

    showPartitions(signature,data2);
    
    double[][] data3 = 
                   //   a     b     e     f     g     h
      /* a */      { { 0.0,  0.8,  0.0,  0.0,  0.0,  0.0 }
      /* b */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.0 }
      /* e */      , { 0.0,  0.0,  0.0,  0.6,  0.7,  0.4 }
      /* f */      , { 0.0,  0.0,  0.0,  0.0,  0.9,  0.7 }
      /* g */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.0 }
      /* h */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.0 }
                   };

    showPartitions(signature,data3);
    
    double[][] data4 = 
                   //   a     b     e     f     g     h
      /* a */      { { 0.0,  0.3,  0.0,  0.5,  0.0,  0.0 }
      /* b */      , { 0.0,  0.0,  0.0,  0.5,  0.4,  0.0 }
      /* e */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.0 }
      /* f */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.2 }
      /* g */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.0 }
      /* h */      , { 0.0,  0.0,  0.0,  0.0,  0.0,  0.0 }
                   };

    showPartitions(signature,data4);
  }

  private static void showPartitions (SimilarFunctorSignature signature, double[][] data)
  {
    int size = signature.size();

    System.out.println("------------------------------------------------------------------------");
    System.out.println();

    System.out.println("a signature of "+size+" functors: "+signature);
    System.out.println();

    SignatureSimilarity sim = new SignatureSimilarity(signature,data);

    System.out.println("the "+size+"x"+size+" similarity closure of the similar pairs in this signature:\n");
    sim.show();

    DoubleArrayList degrees = sim.computeDegrees();

    System.out.println("and its set of degrees: "+setForm(degrees));
    System.out.println();

    System.out.println("and its fuzzy partitions:\n");

    for (int k=0; k<degrees.size(); k++)
      {
  	double threshold = degrees.get(k);
  	System.out.print(">= "+threshold+": ");
  	IntArrayList[] indexClasses = sim.partition(threshold);

	// // by indices:
	// System.out.println("by indices:");
  	// for (int i=0; i<sim.rank(); i++)
  	//   System.out.println("["+i+"] = "+indexClasses[i]);
  	// System.out.println();

	// // by names:
	// System.out.println("by names:");
	ArrayList[] nameClasses = new ArrayList[sim.rank()];
	for (int i=0; i<sim.rank(); i++)
	  {
	    ArrayList nameClass = new ArrayList();
	    for (int j=0; j<indexClasses[i].size(); j++)
	      nameClass.add(sim.functor(indexClasses[i].get(j)).name());
	    nameClasses[i] = nameClass;
	  }

  	// for (int i=0; i<sim.rank(); i++)
  	//   System.out.println("["+sim.functor(i).name()+"] = "+setForm(nameClasses[i]));
  	// System.out.println();

	ArrayList dejavu = new ArrayList(sim.rank());

  	for (int i=0; i<sim.rank(); i++)
	  {
	    ArrayList classNames = nameClasses[i];
	    if (!dejavu.contains(classNames))
	      {
		System.out.print(" "+setForm(classNames));
		dejavu.add(classNames);
	      }
	  }
  	System.out.println("\n");
      }
  }

  private static String setForm (ArrayList list)
  {
    StringBuilder buf = new StringBuilder("{");

    int size = list.size();
    for (int i=0; i<size; i++)
      buf.append(list.get(i)+(i==size-1?"":","));

    return (buf.append("}")).toString();
  }
  
  private static String setForm (DoubleArrayList list)
  {
    StringBuilder buf = new StringBuilder("{");

    int size = list.size();
    for (int i=0; i<size; i++)
      buf.append(list.get(i)+(i==size-1?"":", "));

    return (buf.append("}")).toString();
  }
  
}
