/* * 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.entities.analysis; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.drugis.addis.entities.Arm; import org.drugis.addis.entities.BasicContinuousMeasurement; import org.drugis.addis.entities.BasicMeasurement; import org.drugis.addis.entities.BasicRateMeasurement; import org.drugis.addis.entities.ContinuousMeasurement; import org.drugis.addis.entities.Entity; import org.drugis.addis.entities.Indication; import org.drugis.addis.entities.Measurement; import org.drugis.addis.entities.OutcomeMeasure; import org.drugis.addis.entities.RateMeasurement; import org.drugis.addis.entities.Study; import org.drugis.addis.entities.relativeeffect.BasicOddsRatio; import org.drugis.addis.entities.relativeeffect.BasicStandardisedMeanDifference; import org.drugis.addis.entities.relativeeffect.Beta; import org.drugis.addis.entities.relativeeffect.Distribution; import org.drugis.addis.entities.relativeeffect.TransformedStudentT; import org.drugis.addis.util.EntityUtil; import com.jgoodies.binding.list.ArrayListModel; import com.jgoodies.binding.list.ObservableList; public class StudyBenefitRiskAnalysis extends BenefitRiskAnalysis<Arm> { public static String PROPERTY_STUDY = "study"; public static String PROPERTY_ARMS = "arms"; private Study d_study; private Indication d_indication; private List<OutcomeMeasure> d_criteria; private ObservableList<Arm> d_alternatives; private AnalysisType d_analysisType; private final Arm d_baseline; private DecisionContext d_decisionContext; private class StudyMeasurementSource extends AbstractMeasurementSource<Arm> { } public StudyBenefitRiskAnalysis(String name, Indication indication, Study study, List<OutcomeMeasure> criteria, List<Arm> alternatives, AnalysisType analysisType) { this(name, indication, study, criteria, alternatives.get(0), alternatives, analysisType); } public StudyBenefitRiskAnalysis(String name, Indication indication, Study study, List<OutcomeMeasure> criteria, Arm baseline, List<Arm> alternatives, AnalysisType analysisType) { this(name, indication, study, criteria, baseline, alternatives, analysisType, null); } public StudyBenefitRiskAnalysis(String name, Indication indication, Study study, List<OutcomeMeasure> criteria, Arm baseline, List<Arm> alternatives, AnalysisType analysisType, DecisionContext context) { super(name); d_baseline = baseline; assertMeasurementsPresent(study, criteria, alternatives); d_indication = indication; d_study = study; setCriteria(criteria); d_alternatives = new ArrayListModel<Arm>(Collections.unmodifiableList(alternatives)); d_analysisType = analysisType; if(d_analysisType == AnalysisType.LyndOBrien && (d_criteria.size() != 2 || d_alternatives.size() != 2) ) { throw new IllegalArgumentException("Attempt to create Lynd & O'Brien analysis with not exactly 2 criteria and 2 alternatives"); } d_decisionContext = context; } private void assertMeasurementsPresent(Study study, List<OutcomeMeasure> criteria, List<Arm> alternatives) { for (OutcomeMeasure om : criteria) { for (Arm a : alternatives) { if (study.getMeasurement(om, a) == null) { throw new IllegalArgumentException("Trying to create a StudyBR, but " + a + "," + om + " has no measurement in study " + study); } } } } private void setCriteria(List<OutcomeMeasure> criteria) { criteria = new ArrayList<OutcomeMeasure>(criteria); Collections.sort(criteria); d_criteria = Collections.unmodifiableList(criteria); } @Override public Set<? extends Entity> getDependencies() { Set <Entity> deps = new HashSet<Entity>(d_study.getDependencies()); deps.add(d_study); return deps; } public ObservableList<Arm> getArms() { return d_alternatives; } public ObservableList<Arm> getAlternatives() { return d_alternatives; } public Indication getIndication() { return d_indication; } public Distribution getMeasurement(OutcomeMeasure criterion, Arm alternative) { Measurement measurement = d_study.getMeasurement(criterion, alternative); if (measurement instanceof RateMeasurement) { RateMeasurement rateMeasurement = (RateMeasurement) measurement; return new Beta(1 + rateMeasurement.getRate(), 1 + rateMeasurement.getSampleSize() - rateMeasurement.getRate()); } else if (measurement instanceof ContinuousMeasurement) { ContinuousMeasurement contMeasurement = (ContinuousMeasurement) measurement; return new TransformedStudentT(contMeasurement.getMean(), contMeasurement.getStdDev() / Math.sqrt(contMeasurement.getSampleSize()), contMeasurement.getSampleSize() - 1); } else { throw new IllegalStateException("Unknown measurement type " + measurement.getClass().getSimpleName()); } } public List<OutcomeMeasure> getCriteria() { return d_criteria; } public Study getStudy() { return d_study; } @Override public String toString() { return getName(); } public MeasurementSource<Arm> getMeasurementSource() { return new StudyMeasurementSource(); } public AnalysisType getAnalysisType() { return d_analysisType; } @Override public boolean deepEquals(Entity other) { if (!equals(other) || !(other instanceof StudyBenefitRiskAnalysis)) { return false; } StudyBenefitRiskAnalysis o = (StudyBenefitRiskAnalysis) other; return EntityUtil.deepEqual(getStudy(), o.getStudy()) && EntityUtil.deepEqual(getIndication(), o.getIndication()) && EntityUtil.deepEqual(getBaseline(), o.getBaseline()) && EntityUtil.deepEqual(getAlternatives(), o.getAlternatives()) && EntityUtil.deepEqual(getCriteria(), o.getCriteria()) && EntityUtil.deepEqual(getDecisionContext(), o.getDecisionContext()); } public Arm getBaseline() { return d_baseline; } public DecisionContext getDecisionContext() { return d_decisionContext; } public Distribution getRelativeEffectDistribution(OutcomeMeasure om, Arm subject) { BasicMeasurement baseMeas = getStudy().getMeasurement(om, d_baseline); BasicMeasurement subjMeas = getStudy().getMeasurement(om, subject); if (baseMeas instanceof BasicRateMeasurement) { BasicOddsRatio ratio = new BasicOddsRatio((RateMeasurement) baseMeas, (RateMeasurement) subjMeas); if (ratio.isDefined()) { return ratio.getDistribution(); } else { if (ratio.getCorrected().isDefined()) { return ratio.getCorrected().getDistribution(); } else { return null; } } } if (baseMeas instanceof BasicContinuousMeasurement) { return new BasicStandardisedMeanDifference((ContinuousMeasurement) baseMeas, (ContinuousMeasurement) subjMeas).getDistribution(); } throw new IllegalStateException("Unknown error creating relative effect distribution in StudyBenefitRiskAnalysis"); } @Override public List<Arm> getNonBaselineAlternatives() { List<Arm> list = new ArrayList<Arm>(d_alternatives); list.remove(getBaseline()); return list; } }