/*
* This file is part of ADDIS (Aggregate Data Drug Information System).
* ADDIS is distributed from http://drugis.org/.
* Copyright © 2009 Gert van Valkenhoef, Tommi Tervonen.
* Copyright © 2010 Gert van Valkenhoef, Tommi Tervonen, Tijs Zwinkels,
* Maarten Jacobs, Hanno Koeslag, Florin Schimbinschi, Ahmad Kamal, Daniel
* Reid.
* Copyright © 2011 Gert van Valkenhoef, Ahmad Kamal, Daniel Reid, Florin
* Schimbinschi.
* Copyright © 2012 Gert van Valkenhoef, Daniel Reid, Joël Kuiper, Wouter
* Reckman.
* Copyright © 2013 Gert van Valkenhoef, Joël Kuiper.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.drugis.addis.presentation;
import java.io.IOException;
import java.io.OutputStream;
import java.text.Normalizer;
import java.text.Normalizer.Form;
import java.util.Locale;
import java.util.regex.Pattern;
import org.apache.commons.math3.linear.RealMatrix;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;
import org.drugis.addis.entities.Entity;
import org.drugis.addis.entities.OutcomeMeasure;
import org.drugis.addis.entities.OutcomeMeasure.Direction;
import org.drugis.addis.entities.analysis.BenefitRiskAnalysis;
import org.drugis.addis.util.JSMAAintegration.AbstractBenefitRiskSMAAFactory;
import fi.smaa.jsmaa.model.BetaMeasurement;
import fi.smaa.jsmaa.model.Criterion;
import fi.smaa.jsmaa.model.CriterionMeasurement;
import fi.smaa.jsmaa.model.FullJointMeasurements;
import fi.smaa.jsmaa.model.GaussianMeasurement;
import fi.smaa.jsmaa.model.ImpactMatrix;
import fi.smaa.jsmaa.model.Interval;
import fi.smaa.jsmaa.model.Measurement;
import fi.smaa.jsmaa.model.MultivariateGaussianCriterionMeasurement;
import fi.smaa.jsmaa.model.PerCriterionMeasurements;
import fi.smaa.jsmaa.model.RelativeGaussianCriterionMeasurement;
import fi.smaa.jsmaa.model.RelativeLogitGaussianCriterionMeasurement;
import fi.smaa.jsmaa.model.SMAAModel;
public class SMAASerializer<Alternative extends Entity, AnalysisType extends BenefitRiskAnalysis<Alternative>> {
private SMAAModel d_model;
private BenefitRiskAnalysis<Alternative> d_analysis;
private AbstractBenefitRiskSMAAFactory<Alternative> d_factory;
private ObjectMapper d_mapper;
private static final Pattern NONLATIN = Pattern.compile("[^\\w-]");
private static final Pattern WHITESPACE = Pattern.compile("[\\s]");
public static String toSlug(String input) {
String nowhitespace = WHITESPACE.matcher(input).replaceAll("-");
String normalized = Normalizer.normalize(nowhitespace, Form.NFD);
String slug = NONLATIN.matcher(normalized).replaceAll("");
return slug.toLowerCase(Locale.ENGLISH);
}
public SMAASerializer(SMAAModel model, AnalysisType a, AbstractBenefitRiskSMAAFactory<Alternative> smaaFactory) {
d_model = model;
d_analysis = a;
d_factory = smaaFactory;
d_mapper = new ObjectMapper();
}
public JsonNode getRootNode() {
ObjectNode rootNode = (ObjectNode) d_mapper.createObjectNode();
rootNode.put("title", d_analysis.getName());
insertCriteria(d_mapper, rootNode);
insertAlternatives(d_mapper, rootNode);
// Add PerfomanceTable
FullJointMeasurements m = d_model.getMeasurements();
ArrayNode performancesNode = (ArrayNode) d_mapper.createArrayNode();
if (m instanceof ImpactMatrix) {
insertMeasurements(d_mapper, m, performancesNode);
}
if (m instanceof PerCriterionMeasurements) {
insertPerCriterionMeasurement(d_mapper, m, performancesNode);
}
rootNode.put("performanceTable", performancesNode);
rootNode.put("preferences", d_mapper.createObjectNode());
return rootNode;
}
public void serialize(OutputStream stream) {
try {
d_mapper.writerWithDefaultPrettyPrinter().writeValue(stream, getRootNode());
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void insertPerCriterionMeasurement(ObjectMapper mapper, FullJointMeasurements m, ArrayNode performancesNode) {
PerCriterionMeasurements measurements = (PerCriterionMeasurements) m;
for (Criterion criterion : measurements.getCriteria()) {
ObjectNode measurementNode = (ObjectNode) mapper.createObjectNode();
measurementNode.put("criterion", toSlug(criterion.getName()));
ObjectNode performanceNode = (ObjectNode) mapper.createObjectNode();
CriterionMeasurement criterionMeasurement = measurements.getCriterionMeasurement(criterion);
Class<? extends CriterionMeasurement> measurementType = criterionMeasurement.getClass();
if (measurementType.equals(RelativeLogitGaussianCriterionMeasurement.class)
|| measurementType.equals(RelativeGaussianCriterionMeasurement.class)) {
ObjectNode parameterNode = (ObjectNode) mapper.createObjectNode();
String type = measurementType.equals(RelativeLogitGaussianCriterionMeasurement.class) ? "relative-logit-normal" : "relative-normal";
performanceNode.put("type", type);
GaussianMeasurement baseline;
MultivariateGaussianCriterionMeasurement relativeMeasurement;
CriterionMeasurement measurement = measurementType.cast(criterionMeasurement);
if (measurementType.equals(RelativeLogitGaussianCriterionMeasurement.class)) {
RelativeLogitGaussianCriterionMeasurement tmp = (RelativeLogitGaussianCriterionMeasurement) measurement;
baseline = tmp.getGaussianMeasurement().getBaselineMeasurement();
relativeMeasurement = tmp.getGaussianMeasurement().getRelativeMeasurement();
} else {
RelativeGaussianCriterionMeasurement tmp = (RelativeGaussianCriterionMeasurement) measurement;
baseline = tmp.getBaselineMeasurement();
relativeMeasurement = tmp.getRelativeMeasurement();
}
// Add baseline
ObjectNode baselineNode = (ObjectNode) mapper.createObjectNode();
baselineNode.put("type", "dnorm");
baselineNode.put("name", toSlug(d_analysis.getBaseline().getLabel()));
baselineNode.put("mu", baseline.getMean());
baselineNode.put("sigma", baseline.getStDev());
parameterNode.put("baseline", baselineNode);
// Add relative
ObjectNode relativeNode = (ObjectNode) mapper.createObjectNode();
relativeNode.put("type", "dmnorm");
ObjectNode relativeMuNode = (ObjectNode) mapper.createObjectNode();
ObjectNode relativeCovNode = (ObjectNode) mapper.createObjectNode();
ArrayNode relativeCovRowNames = (ArrayNode) mapper.createArrayNode();
ArrayNode relativeCovColNames = (ArrayNode) mapper.createArrayNode();
for (int i = 0; i < relativeMeasurement.getAlternatives().size(); ++i) {
String alternative = toSlug(relativeMeasurement.getAlternatives().get(i).getName());
relativeCovRowNames.add(alternative);
relativeCovColNames.add(alternative);
relativeMuNode.put(alternative, relativeMeasurement.getMeanVector().getEntry(i));
}
relativeCovNode.put("colnames", relativeCovColNames);
relativeCovNode.put("rownames", relativeCovRowNames);
ArrayNode relativeCovDataNode = (ArrayNode) mapper.createArrayNode();
RealMatrix covarianceMatrix = relativeMeasurement.getCovarianceMatrix();
for (int i = 0; i < covarianceMatrix.getRowDimension(); ++i) {
ArrayNode row = (ArrayNode) mapper.createArrayNode();
for (int j = 0; j < covarianceMatrix.getRowDimension(); ++j) {
row.add(covarianceMatrix.getRow(i)[j]);
}
relativeCovDataNode.add(row);
}
relativeCovNode.put("data", relativeCovDataNode);
relativeNode.put("mu", relativeMuNode);
relativeNode.put("cov", relativeCovNode);
parameterNode.put("relative", relativeNode);
performanceNode.put("parameters", parameterNode);
}
measurementNode.put("performance", performanceNode);
performancesNode.add(measurementNode);
}
}
private void insertMeasurements(ObjectMapper mapper, FullJointMeasurements m, ArrayNode performancesNode) {
ImpactMatrix impactMatrix = (ImpactMatrix) m;
for (Criterion criterion : impactMatrix.getCriteria()) {
for (fi.smaa.jsmaa.model.Alternative alternative : impactMatrix.getAlternatives()) {
ObjectNode measurementNode = (ObjectNode) mapper.createObjectNode();
measurementNode.put("alternative", toSlug(alternative.getName()));
measurementNode.put("criterion", toSlug(criterion.getName()));
ObjectNode performanceNode = (ObjectNode) mapper.createObjectNode();
Measurement measurement = impactMatrix.getMeasurement(criterion, alternative);
if (measurement instanceof BetaMeasurement) {
BetaMeasurement betaMeasurement = (BetaMeasurement) measurement;
performanceNode.put("type", "dbeta");
ObjectNode parameters = (ObjectNode) mapper.createObjectNode();
parameters.put("alpha", betaMeasurement.getAlpha());
parameters.put("beta", betaMeasurement.getBeta());
performanceNode.put("parameters", parameters);
}
if (measurement instanceof GaussianMeasurement) {
GaussianMeasurement gaussianMeasurement = (GaussianMeasurement) measurement;
performanceNode.put("type", "dnorm");
ObjectNode parameters = (ObjectNode) mapper.createObjectNode();
parameters.put("mu", gaussianMeasurement.getMean());
parameters.put("sigma", gaussianMeasurement.getStDev());
performanceNode.put("parameters", parameters);
}
measurementNode.put("performance", performanceNode);
performancesNode.add(measurementNode);
}
}
}
private void insertAlternatives(ObjectMapper mapper, ObjectNode rootNode) {
// Add Alternatives
ObjectNode alternativesNode = (ObjectNode) mapper.createObjectNode();
for (fi.smaa.jsmaa.model.Alternative alternative : d_model.getAlternatives()) {
ObjectNode alternativeNode = (ObjectNode) mapper.createObjectNode();
alternativeNode.put("title", alternative.getName());
alternativesNode.put(toSlug(alternative.getName()), alternativeNode);
}
rootNode.put("alternatives", alternativesNode);
}
private void insertCriteria(ObjectMapper mapper, ObjectNode rootNode) {
// Add Criteria
ObjectNode criteriaNode = (ObjectNode) mapper.createObjectNode();
for (OutcomeMeasure criterion : d_analysis.getCriteria()) {
ObjectNode criterionNode = (ObjectNode) mapper.createObjectNode();
criterionNode.put("title", criterion.getLabel());
ObjectNode pvfNode = (ObjectNode) mapper.createObjectNode();
pvfNode.put("direction", criterion.getDirection() == Direction.HIGHER_IS_BETTER ? "increasing" : "decreasing");
pvfNode.put("type", "linear");
ArrayNode scaleRangeNode = mapper.createArrayNode();
Interval scale = d_factory.getCriterion(criterion).getScale();
scaleRangeNode.add(scale.getStart());
scaleRangeNode.add(scale.getEnd());
pvfNode.put("range", scaleRangeNode);
criterionNode.put("pvf", pvfNode);
criteriaNode.put(toSlug(criterion.getName()), criterionNode);
}
rootNode.put("criteria", criteriaNode);
}
}