Commit e3a8f107 authored by Romana Pernischova's avatar Romana Pernischova
Browse files

Initial commit

parents
# Change and Impact Visualization (CHIMP) Plugin
This repository contains code for the Protégé desktop plugin.
### Prerequisites
To build and run the plugin, the following items must be installed:
+ Apache's [Maven](http://maven.apache.org/index.html).
+ A Protege distribution (5.0.0 or higher). The Protege 5.2.0 release is [available](http://protege.stanford.edu/products.php#desktop-protege) from the main Protege website.
### Build
1. In the chimp-plugin directory:
mvn clean package
2. On build completion, the "target" directory will contain a chimp-plugin${version}.jar file.
3. Copy the JAR file from the target directory to the "plugins" subdirectory of your Protege distribution.
### View the Plugin in Protégé
1. Launch your Protege distribution.
2. Window > Views > Ontology views > Change and Impact Visualization
3. Select About from the Help menu to verify successful installation
### Develop
#### Setup
1. Download the project:
git clone git@gitlab.ifi.uzh.ch:ddis/Students/Theses/2020-mirko-serbak.git
2. Open up in an IDE: Intellij works best.
3. Ensure that Maven is available
4. Setup runtime configuration
Arguments: clean package
Runtime: Use a JDK instead of a JRE
#### Dependencies
The Maven POM file in the top-level directory defines how the [Maven Bundle Plugin](http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html) packages the plug-in code into the required OSGi bundle format.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>chimp</groupId>
<artifactId>chimp.plugin</artifactId>
<version>1.1.0</version>
<packaging>bundle</packaging>
<name>Chimp Plugin</name>
<description>Compact change and impact view</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/edu.stanford.protege/protege-editor-owl -->
<dependency>
<groupId>edu.stanford.protege</groupId>
<artifactId>protege-editor-owl</artifactId>
<version>5.5.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit-jupiter.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.assertj/assertj-core -->
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.17.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.miglayout/miglayout -->
<dependency>
<groupId>com.miglayout</groupId>
<artifactId>miglayout</artifactId>
<version>3.7.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.scilab.forge/jlatexmath -->
<dependency>
<groupId>org.scilab.forge</groupId>
<artifactId>jlatexmath</artifactId>
<version>1.0.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.sourceforge.owlapi/org.semanticweb.hermit -->
<dependency>
<groupId>net.sourceforge.owlapi</groupId>
<artifactId>org.semanticweb.hermit</artifactId>
<version>1.4.5.456</version>
<!-- CHANGE TO TEST TO EXCLUDE IT FROM TARGET -->
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.knowm.xchart/xchart -->
<dependency>
<groupId>org.knowm.xchart</groupId>
<artifactId>xchart</artifactId>
<version>3.6.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-csv -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.8</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<!-- Use resource filtering to replace references to the artifactId in the plugin.xml file -->
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<excludes>
<!-- Exclude performance tests-->
<exclude>**/*PerformanceTest.java</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>3.0.0</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-ClassPath>.</Bundle-ClassPath>
<Bundle-SymbolicName>${project.artifactId};singleton:=true</Bundle-SymbolicName>
<Bundle-Vendor>Mirko Serbak</Bundle-Vendor>
<Embed-Dependency>
miglayout; version="3.7.4"; scope=compile|runtime,
jlatexmath; version="1.0.7"; scope=compile|runtime,
xchart; version="3.6.5"; scope=compile|runtime,
</Embed-Dependency>
<Import-Package>
org.protege.editor.owl.*;version="5.0.0", <!-- equivalent to [5.0.0,infinity) -->
*;resolution:=optional
</Import-Package>
</instructions>
</configuration>
</plugin>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<pde>true</pde>
</configuration>
</plugin>
</plugins>
</build>
</project>
package metrics;
import org.semanticweb.owlapi.model.OWLAxiom;
import java.util.Set;
public interface ImpactMetric {
/**
* This interface acts as a marker interface and enforces the following method:
* <p>
* calculateMetricWithMaterializations() is used for testing purposes: see test/metrictests/ontologies
*/
double calculateMetricWithMaterializations(Set<OWLAxiom> oldMaterialization, Set<OWLAxiom> newMaterialization);
}
package metrics;
import java.util.LinkedList;
public abstract class Metric {
private final String displayName;
private final String description;
private String latexFormula;
private final LinkedList<Number> values = new LinkedList<>();
public Metric(String displayName, String description) {
this.displayName = displayName;
this.description = description;
}
public Metric(String displayName, String description, String latexFormula) {
this(displayName, description);
this.latexFormula = latexFormula;
}
public abstract void calculateMetric();
public void updateMetric(Number newValue) {
addValue(newValue);
}
private void addValue(Number oldValue) {
values.add(oldValue);
}
public String getDisplayName() {
return displayName;
}
public String getDescription() {
return description;
}
public String getLatexFormula() {
return latexFormula;
}
public Number getValue() {
return values.isEmpty() ? null : values.getLast();
}
public LinkedList<Number> getValues() {
return values;
}
public Number getFirstValue() {
return values.isEmpty() ? null : values.getFirst();
}
public Number getPreviousValue() {
return values.size() > 1 ? values.get(values.size() - 2) : null;
}
private Double getChangeDifference(Number oldValue, Number newValue) {
if (oldValue != null && newValue != null) {
double oldDouble = oldValue.doubleValue();
double newDouble = newValue.doubleValue();
return newDouble - oldDouble;
}
return null;
}
private Double getChangePercentage(Number oldValue, Number newValue) {
if (oldValue != null && newValue != null) {
double oldDouble = oldValue.doubleValue();
double newDouble = newValue.doubleValue();
if (oldDouble > 0) {
return (newDouble - oldDouble) * 100.0 / oldDouble;
} else {
return 0.0;
}
}
return null;
}
public Double getLastChange(boolean absolute, boolean cumulative) {
if (absolute) {
return cumulative ? getChangeDifference(getFirstValue(), getValue()) : getChangeDifference(getPreviousValue(), getValue());
} else {
return cumulative ? getChangePercentage(getFirstValue(), getValue()) : getChangePercentage(getPreviousValue(), getValue());
}
}
}
package metrics;
public interface PrimitiveMetric {
}
package metrics;
public interface RatioMetric {
}
package metrics.impact;
import metrics.ImpactMetric;
import metrics.Metric;
import reasoning.ChimpReasoner;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.Set;
public class AddedInferenceImpact extends Metric implements ImpactMetric {
private final Logger log = LoggerFactory.getLogger(AddedInferenceImpact.class);
private final ChimpReasoner customReasoner;
public AddedInferenceImpact(ChimpReasoner customReasoner) {
super("Added Inference Impact",
"This measure signals the amount of new axioms in the materialization in comparison " +
"to the shared of amount of axioms in the materialization, when comparing " +
"the materialization now and to the one calculated as the reasoner was started. " +
"If this number is one, it means that the amount " +
"of new axioms in the materialization is the same as the amount that has " +
"not changed. Therefore, half of the materialization is new compared to the old version.",
"impact_{add,m} = \\frac{\\Delta_i^+}{m_{i,i+1}}");
this.customReasoner = customReasoner;
}
@Override
public void calculateMetric() {
Set<OWLAxiom> currentMaterialization = customReasoner.getCurrentMaterialization();
Set<OWLAxiom> firstMaterialization = customReasoner.getFirstMaterialization();
if (currentMaterialization != null) {
updateMetric(calculateMetricWithMaterializations(firstMaterialization, currentMaterialization));
} else {
log.debug(getDisplayName() + " could not be calculated because there were no previous materializations");
}
}
@Override
public double calculateMetricWithMaterializations(Set<OWLAxiom> oldMaterialization, Set<OWLAxiom> newMaterialization) {
Set<OWLAxiom> materializedAdditions = new HashSet<>(newMaterialization);
materializedAdditions.removeAll(oldMaterialization);
Set<OWLAxiom> intersection = new HashSet<>(newMaterialization);
intersection.retainAll(oldMaterialization);
double sizeOfMaterializedAdditions = materializedAdditions.size();
double sizeOfIntersection = intersection.size();
return sizeOfIntersection > 0 ? sizeOfMaterializedAdditions / sizeOfIntersection : 0;
}
}
package metrics.impact;
import metrics.ImpactMetric;
import metrics.Metric;
import reasoning.ChimpReasoner;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.Set;
public class AddedInferenceNewRatio extends Metric implements ImpactMetric {
private final Logger log = LoggerFactory.getLogger(AddedInferenceNewRatio.class);
private final ChimpReasoner customReasoner;
public AddedInferenceNewRatio(ChimpReasoner customReasoner) {
super("Added Inference New Ratio",
"This measure signals the amount of new axioms in the materialization " +
"in comparison to the size of the new materialization, when " +
"comparing the materialization now and to the one calculated " +
"as the reasoner was started. If this number is one, it means " +
"that the materialization is completely new. The closer this " +
"number is to 0, the less has been added in the new materialization.",
"impact_{add,m_{i+1}} = \\frac{\\Delta_i^+}{m_{i+1}}");
this.customReasoner = customReasoner;
}
@Override
public void calculateMetric() {
Set<OWLAxiom> currentMaterialization = customReasoner.getCurrentMaterialization();
Set<OWLAxiom> firstMaterialization = customReasoner.getFirstMaterialization();
if (currentMaterialization != null) {
updateMetric(calculateMetricWithMaterializations(firstMaterialization, currentMaterialization));
} else {
log.debug(getDisplayName() + " could not be calculated because there were no previous materializations");
}
}
@Override
public double calculateMetricWithMaterializations(Set<OWLAxiom> oldMaterialization, Set<OWLAxiom> newMaterialization) {
Set<OWLAxiom> MaterializedAdditions = new HashSet<>(newMaterialization);
MaterializedAdditions.removeAll(oldMaterialization);
double sizeOfMaterializedAdditions = MaterializedAdditions.size();
double sizeOfMaterialization = newMaterialization.size();
return sizeOfMaterialization > 0 ? sizeOfMaterializedAdditions / sizeOfMaterialization : 0;
}
}
package metrics.impact;
import metrics.ImpactMetric;
import metrics.Metric;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reasoning.ChimpReasoner;
import java.util.HashSet;
import java.util.Set;
public class AddedInferenceOldRatio extends Metric implements ImpactMetric {
private final Logger log = LoggerFactory.getLogger(AddedInferenceOldRatio.class);
private final ChimpReasoner reasoner;
public AddedInferenceOldRatio(ChimpReasoner reasoner) {
super("Added Inference Old Ratio",
"This measure signals the amount of new axioms in the materialization " +
"in comparison to the size of the old materialization, when " +
"comparing the materialization now and to the one calculated " +
"as the reasoner was started. If this number is larger than 1, " +
"it means that the amount of new axioms in the materialization " +
"exceed the size of the old materialization.",
"impact_{add,m_i} = \\frac{\\Delta_i^+}{m_i}");
this.reasoner = reasoner;
}
@Override
public void calculateMetric() {
Set<OWLAxiom> currentMaterialization = reasoner.getCurrentMaterialization();
Set<OWLAxiom> firstMaterialization = reasoner.getFirstMaterialization();
if (currentMaterialization != null) {
updateMetric(calculateMetricWithMaterializations(firstMaterialization, currentMaterialization));
} else {
log.debug(getDisplayName() + " could not be calculated because there were no previous materializations");
}
}
@Override
public double calculateMetricWithMaterializations(Set<OWLAxiom> oldMaterialization, Set<OWLAxiom> newMaterialization) {
Set<OWLAxiom> materializedAdditions = new HashSet<>(newMaterialization);
materializedAdditions.removeAll(oldMaterialization);
double sizeOfMaterializedAdditions = materializedAdditions.size();
double sizeOfMaterialization = oldMaterialization.size();
return sizeOfMaterialization > 0 ? sizeOfMaterializedAdditions / sizeOfMaterialization : 0;
}
}
package metrics.impact;
import metrics.ImpactMetric;
import metrics.Metric;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLOntology;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reasoning.ChimpReasoner;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
public class ChangeImpact extends Metric implements ImpactMetric {
private final Logger log = LoggerFactory.getLogger(ChangeImpact.class);
private final ChimpReasoner customReasoner;
public ChangeImpact(ChimpReasoner customReasoner) {
super("Change Impact",
"This measure signals the amount of changed axioms (added and removed) in the materialization " +
"in comparison to the number of changes in the ontology.",
"\\gamma = \\frac{\\Delta_i^+ + \\Delta_i^-}{\\delta_i^+ + \\delta_i^-}");
this.customReasoner = customReasoner;
}
@Override
public void calculateMetric() {
Set<OWLAxiom> currentMaterialization = customReasoner.getCurrentMaterialization();
Set<OWLAxiom> firstMaterialization = customReasoner.getFirstMaterialization();
Set<OWLAxiom> firstOntology = customReasoner.getFirstOntology();
Set<OWLOntology> activeOntologies = customReasoner.getCurrentOntology();
Set<OWLAxiom> currentOntology = new TreeSet<>();
for (OWLOntology ont : activeOntologies){
currentOntology.addAll(ont.getAxioms());
}
if (currentMaterialization != null) {
updateMetric(calculateMetricWithMaterializations(firstMaterialization, currentMaterialization,firstOntology,currentOntology));
} else {
log.debug(getDisplayName() + " could not be calculated because there were no previous materializations");
}
}
public double calculateMetricWithMaterializations(Set<OWLAxiom> oldMaterialization, Set<OWLAxiom> newMaterialization,
Set<OWLAxiom> oldOntology, Set<OWLAxiom> newOntology) {
Set<OWLAxiom> materializedAdditions = new HashSet<>(newMaterialization);
materializedAdditions.removeAll(oldMaterialization);
Set<OWLAxiom> materializedRemovals = new HashSet<>(oldMaterialization);
materializedRemovals.removeAll(newMaterialization);
Set<OWLAxiom> ontologyAdditions = new HashSet<>(newOntology);
ontologyAdditions.removeAll(oldOntology);
Set<OWLAxiom> ontologyRemovals = new HashSet<>(oldOntology);
ontologyRemovals.removeAll(newOntology);
double sizeOfMaterializedChanges = materializedAdditions.size() + materializedRemovals.size();
double sizeOfOntologyChanges = ontologyAdditions.size() + ontologyRemovals.size();
return sizeOfOntologyChanges > 0 ? sizeOfMaterializedChanges / sizeOfOntologyChanges : 0;
}
@Override
public double calculateMetricWithMaterializations(Set<OWLAxiom> oldMaterialization, Set<OWLAxiom> newMaterialization) {
return 0;
}
}
package metrics.impact;
import metrics.ImpactMetric;
import metrics.Metric;
import reasoning.ChimpReasoner;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.Set;
public class ChangeMaxImpact extends Metric implements ImpactMetric {
private final Logger log = LoggerFactory.getLogger(ChangeMaxImpact.class);
private final ChimpReasoner customReasoner;
public ChangeMaxImpact(ChimpReasoner customReasoner) {
super("Change Max Impact",
"This measure signals the amount of changed axioms (removed and added) " +
"in the materialization in comparison to the entire materialization. " +
"Here the maximum is taken, meaning that the bigger materialization " +
"is chosen between the old and the new one.",
"impact_{D,a} = \\frac{\\Delta_i^+ + \\Delta_i^-}{max(m_i,m_{i+1})}");
this.customReasoner = customReasoner;
}
@Override
public void calculateMetric() {
Set<OWLAxiom> currentMaterialization = customReasoner.getCurrentMaterialization();
Set<OWLAxiom> firstMaterialization = customReasoner.getFirstMaterialization();
if (currentMaterialization != null) {
updateMetric(calculateMetricWithMaterializations(firstMaterialization, currentMaterialization));
} else {
log.debug(getDisplayName() + " could not be calculated because there were no previous materializations");
}
}
@Override
public double calculateMetricWithMaterializations(Set<OWLAxiom> oldMaterialization, Set<OWLAxiom> newMaterialization) {
Set<OWLAxiom> materializedAdditions = new HashSet<>(newMaterialization);
materializedAdditions.removeAll(oldMaterialization);
Set<OWLAxiom> materializedRemovals = new HashSet<>(oldMaterialization);
materializedRemovals.removeAll(newMaterialization);
double sizeOfMaterializedChanges = materializedAdditions.size() + materializedRemovals.size();
double maxOfMaterializations = Math.max(oldMaterialization.size(), newMaterialization.size());
return maxOfMaterializations > 0 ? sizeOfMaterializedChanges / maxOfMaterializations : 0;
}
}
package metrics.impact;
import metrics.ImpactMetric;
import metrics.Metric;
import org.semanticweb.owlapi.model.AxiomType;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLOntology;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reasoning.ChimpReasoner;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
public class ChangeNoiseImpact extends Metric implements ImpactMetric {
private final Logger log = LoggerFactory.getLogger(ChangeNoiseImpact.class);
private final ChimpReasoner customReasoner;