From 3e7caa3ac0e0adc363fb70f87b2647a56d78558c Mon Sep 17 00:00:00 2001 From: leifeld Date: Mon, 28 Aug 2023 21:45:08 +0100 Subject: [PATCH] Nested backbone algorithm Algorithm seems to work, but results need to be processed and saved and a progress monitor needs to be used. --- dna/src/main/java/export/Exporter.java | 75 +++++++++++++++++++++ dna/src/main/java/gui/BackboneExporter.java | 4 ++ dna/src/main/java/gui/MenuBar.java | 3 +- 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/dna/src/main/java/export/Exporter.java b/dna/src/main/java/export/Exporter.java index d33cf24a..f6178b88 100644 --- a/dna/src/main/java/export/Exporter.java +++ b/dna/src/main/java/export/Exporter.java @@ -2976,4 +2976,79 @@ public void writeBackboneToFile(String filename) { Dna.logger.log(l); } } + + /* NEW BACKBONE ATTEMPT FROM HERE */ + + /** + * Compute penalized Euclidean spectral distance. + * + * @param eigenvalues1 Normalized eigenvalues of the full matrix. + * @param eigenvalues2 Normalized eigenvalues of the current or candidate matrix. + * @return Spectral loss. + */ + private double spectralLoss(double[] eigenvalues1, double[] eigenvalues2) { + double distance = 0.0; // Euclidean spectral distance + for (int i = 0; i < eigenvalues1.length; i++) { + distance = distance + Math.sqrt((eigenvalues1[i] - eigenvalues2[i]) * (eigenvalues1[i] - eigenvalues2[i])); + } + return distance; + } + + public void nestedBackbone() { + + // initial values before iterations start + this.originalStatements = this.filteredStatements; // to ensure not all isolates are included later + + // full set of concepts C + fullConcepts = this.extractLabels(this.filteredStatements, this.variable2, this.variable2Document); + + // full network matrix Y against which we compare in every iteration + fullMatrix = this.computeOneModeMatrix(this.filteredStatements, this.qualifierAggregation, this.startDateTime, this.stopDateTime); + //this.isolates = true; // include isolates in the iterations; will be adjusted to full matrix without isolates manually each time + + // compute normalised eigenvalues for the full matrix; no need to recompute every time as they do not change + eigenvaluesFull = computeNormalizedEigenvalues(fullMatrix.getMatrix()); + + ArrayList addedIteration = new ArrayList<>(); + ArrayList addedLoss = new ArrayList<>(); + ArrayList addedRedundantConcept = new ArrayList<>(); + ArrayList allConcepts = new ArrayList<>(); + for (int i = 0; i < fullConcepts.length; i++) { + allConcepts.add(fullConcepts[i]); + } + ArrayList backboneConcepts = new ArrayList<>(allConcepts); + ArrayList redundantConcepts = new ArrayList<>(); + double currentLoss = 999999.99; + while (backboneConcepts.size() > 0) { + double[] currentLosses = new double[backboneConcepts.size()]; + for (int i = 0; i < backboneConcepts.size(); i++) { + ArrayList candidate = new ArrayList<>(backboneConcepts); + candidate.remove(i); + final ArrayList finalCandidate = new ArrayList(candidate); // make it final, so it can be used in a stream + candidateStatementList = this.filteredStatements + .stream() + .filter(s -> finalCandidate.contains(((Entity) s.get(this.variable2)).getValue())) + .collect(Collectors.toCollection(ArrayList::new)); + candidateMatrix = this.computeOneModeMatrix(candidateStatementList, this.qualifierAggregation, this.startDateTime, this.stopDateTime); + candidateMatrix = this.reduceCandidateMatrix(candidateMatrix, fullMatrix.getRowNames()); // ensure it has the right dimensions by purging isolates relative to the full matrix + eigenvaluesCandidate = computeNormalizedEigenvalues(candidateMatrix.getMatrix()); // normalised eigenvalues for the candidate matrix + currentLosses[i] = spectralLoss(eigenvaluesFull, eigenvaluesCandidate); + } + double smallestLoss = 0.0; + if (backboneConcepts.size() > 0) { + smallestLoss = Arrays.stream(currentLosses).min().getAsDouble(); + } + for (int i = backboneConcepts.size() - 1; i >= 0; i--) { + if (currentLosses[i] == smallestLoss) { + addedIteration.add(addedIteration.size()); + addedRedundantConcept.add(backboneConcepts.get(i)); + addedLoss.add(smallestLoss); + System.out.println("Iteration: " + addedIteration.get(addedIteration.size() - 1) + ". Loss: " + addedLoss.get(addedLoss.size() - 1) + ". Concept: " + backboneConcepts.get(i) + "."); + redundantConcepts.add(backboneConcepts.get(i)); + backboneConcepts.remove(i); + } + } + } + // TODO: + } } \ No newline at end of file diff --git a/dna/src/main/java/gui/BackboneExporter.java b/dna/src/main/java/gui/BackboneExporter.java index 48db72e1..c0e8538a 100644 --- a/dna/src/main/java/gui/BackboneExporter.java +++ b/dna/src/main/java/gui/BackboneExporter.java @@ -1088,6 +1088,7 @@ public void run() { // step 3: simulated annealing if (proceed) { progressMonitor.setNote("Simulated annealing..."); + /* try (ProgressBar pb = new ProgressBar("Simulated annealing...", T)) { while (exporter.getCurrentT() <= T && !progressMonitor.isCanceled()) { // run up to upper bound of iterations T, provided by the user if (progressMonitor.isCanceled()) { @@ -1110,6 +1111,9 @@ public void run() { System.err.println("Canceled."); } } + */ + // TODO: use progress monitor for computing nested backbone results! + exporter.nestedBackbone(); } if (progressMonitor.isCanceled()) { JOptionPane.showMessageDialog(BackboneExporter.this, "Backbone finder was canceled."); diff --git a/dna/src/main/java/gui/MenuBar.java b/dna/src/main/java/gui/MenuBar.java index ad855dfc..0938f219 100644 --- a/dna/src/main/java/gui/MenuBar.java +++ b/dna/src/main/java/gui/MenuBar.java @@ -203,8 +203,7 @@ public MenuBar(ActionOpenDatabase actionOpenDatabase, // export menu: open backbone exporter JMenuItem backboneExporterItem = new JMenuItem(actionBackboneExporter); - // exportMenu.add(backboneExporterItem); - // TODO: add back in once finalized + exportMenu.add(backboneExporterItem); // settings menu JMenu settingsMenu = new JMenu("Settings");