V1_0.java [src/java/m/ann/selection] Revision: default  Date:
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package m.ann.selection;

//import com.owlike.genson.Genson;
import m.ann.selection.mechanism.SelectionMechanism;
import utils.MongoAccess;
import csip.ModelDataService;
import csip.ServiceException;
import csip.utils.ANN;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javax.ws.rs.Path;
import oms3.annotations.Description;
import oms3.annotations.Name;
import org.bson.Document;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.encog.ml.data.MLData;
import org.encog.ml.data.MLDataSet;
import org.encog.neural.neat.NEATNetwork;
import org.hyperledger.fabric.gateway.ContractException;
import utils.CSIPMLDataSet;
import utils.Calc;
import utils.ErrorEstimate;
import utils.MongoUtils;
import utils.blockchain.application.java.FeNS_blockchain;

/**
 *
 * @author sidereus
 */
@Name("Select the best networks")
@Description("Select the best networks depending on validation error analysis")
@Path("m/select/1.0")
public class V1_0 extends ModelDataService {

  protected String ann;
  protected String mechanism;
  protected double threshold;
  protected String varName;
  protected String error;
  protected Boolean blockchain;


  @Override
  public void preProcess() throws ServiceException, JSONException {
    if (parameter().getNames().contains("select")) {
      JSONArray train = parameter().getJSONArray("select");
      Map<String, JSONObject> payload = new LinkedHashMap();
      for (int i = 0; i < train.length(); i++) {
        JSONObject obj = train.getJSONObject(i);
        String name = obj.getString("name");
        payload.put(name, obj);
      }
      ann = payload.get("annName").getString("value");
      mechanism = payload.get("mechanism").getString("value");
      threshold = payload.get("threshold").getInt("value");
      varName = payload.get("variable").getString("value");
      error = payload.get("error").getString("value");
      blockchain = payload.get("blockchain").getBoolean("value");
    } else {
      ann = parameter().getString("annName");
      mechanism = parameter().getString("mechanism", "percentile");
      threshold = parameter().getDouble("threshold", 95);
      varName = parameter().getString("variable");
      error = parameter().getString("error", "nashSutcliffe");
      blockchain = parameter().getBoolean("blockchain", false);
    }

  }


  @Override // new json request from combined
  public void doProcess() throws ServiceException, IOException, ContractException {

//    Genson genson = new Genson();
    // @TODO: throw exception only if net has more than one output node
    SelectionMechanism selMechanism = SelectionMechanism.mechanism(mechanism, varName, error, threshold, ann);
    Selected selANNs = selMechanism.select();

    ErrorEstimate ee = errorEstimate(ann, selANNs.getANNs());
    ee.compute();

    if (selANNs.getANNCount() == 0) {
      throw new ServiceException("No Anns selected.");
    }

    if (parameter().getBoolean("download", false)) {
      // The selected anns should be downloaded.
      File zippedAnns = ANN.writeAnns(workspace().getFile("anns"), selANNs.getANNs());
      results().put(zippedAnns);
    } else {
      // push them to a different collection
      MongoAccess.pushSelectedANNs(ann, selANNs.getANNids(), ee);
    }
    File zippedAnns = ANN.writeAnns(workspace().getFile("anns"), selANNs.getANNs());
    if (blockchain) {
      FeNS_blockchain.init();
      FeNS_blockchain.submit("FeNS_select", MongoAccess.getCollectionHash(ann, "selected"));
//      FeNS_blockchain.submit("FeNS_normalize", MongoAccess.getCollectionHash(ann, "selected"), serialize);
//      FeNS_blockchain.getAssets();
    }

    // return the percentile, t-error, number of selected anns
    results().put("status", "ok");
    results().put("error", error);
    results().put("error treshold", selANNs.getTresholdError());
    results().put("selected_anns", selANNs.getANNCount());
    results().put("Between_quartiles", ee.getQuartilesPerc());
    results().put("Between_min_max", ee.getMinMaxPerc());
  }


  @Override
  public void postProcess() {
  }


  private ErrorEstimate errorEstimate(String ann_in, List<NEATNetwork> nn) throws ServiceException {
    Iterable<Document> d = MongoAccess.getSortedNormalizedData(ann_in, MongoAccess.NORMALIZED, MongoAccess.NAME, MongoUtils.Sorting.ASCENDING);

    int dataLength = d.iterator().next().get(MongoAccess.METADATA, Document.class).getInteger(MongoAccess.VALUES_COUNT);
    List<Integer> indices = IntStream.range(0, dataLength).boxed().collect(Collectors.toCollection(ArrayList::new));

    MLDataSet dataset = new CSIPMLDataSet(d, Calc.toIntArray(indices));

    ErrorEstimate ee = new ErrorEstimate();
    dataset.forEach(data -> {
      List<Double> res = new ArrayList<>();
      double observed = data.getIdeal().getData(0);
      nn.forEach(n -> {
        MLData result = n.compute(data.getInput());
        res.add(result.getData(0));
      });
      ee.add(res, observed);
    });
    return ee;
  }

}