From c2cd4e3fb231f5ed87a07171ee70a16d767ddeec Mon Sep 17 00:00:00 2001 From: Berack96 Date: Thu, 4 Jan 2024 23:37:46 +0100 Subject: [PATCH] GUI - renamed LW to the correct name - copied two nets as resources - removed unnecessary code in NetworkNode - Created MainGUI - changed some code in SmileLib --- src/main/java/net/berack/upo/ai/Main.java | 38 ----- src/main/java/net/berack/upo/ai/MainGUI.java | 92 ++++++++++++ src/main/java/net/berack/upo/ai/MyPanel.java | 20 +++ .../upo/ai/decision/ConsoleInterface.java | 5 - .../berack/upo/ai/decision/PrototypeGUI.java | 20 +++ .../berack/upo/ai/decision/VehicleGUI.java | 19 +++ .../berack/upo/ai/problem1/Puzzle8GUI.java | 73 ++++----- .../net/berack/upo/ai/problem2/TrisGUI.java | 80 ++++------ ...eighting.java => LikelihoodWeighting.java} | 26 +++- .../ai/problem3/LikelihoodWeightingGUI.java | 141 ++++++++++++++++++ .../berack/upo/ai/problem3/NetworkNode.java | 17 ++- .../upo/ai/problem3/OutcomeChartGUI.java | 79 ++++++++++ .../net/berack/upo/ai/problem3/SmileLib.java | 45 +++--- src/main/resources/Prototipo.xdsl | 43 ++++-- src/main/resources/Veicolo.xdsl | 63 ++++++-- src/main/resources/lw/Malaria.xdsl | 56 +++++++ src/main/resources/lw/WetGrass.xdsl | 65 ++++++++ .../net/berack/upo/ai/problem3/LWTest.java | 4 +- 18 files changed, 694 insertions(+), 192 deletions(-) delete mode 100644 src/main/java/net/berack/upo/ai/Main.java create mode 100644 src/main/java/net/berack/upo/ai/MainGUI.java create mode 100644 src/main/java/net/berack/upo/ai/MyPanel.java delete mode 100644 src/main/java/net/berack/upo/ai/decision/ConsoleInterface.java create mode 100644 src/main/java/net/berack/upo/ai/decision/PrototypeGUI.java create mode 100644 src/main/java/net/berack/upo/ai/decision/VehicleGUI.java rename src/main/java/net/berack/upo/ai/problem3/{LikelyhoodWeighting.java => LikelihoodWeighting.java} (72%) create mode 100644 src/main/java/net/berack/upo/ai/problem3/LikelihoodWeightingGUI.java create mode 100644 src/main/java/net/berack/upo/ai/problem3/OutcomeChartGUI.java create mode 100644 src/main/resources/lw/Malaria.xdsl create mode 100644 src/main/resources/lw/WetGrass.xdsl diff --git a/src/main/java/net/berack/upo/ai/Main.java b/src/main/java/net/berack/upo/ai/Main.java deleted file mode 100644 index b238aa2..0000000 --- a/src/main/java/net/berack/upo/ai/Main.java +++ /dev/null @@ -1,38 +0,0 @@ -package net.berack.upo.ai; - -import java.util.Scanner; -import java.util.function.Function; - -import net.berack.upo.ai.problem1.Puzzle8GUI; -import net.berack.upo.ai.problem2.TrisGUI; - -public class Main { - - public static void main(String[] args) { - var value = read("What do you want to play?\n1. Puzzle8\n2. Tris\n", new Scanner(System.in), num -> num > 0 && num < 2); - var window = switch (value) { - case 1 -> new Puzzle8GUI(); - case 2 -> new TrisGUI(); - default -> null; - }; - - if(window != null) { - window.toFront(); - window.requestFocus(); - } - } - - private static int read(String out, Scanner in, Function control) { - var ret = 0; - - do { - try { - System.out.print(out); - var str = in.nextLine(); - ret = Integer.parseInt(str); - } catch (NumberFormatException ignore) {} - } while(!control.apply(ret)); - - return ret; - } -} \ No newline at end of file diff --git a/src/main/java/net/berack/upo/ai/MainGUI.java b/src/main/java/net/berack/upo/ai/MainGUI.java new file mode 100644 index 0000000..bc17a0f --- /dev/null +++ b/src/main/java/net/berack/upo/ai/MainGUI.java @@ -0,0 +1,92 @@ +package net.berack.upo.ai; + +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JSeparator; + +import net.berack.upo.ai.decision.PrototypeGUI; +import net.berack.upo.ai.decision.VehicleGUI; +import net.berack.upo.ai.problem1.Puzzle8GUI; +import net.berack.upo.ai.problem2.TrisGUI; +import net.berack.upo.ai.problem3.LikelihoodWeightingGUI; + +/** + * Classe che rappresenta il main di tutto il progetto + * In essa si può navigare in tutti gli esercizi e testarli + * @author Berack + */ +public class MainGUI extends JFrame { + + public final Puzzle8GUI Puzzle8GUI = new Puzzle8GUI(); + public final TrisGUI TrisGUI = new TrisGUI(); + public final LikelihoodWeightingGUI LikelihoodWeightingGUI = new LikelihoodWeightingGUI(); + public final PrototypeGUI PrototypeGUI = new PrototypeGUI(); + public final VehicleGUI VehicleGUI = new VehicleGUI(); + + public static void main(String[] args) { + new MainGUI(); + } + + private final JMenuBar menuBar = new JMenuBar(); + + /** + * Crea una finestra con nulla da mostrare, ma si può visualizzare uno degli esercizi tramite + * la barre dei menù che permette di cambiare da un esercizio all'altro + */ + private MainGUI() { + super("Progetto per AI"); + this.buildMenu(); + this.setJMenuBar(menuBar); + + this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + this.setSize(400, 400); + this.setResizable(false); + this.setLocationRelativeTo(null); + this.setVisible(true); + } + + /** + * Crea la barra dei menu aggiungendo tutti i menù passati in input + * @param menus una lista di menù da aggiungere + */ + private void buildMenu(JMenu...menus) { + menuBar.removeAll(); + var menu = new JMenu("View"); + + var puzzle = new JMenuItem("Puzzle8 Game"); + puzzle.addActionListener(action -> this.setPanel(Puzzle8GUI)); + var tris = new JMenuItem("Tris Game"); + tris.addActionListener(action -> this.setPanel(TrisGUI)); + var lw = new JMenuItem("Likelihood Weighting"); + lw.addActionListener(action -> this.setPanel(LikelihoodWeightingGUI)); + var prototype = new JMenuItem("Prototype net"); + prototype.addActionListener(action -> this.setPanel(PrototypeGUI)); + var vehicle = new JMenuItem("Vehicle net"); + vehicle.addActionListener(action -> this.setPanel(VehicleGUI)); + + menu.add(puzzle); + menu.add(tris); + menu.add(lw); + menu.add(new JSeparator()); + menu.add(prototype); + menu.add(vehicle); + + menuBar.add(menu); + for(var m : menus) menuBar.add(m); + } + + /** + * Cambia il pannello principale con quello passato in input + * @param panel il pannello da mostrare + */ + private void setPanel(MyPanel panel) { + this.setContentPane(panel); + this.buildMenu(panel.getMenu()); + this.pack(); + this.invalidate(); + this.validate(); + this.repaint(); + } +} diff --git a/src/main/java/net/berack/upo/ai/MyPanel.java b/src/main/java/net/berack/upo/ai/MyPanel.java new file mode 100644 index 0000000..e2326b3 --- /dev/null +++ b/src/main/java/net/berack/upo/ai/MyPanel.java @@ -0,0 +1,20 @@ +package net.berack.upo.ai; + +import javax.swing.JMenu; +import javax.swing.JPanel; + +/** + * Classe utilizzata per far si che tutti i frame della finestra abbiano lo stesso metodo + * per la generazione dei menu. + * @author Berack + */ +public abstract class MyPanel extends JPanel { + + /** + * Crea un menu da aggiungere alla lista, in modo che appaia solamente quando + * la finestra venga utilizzata. + * Questo metodo viene usato solo dalla finestra MainGUI + * @return il menu contestuale da aggiungere + */ + abstract public JMenu getMenu(); +} diff --git a/src/main/java/net/berack/upo/ai/decision/ConsoleInterface.java b/src/main/java/net/berack/upo/ai/decision/ConsoleInterface.java deleted file mode 100644 index 47799f0..0000000 --- a/src/main/java/net/berack/upo/ai/decision/ConsoleInterface.java +++ /dev/null @@ -1,5 +0,0 @@ -package net.berack.upo.ai.decision; - -public class ConsoleInterface { - -} diff --git a/src/main/java/net/berack/upo/ai/decision/PrototypeGUI.java b/src/main/java/net/berack/upo/ai/decision/PrototypeGUI.java new file mode 100644 index 0000000..25a2609 --- /dev/null +++ b/src/main/java/net/berack/upo/ai/decision/PrototypeGUI.java @@ -0,0 +1,20 @@ +package net.berack.upo.ai.decision; + +import javax.swing.JMenu; + +import net.berack.upo.ai.MyPanel; + +/** + * Classe che mostra le decisioni possibili, insieme ai guadagni + * per la rete Prototipo.xdsl + * @author Berack + */ +public class PrototypeGUI extends MyPanel { + + @Override + public JMenu getMenu() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getMenu'"); + } + +} diff --git a/src/main/java/net/berack/upo/ai/decision/VehicleGUI.java b/src/main/java/net/berack/upo/ai/decision/VehicleGUI.java new file mode 100644 index 0000000..e878118 --- /dev/null +++ b/src/main/java/net/berack/upo/ai/decision/VehicleGUI.java @@ -0,0 +1,19 @@ +package net.berack.upo.ai.decision; + +import javax.swing.JMenu; + +import net.berack.upo.ai.MyPanel; + +/** + * Classe che mostra le decisioni possibili, insieme ai guadagni + * per la rete Veicolo.xdsl + */ +public class VehicleGUI extends MyPanel { + + @Override + public JMenu getMenu() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getMenu'"); + } + +} diff --git a/src/main/java/net/berack/upo/ai/problem1/Puzzle8GUI.java b/src/main/java/net/berack/upo/ai/problem1/Puzzle8GUI.java index b0e145e..aae3017 100644 --- a/src/main/java/net/berack/upo/ai/problem1/Puzzle8GUI.java +++ b/src/main/java/net/berack/upo/ai/problem1/Puzzle8GUI.java @@ -1,31 +1,25 @@ package net.berack.upo.ai.problem1; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JMenu; -import javax.swing.JMenuBar; -import javax.swing.JMenuItem; -import javax.swing.JPanel; - -import net.berack.upo.ai.problem1.Puzzle8.Move; - import java.awt.Color; import java.awt.GridLayout; import java.util.ArrayList; import java.util.List; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JMenu; +import javax.swing.JMenuItem; + +import net.berack.upo.ai.MyPanel; +import net.berack.upo.ai.problem1.Puzzle8.Move; + /** * Classe che permette di visualizzare graficamente il gioco Puzzle8 * In questa classe si trova un main che crea una istanza di questa finestra * * @author Berack96 */ -public class Puzzle8GUI extends JFrame { - - public static void main(String[] args) { - new Puzzle8GUI(); - } +public class Puzzle8GUI extends MyPanel { /** * Carica staticamente le immagini necessarie per giocare al gioco @@ -50,49 +44,20 @@ public class Puzzle8GUI extends JFrame { * Come default viene creato il puzzle "GOAL" ovvero non mescolato. */ public Puzzle8GUI() { - super("Puzzle 8 game"); + super(); var grid = new GridLayout(Puzzle8.LENGTH, Puzzle8.LENGTH); grid.setHgap(6); grid.setVgap(grid.getHgap()); - var panel = new JPanel(grid); + this.setLayout(grid); for(var i = 0; i < Puzzle8.LENGTH; i++) { for(var j = 0; j < Puzzle8.LENGTH; j++) { var comp = new MyComponent(Puzzle8.LENGTH, j, i); - panel.add(comp); + this.add(comp); this.buttons[j][i] = comp; } } - - this.add(panel); - this.attachMenu(); - - this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - this.pack(); - this.setResizable(false); - this.setLocationRelativeTo(null); - this.setVisible(true); - } - - /** - * Metodo utile per non mettere tutto nel costruttore. - * Qui viene creata la menubar - */ - private void attachMenu() { - var menuBar = new JMenuBar(); - - var menu1 = new JMenu("Game"); - var item1 = new JMenuItem("Shuffle"); - item1.addActionListener(action -> this.shuffleGame()); - menu1.add(item1); - - var item2 = new JMenuItem("Show solution"); - item2.addActionListener(action -> this.solveGame()); - menu1.add(item2); - - menuBar.add(menu1); - this.setJMenuBar(menuBar); } /** @@ -194,4 +159,18 @@ public class Puzzle8GUI extends JFrame { }); } } + + @Override + public JMenu getMenu() { + var menu = new JMenu("Game"); + var item1 = new JMenuItem("Shuffle"); + item1.addActionListener(action -> this.shuffleGame()); + menu.add(item1); + + var item2 = new JMenuItem("Show solution"); + item2.addActionListener(action -> this.solveGame()); + menu.add(item2); + + return menu; + } } diff --git a/src/main/java/net/berack/upo/ai/problem2/TrisGUI.java b/src/main/java/net/berack/upo/ai/problem2/TrisGUI.java index 57ed1b3..fb7ce32 100644 --- a/src/main/java/net/berack/upo/ai/problem2/TrisGUI.java +++ b/src/main/java/net/berack/upo/ai/problem2/TrisGUI.java @@ -1,18 +1,17 @@ package net.berack.upo.ai.problem2; +import java.awt.Color; +import java.awt.GridLayout; + import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; -import javax.swing.JFrame; import javax.swing.JMenu; -import javax.swing.JMenuBar; import javax.swing.JMenuItem; -import javax.swing.JPanel; import javax.swing.JSeparator; -import java.awt.Color; -import java.awt.GridLayout; +import net.berack.upo.ai.MyPanel; /** * Classe che permette di visualizzare graficamente il gioco Tris @@ -20,11 +19,7 @@ import java.awt.GridLayout; * * @author Berack96 */ -public class TrisGUI extends JFrame { - - public static void main(String[] args) { - new TrisGUI(); - } +public class TrisGUI extends MyPanel { /** * Caricamento statico delle immagini @@ -57,54 +52,17 @@ public class TrisGUI extends JFrame { * Come default viene abilitata la AI come secondo giocatore. */ public TrisGUI() { - super("Tris"); + super(); var grid = new GridLayout(Tris.LENGTH, Tris.LENGTH); - var panel = new JPanel(grid); + this.setLayout(grid); for(var i = 0; i < Tris.LENGTH; i++) { for(var j = 0; j < Tris.LENGTH; j++) { var comp = new MyComponent(Tris.LENGTH, j, i); - panel.add(comp); + this.add(comp); this.buttons[j][i] = comp; } } - - this.add(panel); - this.attachMenu(); - - this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - this.pack(); - this.setResizable(false); - this.setLocationRelativeTo(null); - this.setVisible(true); - } - - /** - * Metodo utile per non mettere tutto nel costruttore. - * Qui viene creata la menubar - */ - private void attachMenu() { - var menuBar = new JMenuBar(); - - var menu1 = new JMenu("Game"); - var item1 = new JMenuItem("Reset"); - item1.addActionListener(action -> this.reset()); - menu1.add(item1); - - var separator = new JSeparator(); - menu1.add(separator); - - var item2 = new JCheckBoxMenuItem("AI Enabled"); - item2.setSelected(this.ai != null); - item2.addChangeListener(action -> this.ai = item2.getState()? new TrisAi(this.tris):null); - menu1.add(item2); - - this.aiFirst = new JCheckBoxMenuItem("AI First"); - this.aiFirst.setSelected(false); - menu1.add(this.aiFirst); - - menuBar.add(menu1); - this.setJMenuBar(menuBar); } /** @@ -175,4 +133,26 @@ public class TrisGUI extends JFrame { }); } } + + @Override + public JMenu getMenu() { + var menu = new JMenu("Game"); + var item1 = new JMenuItem("Reset"); + item1.addActionListener(action -> this.reset()); + menu.add(item1); + + var separator = new JSeparator(); + menu.add(separator); + + var item2 = new JCheckBoxMenuItem("AI Enabled"); + item2.setSelected(this.ai != null); + item2.addChangeListener(action -> this.ai = item2.getState()? new TrisAi(this.tris):null); + menu.add(item2); + + this.aiFirst = new JCheckBoxMenuItem("AI First"); + this.aiFirst.setSelected(false); + menu.add(this.aiFirst); + + return menu; + } } diff --git a/src/main/java/net/berack/upo/ai/problem3/LikelyhoodWeighting.java b/src/main/java/net/berack/upo/ai/problem3/LikelihoodWeighting.java similarity index 72% rename from src/main/java/net/berack/upo/ai/problem3/LikelyhoodWeighting.java rename to src/main/java/net/berack/upo/ai/problem3/LikelihoodWeighting.java index 46eb113..91079ba 100644 --- a/src/main/java/net/berack/upo/ai/problem3/LikelyhoodWeighting.java +++ b/src/main/java/net/berack/upo/ai/problem3/LikelihoodWeighting.java @@ -1,16 +1,18 @@ package net.berack.upo.ai.problem3; import java.security.SecureRandom; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Objects; + import smile.Network; /** - * Calcolo dei valori tramite l'algoritmo del Likelyhood Weighting + * Calcolo dei valori tramite l'algoritmo del Likelihood Weighting * @author Berack */ -public class LikelyhoodWeighting { +public class LikelihoodWeighting { public final Network net; private final Map nodes = new HashMap<>(); @@ -19,14 +21,14 @@ public class LikelyhoodWeighting { * Inizializza un nuovo oggetto che calcolerà i valori per la rete inserita * @param net la rete a cui calcolare i valori */ - public LikelyhoodWeighting(Network net) { + public LikelihoodWeighting(Network net) { this.net = Objects.requireNonNull(net); } /** * Recupera i valori del nodo dopo averli calcolati * Nel caso in cui non si abbia ancora fatto {@link #updateNetwork(int)} allora restituirà - * una eccezione di tiop UnsupportedOperationException + * una eccezione di tipo UnsupportedOperationException * @param node il nodo da vedere * @return l'array di valori da restituire */ @@ -35,6 +37,17 @@ public class LikelyhoodWeighting { return nodes.get(node).values; } + /** + * Permette di recuperare tutti i nodi. + * Nel caso in cui non si abbia ancora fatto {@link #updateNetwork(int)} allora restituirà + * una eccezione di tipo UnsupportedOperationException + * @return Una collezione di tutti i nodi. + */ + public Collection getAllNodes() { + if(nodes.size() == 0) throw new UnsupportedOperationException("You should run first updateNetwork method"); + return this.nodes.values(); + } + /** * Calcola i valori possibili per la rete. * Per poterli vedere utilizzare il metodo {@link #getNodeValue(int)} @@ -74,4 +87,9 @@ public class LikelyhoodWeighting { node.values[i] /= sum; } } + + @Override + public String toString() { + return this.nodes.values().toString(); + } } diff --git a/src/main/java/net/berack/upo/ai/problem3/LikelihoodWeightingGUI.java b/src/main/java/net/berack/upo/ai/problem3/LikelihoodWeightingGUI.java new file mode 100644 index 0000000..f76141c --- /dev/null +++ b/src/main/java/net/berack/upo/ai/problem3/LikelihoodWeightingGUI.java @@ -0,0 +1,141 @@ +package net.berack.upo.ai.problem3; + +import java.awt.Dimension; +import java.awt.FileDialog; +import java.awt.Font; + +import javax.swing.GroupLayout; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JSeparator; + +import net.berack.upo.ai.MyPanel; + +/** + * Classe usata per far vedere il risultato di una run di lw su un network + * @author Berack + */ +public class LikelihoodWeightingGUI extends MyPanel { + + private LikelihoodWeighting lw = null; + + private final JPanel scroll = new JPanel(); + private final int totalRuns = 1000; + + /** + * Crea il pannello con gli elementi di default. + * Siccome non c'è nessun network, il pannello sarà vuoto finchè non si apriranno dei network + */ + public LikelihoodWeightingGUI() { + this.scroll.setPreferredSize(new Dimension(500, 400)); + this.add(this.scroll); + } + + /** + * Crea una finestra di dialog per la richiesta di un file. + * Il file richiesto è in forma .xdsl + */ + public void openFile() { + var parent = this.getParent(); + while(parent.getParent() != null) parent = parent.getParent(); + if(!(parent instanceof JFrame)) throw new IllegalArgumentException(parent.getClass().getName()); + + var dialog = new FileDialog((JFrame) parent, "Select net"); + dialog.setLocationRelativeTo(null); + dialog.setFile("*.xdsl"); + dialog.setMode(FileDialog.LOAD); + dialog.setVisible(true); + + if(dialog.getFile() != null) this.openFile(dialog.getDirectory() + dialog.getFile()); + } + + /** + * Carica il file indicato nella finestra, esegue l'algoritmo e mostra i risultati + * @param fileName il nome del file + */ + public void openFile(String fileName) { + + try { + var net = SmileLib.getNetworkFrom(fileName); + this.lw = new LikelihoodWeighting(net); + this.updateLW(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Esegue l'algoritmo sul network corrente e mostra i risultati + */ + private void updateLW() { + this.lw.updateNetwork(totalRuns); + + var nodes = this.lw.getAllNodes(); + var panel = new JPanel(); + var layout = new GroupLayout(panel); + + panel.setLayout(layout); + layout.setAutoCreateGaps(true); + + var gLabel = layout.createParallelGroup(); + var gBarch = layout.createParallelGroup(); + var vGroup = layout.createSequentialGroup(); + + for(var node : nodes) { + var label = new JLabel(node.name); + var barch = new OutcomeChartGUI(node, i -> { + if(node.evidence == i) node.net.clearEvidence(node.handle); + else node.net.setEvidence(node.handle, i); + this.updateLW(); + }); + + var font = label.getFont(); + label.setFont(new Font(font.getName(), font.getStyle(), font.getSize() + 4)); + + gLabel.addComponent(label); + gBarch.addComponent(barch); + vGroup.addGroup(layout.createParallelGroup() + .addComponent(label) + .addComponent(barch)); + } + + var hGroup = layout.createSequentialGroup(); + hGroup.addGroup(gLabel).addGroup(gBarch); + + layout.setVerticalGroup(vGroup); + layout.setHorizontalGroup(hGroup); + + this.scroll.removeAll(); + this.scroll.add(panel); + this.repaint(); + + this.invalidate(); + this.validate(); + this.repaint(); + } + + @Override + public JMenu getMenu() { + var menu = new JMenu("File"); + + var open = new JMenuItem("Open"); + open.addActionListener(action -> this.openFile()); + + var net1 = new JMenuItem("WetGrass net"); + net1.addActionListener(action -> this.openFile("lw/WetGrass.xdsl")); + + var net2 = new JMenuItem("Malaria net"); + net2.addActionListener(action -> this.openFile("lw/Malaria.xdsl")); + + + menu.add(open); + menu.add(new JSeparator()); + menu.add(net1); + menu.add(net2); + + return menu; + } +} diff --git a/src/main/java/net/berack/upo/ai/problem3/NetworkNode.java b/src/main/java/net/berack/upo/ai/problem3/NetworkNode.java index 59599a8..195747e 100644 --- a/src/main/java/net/berack/upo/ai/problem3/NetworkNode.java +++ b/src/main/java/net/berack/upo/ai/problem3/NetworkNode.java @@ -16,6 +16,7 @@ import smile.Network; public class NetworkNode { final int handle; + final String name; final String[] outcomes; final double[] definition; final int evidence; @@ -36,12 +37,16 @@ public class NetworkNode { NetworkNode(Network net, int handle, Map nodes) { this.handle = handle; this.type = net.getNodeType(handle); + this.name = net.getNodeId(handle); this.net = net; this.outcomes = net.getOutcomeIds(handle); this.values = new double[this.outcomes.length]; this.evidence = net.isEvidence(handle)? net.getEvidence(handle) : -1; - if(this.isEvidence()) this.values[this.evidence] = 1.0d; + if(this.isEvidence()) { + this.values[this.evidence] = 1.0d; + this.sample = this.evidence; + } var parentsHandle = net.getParents(handle); this.parents = new NetworkNode[parentsHandle.length]; @@ -111,11 +116,10 @@ public class NetworkNode { var tot = this.definition.length; for(var p : this.parents) { - var pIndex = p.isEvidence()? p.evidence : p.sample; - if(pIndex < 0) throw new IllegalArgumentException("Parent"); // in theory impossible since Topological sorted + if(p.sample < 0) throw new IllegalArgumentException("Parent"); // in theory impossible since Topological sorted tot /= p.outcomes.length; - init += tot * pIndex; + init += tot * p.sample; } return init; @@ -132,4 +136,9 @@ public class NetworkNode { return true; } + + @Override + public String toString() { + return this.net.getNodeId(this.handle) + "->" + Arrays.toString(this.values); + } } \ No newline at end of file diff --git a/src/main/java/net/berack/upo/ai/problem3/OutcomeChartGUI.java b/src/main/java/net/berack/upo/ai/problem3/OutcomeChartGUI.java new file mode 100644 index 0000000..83b1fdf --- /dev/null +++ b/src/main/java/net/berack/upo/ai/problem3/OutcomeChartGUI.java @@ -0,0 +1,79 @@ +package net.berack.upo.ai.problem3; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.GridLayout; +import java.awt.Label; +import java.util.function.Consumer; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.border.EmptyBorder; + +/** + * Classe che rappresenta gli outcome di un nodo di un network. + * I valori deli outcome vengono visualizzati con un grafico. + * @author Berack + */ +public class OutcomeChartGUI extends JPanel { + public static final Color[] COLORS = { + new Color(255,127,0), + new Color(0,127,255), + new Color(0,255,127), + new Color(255,0,127), + new Color(127,0,255), + new Color(127,255,0), + }; + + /** + * Crea il JPanel da visualizzare a partire da un NetworkNode appropriamente inizializzato. + * Quando verrà visualizzato, il nodo avrà il nome degli output e i suoi valori in % + * con una barra colorata per indicare la grandezza visivamente. + * + * @param node il nodo di cui si vogliono visualizzare gli outcome + * @param action una azione da fare nel caso in cui venga premuto su un outcome + */ + public OutcomeChartGUI(NetworkNode node, Consumer action) { + var labels = node.outcomes; + var values = node.values; + + if(labels.length != values.length) throw new IllegalArgumentException("Arrays length myst be equals!"); + this.setBorder(BorderFactory.createCompoundBorder(new EmptyBorder(1, 0, 0, 0), BorderFactory.createLineBorder(Color.GRAY))); + + var layout = new GridLayout(labels.length, 2); + this.setLayout(layout); + + for(var i = 0; i < labels.length; i++) { + var value = values[i] * 100; + + var lName = new JButton(labels[i]); + var lValue = new Label(String.format("% 4.2f%%", value)); + var barchart = new Label(); + var size = barchart.getPreferredSize(); + + final var index = i; + lName.setContentAreaFilled(false); + lName.setFocusable(false); + lName.addActionListener(a -> action.accept(index)); + if(node.evidence == i) lName.setForeground(Color.RED); + + size.width = (int) (value * 1.5); + barchart.setPreferredSize(size); + barchart.setBackground(COLORS[i % COLORS.length]); + + + var panel1 = new JPanel(); + panel1.setLayout(new GridLayout(1, 2)); + panel1.add(lName); + panel1.add(lValue); + + var panel2 = new JPanel(); + panel2.setLayout(new BorderLayout()); + panel2.add(barchart, BorderLayout.LINE_START); + + this.add(panel1); + this.add(panel2); + } + } +} diff --git a/src/main/java/net/berack/upo/ai/problem3/SmileLib.java b/src/main/java/net/berack/upo/ai/problem3/SmileLib.java index aa6f4f8..1587b7d 100644 --- a/src/main/java/net/berack/upo/ai/problem3/SmileLib.java +++ b/src/main/java/net/berack/upo/ai/problem3/SmileLib.java @@ -1,9 +1,11 @@ package net.berack.upo.ai.problem3; -import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; import java.util.List; + import smile.Network; /** @@ -18,18 +20,19 @@ import smile.Network; */ public class SmileLib { - public static final String RESOURCE_PATH; static { - var loader = SmileLib.class.getClassLoader(); - var wrongPath = loader.getResource("").getFile(); - var path = wrongPath.substring(1); try { - RESOURCE_PATH = URLDecoder.decode(path, "ASCII"); + var jsmile = "jsmile"; + var loader = SmileLib.class.getClassLoader(); + var resource = loader.getResource(jsmile); + var uri = resource.toURI(); + var path = Path.of(uri).toString(); + System.setProperty("jsmile.native.library", path); } catch (Exception e) { - throw new RuntimeException("Decodification of path failed!\n" + e.getMessage()); + e.printStackTrace(); + System.exit(0); } - System.setProperty("jsmile.native.library", RESOURCE_PATH + "jsmile"); new smile.License( "SMILE LICENSE 02a07eb5 5c5fa64a 2a276459 " + "THIS IS AN ACADEMIC LICENSE AND CAN BE USED " + @@ -60,8 +63,12 @@ public class SmileLib { public static Network getNetworkFrom(String file) { var net = new Network(); try { - net.readFile(RESOURCE_PATH + file); - } catch (smile.SMILEException e) { + var loader = SmileLib.class.getClassLoader(); + var in = loader.getResourceAsStream(file); + var str = new String(in.readAllBytes(), StandardCharsets.UTF_8); + + net.readString(str); + } catch (Exception e) { net.readFile(file); } @@ -78,15 +85,15 @@ public class SmileLib { * @return una lista ordinata di nodi */ public static List buildListFrom(Network net) { - var nodes = new HashMap(); - var list = new ArrayList(); + var nodes = new HashMap(); + var list = new ArrayList(); - for(var handle : net.getAllNodes()) { - var node = new NetworkNode(net, handle, nodes); - list.add(node); - nodes.put(handle, node); - } - - return list; + for(var handle : net.getAllNodes()) { + var node = new NetworkNode(net, handle, nodes); + list.add(node); + nodes.put(handle, node); } + + return list; + } } diff --git a/src/main/resources/Prototipo.xdsl b/src/main/resources/Prototipo.xdsl index 5314b7e..a646bfa 100644 --- a/src/main/resources/Prototipo.xdsl +++ b/src/main/resources/Prototipo.xdsl @@ -35,18 +35,27 @@ Domanda_Mercato Qualità_Prodotto - 0.9 0.09 0.01 0.5 0.35 0.15 0.1 0.2 0.7 0.01 0.09 0.9 + 0.99 0.008999999999999999 0.001 0.85 0.145 0.005 0.1 0.8 0.1 0.001 0.85 0.149 + + + + Migliorare_la_Qualià Effettuare_la_Ricerca + - Profitto - -2500 10000 50000 + Produzione Profitto + 0 10000 50000 0 0 0 Effettuare_la_Ricerca Domanda_Mercato - 0.9 0.09999999999999998 0.1 0.9 0.5 0.5 0.5 0.5 + 0.9 0.1 0.1 0.9 0.5 0.5 0.5 0.5 + + Produzione + -2500 0 + @@ -64,7 +73,7 @@ - 577 90 674 150 + 577 91 674 151 @@ -72,7 +81,7 @@ - 210 84 291 150 + 209 88 290 154 @@ -89,7 +98,7 @@ 40 104 118 140 - + Costo Prototipo @@ -115,13 +124,29 @@ 589 347 661 379 + + Produzione + + + + 221 350 287 376 + + Ricerca di Mercato - 385 90 472 150 - + 383 90 484 153 + + + + Costo Produzione + + + + 44 337 132 390 + diff --git a/src/main/resources/Veicolo.xdsl b/src/main/resources/Veicolo.xdsl index cb0e3b6..bd64e6e 100644 --- a/src/main/resources/Veicolo.xdsl +++ b/src/main/resources/Veicolo.xdsl @@ -11,12 +11,12 @@ - 0.9 0.1 + 0.5 0.5 - 1 0 + 0.5 0.5 @@ -31,7 +31,7 @@ Guasto Condizioni_Meteo Stato_Terreno 0 1 1 0 1 0 - 1 0 0 0 0 1 0.3 0.15 0.5499999999999999 0 0 1 0.6 0.3 0.1 0 0 1 0 0 1 + 1 0 0 0 0 1 0.3 0.15 0.5499999999999999 0 0 1 0.6 0.3 0.1 0 0 1 0.000299999999999967 0.0007 0.999 @@ -50,11 +50,22 @@ Posizione -100 100 -100 + + + + + Comando Posizione + 0.9 0.05 0.04999999999999998 0.9 0.05 0.05 0.05 0.9 0.05 0.9 0.05 0.05 0.04999999999999998 0.9 0.05 0.04999999999999993 0.05 0.9 0.05 0.9 0.05 0.05 0.05 0.9 0.05 0.05 0.9 + + + Posizione_Finale + -100 100 -100 + Posizione Comando - 0.9 0.1 0 0.9 0.1 0 0.1 0.9 0 0.9 0.05 0.05 0.04999999999999998 0.9 0.05 0.04999999999999993 0.05 0.9 0 0.9 0.1 0 0.1 0.9 0 0.1 0.9 + 0.9 0.05 0.04999999999999998 0.9 0.05 0.05 0.05 0.9 0.05 0.9 0.05 0.05 0.04999999999999998 0.9 0.05 0.04999999999999993 0.05 0.9 0.05 0.9 0.05 0.05 0.05 0.9 0.05 0.05 0.9 Condizioni_Meteo @@ -64,6 +75,14 @@ Stato_Terreno 0.8 0.2 0.7 0.3 + + Guasto + 1 0 1 0 0 1 + 0.1 0.9 0 1 0.5 0.5 0 1 1 0 0 1 0.001 0.999 + + + Comando + @@ -74,7 +93,7 @@ - 312 320 402 362 + 308 292 398 334 @@ -82,16 +101,16 @@ - 231 460 307 506 - + 232 386 308 432 + Sensore Posizione - 148 318 223 370 - + 148 285 223 337 + Accuratezza Sensore @@ -99,7 +118,7 @@ 142 179 228 229 - + Condizioni Meteo @@ -107,7 +126,7 @@ 140 47 231 103 - + Stato Terreno @@ -115,7 +134,7 @@ 314 180 392 228 - + Guasto @@ -123,14 +142,30 @@ 313 51 393 100 - + Utilità - 382 406 453 450 + 234 507 305 551 + + + + Posizione Finale + + + + 625 289 701 335 + + + + Utilità Finale + + + + 629 386 700 430 diff --git a/src/main/resources/lw/Malaria.xdsl b/src/main/resources/lw/Malaria.xdsl new file mode 100644 index 0000000..b2b55da --- /dev/null +++ b/src/main/resources/lw/Malaria.xdsl @@ -0,0 +1,56 @@ + + + + + + + + + 0.3333333333333333 0.3333333333333333 0.3333333333333334 + -1 + + + + + 0.5 0.5 + -1 + + + + + + Infliuenza Malaria + 0 1 2 0 1 + 0.99 0.01 0 0.4 0.55 0.04999999999999993 0 0 1 0.999 0.001 0 0 0 1 0.01000000000000001 0.09999999999999998 0.89 + -1 + + + + + + Infliuenza + + + + 338 118 434 178 + + + + Malaria + + + + 645 111 723 159 + + + + Febbre + + + + 524 310 605 360 + + + + + diff --git a/src/main/resources/lw/WetGrass.xdsl b/src/main/resources/lw/WetGrass.xdsl new file mode 100644 index 0000000..6088a05 --- /dev/null +++ b/src/main/resources/lw/WetGrass.xdsl @@ -0,0 +1,65 @@ + + + + + + + + 0.4 0.6 + + + + + Cloudy + 0.7000000000000001 0.3 0.4 0.6 + + + + + Cloudy + 0.1 0.9 0.5 0.5 + + + + + Sprinkler Rain + 0.99 0.01000000000000001 0.85 0.15 0.9 0.09999999999999998 0.1 0.9 + + + + + + Cloudy + + + + 189 22 271 83 + + + + Rain + + + + 337 157 412 213 + + + + Sprinkler + + + + 43 156 134 222 + + + + Wet Grass + + + + 186 277 284 348 + + + + + diff --git a/src/test/java/net/berack/upo/ai/problem3/LWTest.java b/src/test/java/net/berack/upo/ai/problem3/LWTest.java index 7192dea..20a8918 100644 --- a/src/test/java/net/berack/upo/ai/problem3/LWTest.java +++ b/src/test/java/net/berack/upo/ai/problem3/LWTest.java @@ -8,7 +8,7 @@ import smile.Network; public class LWTest { - // 3% difference max (it is a lot but is fair) + // 5% difference max (it is a lot but is fair) public static final float DELTA = 0.05f; @Test @@ -44,7 +44,7 @@ public class LWTest { } private void checkNodesValues(Network net) { - var lw = new LikelyhoodWeighting(net); + var lw = new LikelihoodWeighting(net); net.updateBeliefs(); lw.updateNetwork(1000);