From f9553ff3dd5efdb8ce4d27169b850a6b14089d6e Mon Sep 17 00:00:00 2001 From: tanvipotdar Date: Tue, 22 Jul 2014 17:06:11 +0100 Subject: [PATCH 1/7] Update ArcView.java --- pipe-gui/src/main/java/pipe/views/ArcView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pipe-gui/src/main/java/pipe/views/ArcView.java b/pipe-gui/src/main/java/pipe/views/ArcView.java index c9d4f82e..4c5d34e7 100644 --- a/pipe-gui/src/main/java/pipe/views/ArcView.java +++ b/pipe-gui/src/main/java/pipe/views/ArcView.java @@ -91,8 +91,8 @@ private void addIntermediatePoints() { for (ArcPoint arcPoint : model.getArcPoints()) { if (!arcPath.contains(arcPoint)) { arcPath.insertIntermediatePoint(arcPoint, index); + index++; } - index++; } } From 1426bcb8aef7e4212262f9eeda267eeaab40ad1d Mon Sep 17 00:00:00 2001 From: tanvipotdar Date: Wed, 23 Jul 2014 17:20:16 +0100 Subject: [PATCH 2/7] Update PlaceEditorPanel.java --- pipe-gui/src/main/java/pipe/gui/widgets/PlaceEditorPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pipe-gui/src/main/java/pipe/gui/widgets/PlaceEditorPanel.java b/pipe-gui/src/main/java/pipe/gui/widgets/PlaceEditorPanel.java index 0c07fc1f..7e08a3e6 100644 --- a/pipe-gui/src/main/java/pipe/gui/widgets/PlaceEditorPanel.java +++ b/pipe-gui/src/main/java/pipe/gui/widgets/PlaceEditorPanel.java @@ -484,7 +484,7 @@ private void cancelButtonHandler(java.awt.event.ActionEvent evt) { * @param evt */ private void capacitySpinnerStateChanged(javax.swing.event.ChangeEvent evt) { - Double capacity = (Double) capacitySpinner.getValue(); + int capacity = (int) capacitySpinner.getValue(); setCapacityVisible(capacity); } From 35494332bfb0a84f63c3c0d0ff2d449b6257a2a2 Mon Sep 17 00:00:00 2001 From: tanvipotdar Date: Wed, 23 Jul 2014 17:22:06 +0100 Subject: [PATCH 3/7] Update PlaceEditorPanel.java --- pipe-gui/src/main/java/pipe/gui/widgets/PlaceEditorPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pipe-gui/src/main/java/pipe/gui/widgets/PlaceEditorPanel.java b/pipe-gui/src/main/java/pipe/gui/widgets/PlaceEditorPanel.java index 7e08a3e6..f0b992fa 100644 --- a/pipe-gui/src/main/java/pipe/gui/widgets/PlaceEditorPanel.java +++ b/pipe-gui/src/main/java/pipe/gui/widgets/PlaceEditorPanel.java @@ -378,8 +378,8 @@ private boolean canSetCapacity() { * * @return the capacity spinner value */ - private Double getCapacitySpinnerValue() { - return (Double) capacitySpinner.getValue(); + private int getCapacitySpinnerValue() { + return (int) capacitySpinner.getValue(); } /** From 98a7c80b725a9795c582652b030f63fda91e990b Mon Sep 17 00:00:00 2001 From: tanvipotdar Date: Wed, 30 Jul 2014 21:31:52 +0100 Subject: [PATCH 4/7] Update ArcWeightEditorPanel.java --- .../src/main/java/pipe/gui/widgets/ArcWeightEditorPanel.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pipe-gui/src/main/java/pipe/gui/widgets/ArcWeightEditorPanel.java b/pipe-gui/src/main/java/pipe/gui/widgets/ArcWeightEditorPanel.java index 0be820a3..7376d0f9 100644 --- a/pipe-gui/src/main/java/pipe/gui/widgets/ArcWeightEditorPanel.java +++ b/pipe-gui/src/main/java/pipe/gui/widgets/ArcWeightEditorPanel.java @@ -231,13 +231,12 @@ private void nameTextFieldFocusLost(java.awt.event.FocusEvent evt) { public void createEditorWindow(String token) { Window window = SwingUtilities.getWindowAncestor(rootPane); - EscapableDialog guiDialog = new EscapableDialog(window, "PIPE2", true); + EscapableDialog guiDialog = new EscapableDialog(window, "PIPE5", true); ArcFunctionEditor feditor = new ArcFunctionEditor(this, guiDialog, petriNetController.getPetriNet(), arcController, token); guiDialog.add(feditor); guiDialog.setSize(270, 230); guiDialog.setVisible(true); - guiDialog.dispose(); } public void setWeight(String func, String id) { From 32d30016484a62ccfaeb62d0584072cfd833d025 Mon Sep 17 00:00:00 2001 From: tanvipotdar Date: Sat, 2 Aug 2014 19:25:46 +0100 Subject: [PATCH 5/7] Enable capacity spinner in the Place Editor Changed double to int on lines 381, 382 and 487 --- pipe-gui/src/main/java/pipe/gui/widgets/PlaceEditorPanel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/pipe-gui/src/main/java/pipe/gui/widgets/PlaceEditorPanel.java b/pipe-gui/src/main/java/pipe/gui/widgets/PlaceEditorPanel.java index f0b992fa..0b9acb67 100644 --- a/pipe-gui/src/main/java/pipe/gui/widgets/PlaceEditorPanel.java +++ b/pipe-gui/src/main/java/pipe/gui/widgets/PlaceEditorPanel.java @@ -484,6 +484,7 @@ private void cancelButtonHandler(java.awt.event.ActionEvent evt) { * @param evt */ private void capacitySpinnerStateChanged(javax.swing.event.ChangeEvent evt) { + int capacity = (int) capacitySpinner.getValue(); setCapacityVisible(capacity); } From 59446dcad9d7701a14b19c79e57fc0eebb2e6fa5 Mon Sep 17 00:00:00 2001 From: tanvipotdar Date: Sun, 3 Aug 2014 00:30:43 +0100 Subject: [PATCH 6/7] Implemented the algorithm for splitting a SPN into building blocks. Added an RCAT module which currently only splits SPNs and informs if RCAT can be run. --- .../pipe/gui/plugin/concrete/RCATModule.java | 38 ++++ .../java/pipe/gui/rcat/BuildingBlock.java | 40 ++++ .../pipe/gui/rcat/BuildingBlockCreator.java | 140 +++++++++++++ .../main/java/pipe/gui/widget/RCATForm.form | 175 ++++++++++++++++ .../main/java/pipe/gui/widget/RCATForm.java | 190 ++++++++++++++++++ 5 files changed, 583 insertions(+) create mode 100644 pipe-gui/src/main/java/pipe/gui/plugin/concrete/RCATModule.java create mode 100644 pipe-module-gui/src/main/java/pipe/gui/rcat/BuildingBlock.java create mode 100644 pipe-module-gui/src/main/java/pipe/gui/rcat/BuildingBlockCreator.java create mode 100644 pipe-module-gui/src/main/java/pipe/gui/widget/RCATForm.form create mode 100644 pipe-module-gui/src/main/java/pipe/gui/widget/RCATForm.java diff --git a/pipe-gui/src/main/java/pipe/gui/plugin/concrete/RCATModule.java b/pipe-gui/src/main/java/pipe/gui/plugin/concrete/RCATModule.java new file mode 100644 index 00000000..68987f6b --- /dev/null +++ b/pipe-gui/src/main/java/pipe/gui/plugin/concrete/RCATModule.java @@ -0,0 +1,38 @@ +package pipe.gui.plugin.concrete; + +import pipe.gui.widget.RCATForm; +import pipe.gui.plugin.GuiModule; +import uk.ac.imperial.pipe.models.petrinet.PetriNet; + +import javax.swing.*; +import java.awt.*; + +/** + * RCAT Module that is dynamically loaded into the GUI + */ +public class RCATModule implements GuiModule{ + /** + * Starts the RCAT module + * @param petriNet current Petri net to use + */ + @Override + public void start(PetriNet petriNet) { + JFrame frame = new JFrame("RCAT for Stochastic Petri Nets"); + FileDialog selector = new FileDialog(frame, "Select petri net", FileDialog.LOAD); + frame.setContentPane(new RCATForm(petriNet, selector).getPrimPanel()); + frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frame.pack(); + frame.setVisible(true); + } + + /** + * + * @return RCAT Module + */ + @Override + public String getName() { + return "RCAT for Stochastic Petri Nets"; + } + + +} diff --git a/pipe-module-gui/src/main/java/pipe/gui/rcat/BuildingBlock.java b/pipe-module-gui/src/main/java/pipe/gui/rcat/BuildingBlock.java new file mode 100644 index 00000000..30b3018e --- /dev/null +++ b/pipe-module-gui/src/main/java/pipe/gui/rcat/BuildingBlock.java @@ -0,0 +1,40 @@ +package pipe.gui.rcat; + +import uk.ac.imperial.pipe.models.petrinet.Place; +import uk.ac.imperial.pipe.models.petrinet.Transition; + +import java.util.Collection; +import java.util.HashSet; + +/** + * Class for generating Building Blocks - a set of Places and Transitions + * such that for every input transition there exists an output transition. + * + * @author Tanvi Potdar + */ +public class BuildingBlock { + private Collection places; + private Collection transitions; + + public BuildingBlock(Collection places, Collection transitions){ + this.places = places; + this.transitions = transitions; + } + + public Collection getPlaces() { + return places; + } + + public void setPlaces(Collection places) { + this.places = places; + } + + public Collection getTransitions() { + return transitions; + } + + public void setTransitions(Collection transitions) { + this.transitions = transitions; + } + +} diff --git a/pipe-module-gui/src/main/java/pipe/gui/rcat/BuildingBlockCreator.java b/pipe-module-gui/src/main/java/pipe/gui/rcat/BuildingBlockCreator.java new file mode 100644 index 00000000..daaa55ed --- /dev/null +++ b/pipe-module-gui/src/main/java/pipe/gui/rcat/BuildingBlockCreator.java @@ -0,0 +1,140 @@ +package pipe.gui.rcat; + +import uk.ac.imperial.pipe.exceptions.PetriNetComponentException; +import uk.ac.imperial.pipe.models.petrinet.*; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; + +/** + * Controller for the RCAT Module + * @author Tanvi Potdar + */ +public class BuildingBlockCreator { + + /** + * called by the splitBB Jbutton to split the Petri Net into building blocks + * @param petriNet + * @return + * @throws PetriNetComponentException + */ + public Collection> splitIntoBuildingBlocks(PetriNet petriNet) throws PetriNetComponentException { + + Collection> listOfBuildingBlocks = new HashSet<>(); + + RcatPlaceVisitor rcatPlaceVisitor = new RcatPlaceVisitor(petriNet); + Collection visitedPlaces = rcatPlaceVisitor.visitedPlaces; + + for(Place place: petriNet.getPlaces()){ + if(! visitedPlaces.contains(place)){ + place.accept(rcatPlaceVisitor); + Collection buildingBlock = rcatPlaceVisitor.buildingBlock.getPlaces(); + listOfBuildingBlocks.add(buildingBlock); + } + + } + return listOfBuildingBlocks; + + } + + /** + * class that creates a Visitor for the places in a Petri Net + * so as to delineate the actions required of a place when it + * is visited, i.e., + * 1. get its neighbours + * 2. create a building block using the place and its neighbours + */ + + private static class RcatPlaceVisitor implements PlaceVisitor { + /** + * current petri net + */ + private PetriNet petriNet; + /** + * set of places that the visitor has already visited + */ + private final Collection visitedPlaces = new HashSet<>(); + /** + * building block created for the place in question + */ + private BuildingBlock buildingBlock; + + /** + * Constructor for the RCATPlaceVisitor class + * @param petriNet in use + */ + RcatPlaceVisitor(PetriNet petriNet) { + this.petriNet = petriNet; + } + + /** + * specifies the actions that should happen when a + * place is visited by the RCATPlaceVisitor + * @param place + * @throws PetriNetComponentException + */ + @Override + public void visit(Place place) throws PetriNetComponentException { + visitedPlaces.add(place); + searchForBuildingBlock(place); + } + + /** + *creates a building block for the place in question + * @param place + * @throws PetriNetComponentException + */ + private void searchForBuildingBlock(Place place) throws PetriNetComponentException { + Collection bbPlaces = new HashSet<>(); + bbPlaces.add(place); + + for(Place neighbour: getNeighbours(place)){ + if(!visitedPlaces.contains(neighbour)){ + this.visit(neighbour); + } + bbPlaces.add(neighbour); + } + + //TODO: add transitions to BB. + buildingBlock = new BuildingBlock(bbPlaces, new HashSet()); + } + + /** + *gets the neighbours of the place in question + * @param place + * @return the neighbours of the place, i.e , all the places that have the ~ relation with p + * The ~ relation: p1~p2 if they share inbound arcs + */ + public Iterable getNeighbours(Place place){ + Collection neighbours = new HashSet<>(); + Collection visitedTransitions = new HashSet<>(); + Collection outputTransitionsForSinglePlace = new ArrayList<>(); + + for(uk.ac.imperial.pipe.models.petrinet.Arc arc: petriNet.getArcs()){ + if(place.equals(arc.getSource())){ + outputTransitionsForSinglePlace.add((Transition) arc.getTarget()); + } + } + + for(Transition transition: outputTransitionsForSinglePlace){ + if(! (visitedTransitions.contains(transition))){ + Collection inboundArcs = petriNet.inboundArcs(transition); + for(InboundArc inboundArc : inboundArcs){ + Place inboundPlace = inboundArc.getSource(); + if(!place.equals(inboundPlace)){ + neighbours.add(inboundPlace); + } + } + + } + visitedTransitions.add(transition); + } + return neighbours; + } + + } + + + +} diff --git a/pipe-module-gui/src/main/java/pipe/gui/widget/RCATForm.form b/pipe-module-gui/src/main/java/pipe/gui/widget/RCATForm.form new file mode 100644 index 00000000..ed8df4f2 --- /dev/null +++ b/pipe-module-gui/src/main/java/pipe/gui/widget/RCATForm.form @@ -0,0 +1,175 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pipe-module-gui/src/main/java/pipe/gui/widget/RCATForm.java b/pipe-module-gui/src/main/java/pipe/gui/widget/RCATForm.java new file mode 100644 index 00000000..a726e832 --- /dev/null +++ b/pipe-module-gui/src/main/java/pipe/gui/widget/RCATForm.java @@ -0,0 +1,190 @@ +package pipe.gui.widget; + +import pipe.gui.rcat.BuildingBlockCreator; +import uk.ac.imperial.pipe.exceptions.PetriNetComponentException; +import uk.ac.imperial.pipe.io.PetriNetIOImpl; +import uk.ac.imperial.pipe.io.PetriNetReader; +import uk.ac.imperial.pipe.models.petrinet.*; + + +import javax.swing.*; +import javax.xml.bind.JAXBException; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.FileNotFoundException; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * View class for the RCAT Module + * @author Tanvi Potdar + * + */ +public class RCATForm { + /** + * main JPanel + */ + private JPanel primPanel; + /** + * radio button to choose to use existing petri net + */ + private JRadioButton useExisting; + /** + * radio buttons to enable the user to load petri nets from file + */ + private JRadioButton loadPetriNetFromRadioButton; + /** + * text field into which the petri net name appears + */ + private JTextField loadpn; + /** + * JButton to calculate rates for passive transitions in the Building Block + */ + private JButton calculatePassiveTransitionRates; + /** + * JButton to split appropriate petri netz into Building Blocks + */ + private JButton splitBB; + private JLabel petriNetTextLabel; + private JPanel resultsP; + /** + * Text area to print results + */ + private JTextArea evalTextArea; + private JLabel resultsLabel; + private final FileDialog loadPetriNetFromFile; + /** + * petri net loaded via the load dialog + */ + private PetriNet lastloaded; + /** + * default petri net/ existing petri net + */ + private PetriNet defaultPetriNet; + /** + * petri net being evaluated currently + */ + private PetriNet petriNet; + + private static final Logger LOGGER = Logger.getLogger(RCATForm.class.getName()); + + /** + * Sets up the load Petri net options with the "use current Petri net" disabled + * @param loadDialog creates file dialog to select petri net + */ + public RCATForm(FileDialog loadDialog){ + this.loadPetriNetFromFile = loadDialog; + useExisting.setEnabled(false); + setUp(); + } + /** + * Sets up the load Petri net options with "use current Petri net" set to + * the petriNet parameter + * + * @param petriNet current Petri net + * @param loadDialog + */ + public RCATForm(PetriNet petriNet, FileDialog loadDialog) { + defaultPetriNet = petriNet; + this.loadPetriNetFromFile = loadDialog; + setUp(); + } + + /** + * Defines action listeners for the radio and J-buttons: + * 1.load petri net from file + * 2.split petri net into building blocks + * 3.calculate rates for passive transitions + */ + public void setUp(){ + loadPetriNetFromRadioButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + loadData(); + } + }); + splitBB.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + setPetriNet(); + splitIntoBuildingBlocks(); + } + }); + calculatePassiveTransitionRates.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + calculatePassiveTransitionRates(); + } + }); + + } + + /** + * calls the BuildingBlockCreator class to split the current PN into Building Blocks + * sets text area to the places in each building block + * tests if a PN satisfies RCAT by checking if it can be split into Building Blocks + */ + private void splitIntoBuildingBlocks() { + try { + Collection> listOfBuildingBlocks = new BuildingBlockCreator().splitIntoBuildingBlocks(petriNet); + if(listOfBuildingBlocks.isEmpty()){ + //TODO: Copy conditions for RCAT + evalTextArea.setText("This Petri Net cannot be split into building blocks as it does ...."); + } + else evalTextArea.setText(listOfBuildingBlocks.toString()); + } + catch (PetriNetComponentException e) { + e.printStackTrace(); + } + } + + /** + * sets the petriNet variable to the petriNet in use(existing vs loaded) + */ + private void setPetriNet() { + petriNet = useExisting.isSelected() ? defaultPetriNet : lastloaded; + } + + /** + * Opens the file dialog and saves the selected Petri net into lastLoadedPetriNet + * for use when calculating the state space exploration + */ + private void loadData() { + useExisting.setSelected(false); + loadPetriNetFromRadioButton.setSelected(true); + loadPetriNetFromFile.setMode(FileDialog.LOAD); + loadPetriNetFromFile.setTitle("Select petri net"); + loadPetriNetFromFile.setVisible(true); + File[] files = loadPetriNetFromFile.getFiles(); + if (files.length > 0) { + File path = files[0]; + try { + loadpn.setText(path.getName()); + PetriNetReader petriNetIO = new PetriNetIOImpl(); + lastloaded = petriNetIO.read(path.getAbsolutePath()); + } catch (JAXBException | FileNotFoundException e) { + LOGGER.log(Level.SEVERE, e.getMessage()); + } + } + } + + /** + * returns the Primary Panel in the UI + * @return + */ + public JPanel getPrimPanel(){ + return primPanel; + } + + /** + * calculates the rates for passive transitions + */ + public void calculatePassiveTransitionRates(){ + + } + + +} From 0031595e46f4a5ce41f5dedef6858b75bb4e46d3 Mon Sep 17 00:00:00 2001 From: tanvipotdar Date: Thu, 28 Aug 2014 15:37:50 +0530 Subject: [PATCH 7/7] Allowed the list of transitions to be displayed along with the list of places in the building block Enabled printing of structural conditions of Building Blocks when the petri net is split Added features to get all arcs (inbound and outbound separately as well) in the building blocks Added methods to calculate elementary rate equations for a building block which works satisfactorily for MM1 queues but less so for larger building blocks --- .../java/pipe/gui/rcat/BuildingBlock.java | 97 +++++++- .../pipe/gui/rcat/BuildingBlockCreator.java | 34 ++- .../main/java/pipe/gui/widget/RCATForm.form | 28 ++- .../main/java/pipe/gui/widget/RCATForm.java | 218 +++++++++++++++++- 4 files changed, 355 insertions(+), 22 deletions(-) diff --git a/pipe-module-gui/src/main/java/pipe/gui/rcat/BuildingBlock.java b/pipe-module-gui/src/main/java/pipe/gui/rcat/BuildingBlock.java index 30b3018e..718b8d91 100644 --- a/pipe-module-gui/src/main/java/pipe/gui/rcat/BuildingBlock.java +++ b/pipe-module-gui/src/main/java/pipe/gui/rcat/BuildingBlock.java @@ -1,10 +1,11 @@ package pipe.gui.rcat; -import uk.ac.imperial.pipe.models.petrinet.Place; -import uk.ac.imperial.pipe.models.petrinet.Transition; +import uk.ac.imperial.pipe.models.petrinet.*; +import java.text.AttributedString; import java.util.Collection; import java.util.HashSet; +import java.util.Map; /** * Class for generating Building Blocks - a set of Places and Transitions @@ -13,28 +14,120 @@ * @author Tanvi Potdar */ public class BuildingBlock { + /** + * collection of places in the building block + */ private Collection places; + /** + * collection of transitions in the building block + */ private Collection transitions; + /** + * symbolic input transition rates stored as strings + */ + private Map inputRates; + /** + * symbolic output transition rates stored as strings + */ + private Map outputRates; + + /** + * constructor for the building block + * @param places + * @param transitions + */ public BuildingBlock(Collection places, Collection transitions){ this.places = places; this.transitions = transitions; } + /** + * gets the places in the building block + * @return places + */ public Collection getPlaces() { return places; } + /** + * sets the places in the building block to the collection provided + * @param places + */ public void setPlaces(Collection places) { this.places = places; } + /** + * gets the transitions in the building block + * @return transitions + */ public Collection getTransitions() { return transitions; } + /** + * sets the transitions in the building block to the collection provided + * @param transitions + */ public void setTransitions(Collection transitions) { this.transitions = transitions; } + /** + * gets all the places and transitions in the building block + * @return places and transitions + */ + public Collection getConnectables(){ + Collection connectables = new HashSet<>(); + connectables.addAll(places); + connectables.addAll(transitions); + return connectables; + + } + + /** + * Unknown input rates represented as strings + * @param petriNet + * @return input rates of the building block + */ + public Map getInputRates(PetriNet petriNet) { + for(Transition transition: getTransitions()){ + if(petriNet.outboundArcs(transition).size()>0){ + inputRates.keySet().add(transition); + inputRates.values().add("x_" + transition.getId()); + } + } + return inputRates; + } + + /** + *Returns the known rates of the output transitions in the building block + * @param petriNet + */ + public Map getOutputRates(PetriNet petriNet) { + for(Transition transition: getTransitions()){ + if(petriNet.inboundArcs(transition).size()>0){ + outputRates.keySet().add(transition); + outputRates.values().add(transition.getRateExpr()); + } + } + return inputRates; + } + + /** + * get input rates in the building block + * @return input rates + */ + public void setInputRates(Map inputRates) { + this.inputRates = inputRates; + } + + /** + * get output rates in the building block + * @return output rates + */ + public void setOutputRates(Map outputRates) { + this.outputRates = outputRates; + } } diff --git a/pipe-module-gui/src/main/java/pipe/gui/rcat/BuildingBlockCreator.java b/pipe-module-gui/src/main/java/pipe/gui/rcat/BuildingBlockCreator.java index daaa55ed..e1b704bc 100644 --- a/pipe-module-gui/src/main/java/pipe/gui/rcat/BuildingBlockCreator.java +++ b/pipe-module-gui/src/main/java/pipe/gui/rcat/BuildingBlockCreator.java @@ -1,8 +1,10 @@ package pipe.gui.rcat; +import pipe.gui.widget.RCATForm; import uk.ac.imperial.pipe.exceptions.PetriNetComponentException; import uk.ac.imperial.pipe.models.petrinet.*; +import java.awt.*; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -19,9 +21,9 @@ public class BuildingBlockCreator { * @return * @throws PetriNetComponentException */ - public Collection> splitIntoBuildingBlocks(PetriNet petriNet) throws PetriNetComponentException { + public Collection splitIntoBuildingBlocks(PetriNet petriNet) throws PetriNetComponentException { - Collection> listOfBuildingBlocks = new HashSet<>(); + Collection listOfBuildingBlocks = new HashSet<>(); RcatPlaceVisitor rcatPlaceVisitor = new RcatPlaceVisitor(petriNet); Collection visitedPlaces = rcatPlaceVisitor.visitedPlaces; @@ -29,11 +31,11 @@ public Collection> splitIntoBuildingBlocks(PetriNet petriNet) for(Place place: petriNet.getPlaces()){ if(! visitedPlaces.contains(place)){ place.accept(rcatPlaceVisitor); - Collection buildingBlock = rcatPlaceVisitor.buildingBlock.getPlaces(); + BuildingBlock buildingBlock = rcatPlaceVisitor.buildingBlock; listOfBuildingBlocks.add(buildingBlock); } - } + return listOfBuildingBlocks; } @@ -96,8 +98,27 @@ private void searchForBuildingBlock(Place place) throws PetriNetComponentExcepti bbPlaces.add(neighbour); } - //TODO: add transitions to BB. - buildingBlock = new BuildingBlock(bbPlaces, new HashSet()); + buildingBlock = new BuildingBlock(bbPlaces, getAllTransitionsInBuildingBlock(bbPlaces)); + } + + /** + * gets all the transitions in a building block + * @param places in the building block + * @return all the transitions in each place in a Building Block + */ + public Collection getAllTransitionsInBuildingBlock(Collection places){ + Collection allTrans = new HashSet<>(); + for(Place place: places){ + for(Arc arc: petriNet.getArcs()){ + if(place.equals(arc.getSource())){ + allTrans.add((Transition)arc.getTarget()); + } + if(place.equals(arc.getTarget())){ + allTrans.add((Transition)arc.getSource()); + } + } + } + return allTrans; } /** @@ -133,6 +154,7 @@ public Iterable getNeighbours(Place place){ return neighbours; } + } diff --git a/pipe-module-gui/src/main/java/pipe/gui/widget/RCATForm.form b/pipe-module-gui/src/main/java/pipe/gui/widget/RCATForm.form index ed8df4f2..3d95db90 100644 --- a/pipe-module-gui/src/main/java/pipe/gui/widget/RCATForm.form +++ b/pipe-module-gui/src/main/java/pipe/gui/widget/RCATForm.form @@ -12,6 +12,8 @@ + + @@ -24,7 +26,7 @@ - + @@ -54,7 +56,7 @@ - + @@ -120,7 +122,7 @@ - + @@ -128,9 +130,13 @@ - + + + + + - + @@ -141,11 +147,21 @@ - + + + + + + + + + + + diff --git a/pipe-module-gui/src/main/java/pipe/gui/widget/RCATForm.java b/pipe-module-gui/src/main/java/pipe/gui/widget/RCATForm.java index a726e832..754ac778 100644 --- a/pipe-module-gui/src/main/java/pipe/gui/widget/RCATForm.java +++ b/pipe-module-gui/src/main/java/pipe/gui/widget/RCATForm.java @@ -1,5 +1,6 @@ package pipe.gui.widget; +import pipe.gui.rcat.BuildingBlock; import pipe.gui.rcat.BuildingBlockCreator; import uk.ac.imperial.pipe.exceptions.PetriNetComponentException; import uk.ac.imperial.pipe.io.PetriNetIOImpl; @@ -55,6 +56,7 @@ public class RCATForm { */ private JTextArea evalTextArea; private JLabel resultsLabel; + private JTextArea ratesTextArea; private final FileDialog loadPetriNetFromFile; /** * petri net loaded via the load dialog @@ -81,7 +83,7 @@ public RCATForm(FileDialog loadDialog){ setUp(); } /** - * Sets up the load Petri net options with "use current Petri net" set to + * Sets up the load Petri net options with "use existing Petri net" set to * the petriNet parameter * * @param petriNet current Petri net @@ -122,6 +124,34 @@ public void actionPerformed(ActionEvent e) { } + /** + * Converts the list of building blocks into String + * @param buildingBlocks + * @return list of building blocks in string form + */ + public String toString(Collection buildingBlocks){ + StringBuilder stringBuilder = new StringBuilder(); + for(BuildingBlock buildingBlock: buildingBlocks){ + for(Connectable c: buildingBlock.getConnectables()){ + stringBuilder.append(" "+c.getId()+" "); + } + stringBuilder.append("\n"); + } + return stringBuilder.toString(); + + } + + /** + * checks if the petri net satisfies POSPN conditions + * @param petriNet is the petri net in use + * @return true if the petri net satisfies POSPN conditions and false + * if it doesn't + */ + //TODO: Fill in conditions for POSPN + public boolean checkIfPOSPN(PetriNet petriNet){ + return false; + } + /** * calls the BuildingBlockCreator class to split the current PN into Building Blocks * sets text area to the places in each building block @@ -129,12 +159,17 @@ public void actionPerformed(ActionEvent e) { */ private void splitIntoBuildingBlocks() { try { - Collection> listOfBuildingBlocks = new BuildingBlockCreator().splitIntoBuildingBlocks(petriNet); - if(listOfBuildingBlocks.isEmpty()){ - //TODO: Copy conditions for RCAT - evalTextArea.setText("This Petri Net cannot be split into building blocks as it does ...."); + Collection listOfBuildingBlocks = new BuildingBlockCreator().splitIntoBuildingBlocks(petriNet); + if(checkIfPOSPN(petriNet)==true){ + evalTextArea.setText("This Petri Net cannot be split into Building Blocks because it is not a POSPN. " + + "\n"+ "In a POSPN, for every input transition, there exists an output transition. " + "\n" + + "This Petri Net does not satisfy those conditions and hence its rate equations cannot be solved by RCAT." + ); } - else evalTextArea.setText(listOfBuildingBlocks.toString()); + else evalTextArea.setText("Here are the building blocks of this Petri Net"+"\n"+toString(listOfBuildingBlocks) + + "\n"+ "Each Building Block satisfies the conditions:" + "\n" + "1.Every transition is an input or an output transition" + + "\n" + "2. For every input transition, there exists an output transition" + "\n" + "3. The Petri Net has to be completely connected." + + "\n" +"As a result, the rate equations of this Petri Net can be solved by RCAT."); } catch (PetriNetComponentException e) { e.printStackTrace(); @@ -148,6 +183,15 @@ private void setPetriNet() { petriNet = useExisting.isSelected() ? defaultPetriNet : lastloaded; } + + /** + * Gets the current petri net + * @return petri net in use + */ + public PetriNet getPetriNet(){ + return petriNet; + } + /** * Opens the file dialog and saves the selected Petri net into lastLoadedPetriNet * for use when calculating the state space exploration @@ -173,7 +217,7 @@ private void loadData() { /** * returns the Primary Panel in the UI - * @return + * @return primary panel */ public JPanel getPrimPanel(){ return primPanel; @@ -183,8 +227,166 @@ public JPanel getPrimPanel(){ * calculates the rates for passive transitions */ public void calculatePassiveTransitionRates(){ + StringBuilder outputProductForm = new StringBuilder(); + Collection stringBuilders = new HashSet<>(); + try { + Collection listOfBuildingBlocks = new BuildingBlockCreator().splitIntoBuildingBlocks(petriNet); + for(BuildingBlock buildingBlock: listOfBuildingBlocks){ + if(buildingBlock.getPlaces().size()==1){ + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(generateSSPDForMM1(buildingBlock)); + stringBuilders.add(stringBuilder); + } + if(buildingBlock.getPlaces().size()>1){ + stringBuilders.addAll(ProductForm(buildingBlock)); + outputProductForm.append(ProductForm(buildingBlock)); + } + } + } catch (PetriNetComponentException e) { + e.printStackTrace(); + } + + ratesTextArea.setText(stringBuilders.toString()); + + } + + /** + * Returns all the arcs in the building block provided + * @param buildingBlock + * @return all the arcs in the building block + */ + public Collection getBuildingBlockArcs(BuildingBlock buildingBlock){ + Collection arcs = new HashSet<>(); + for(Arc arc: petriNet.getArcs()){ + for(Connectable c: buildingBlock.getConnectables()){ + if(c.equals(arc.getSource())||c.equals(arc.getTarget())){ + arcs.add(arc); + } + } + } + return arcs; } + /** + * Returns all the inbound arcs(from place to transition) in the building block + * @param buildingBlock + * @return all inbound arcs + */ + public Collection getInboundArcsInBuildingBlock(BuildingBlock buildingBlock){ + Collection inboundArcsinBuildingBlock = new HashSet<>(); + for(Arc arc: getBuildingBlockArcs(buildingBlock)){ + for(Transition transition: buildingBlock.getTransitions()){ + for(Place place: buildingBlock.getPlaces()){ + if(transition.equals(arc.getTarget())&&place.equals(arc.getSource())){ + inboundArcsinBuildingBlock.add((InboundArc)arc); + } + } + } + } + return inboundArcsinBuildingBlock; + } + + /** + * Returns all outbound arcs(from transition to place) in the building block + * @param buildingBlock + * @return all outbound arcs + */ + public Collection getOutboundArcsInBuildingBlock(BuildingBlock buildingBlock){ + Collection outboundArcsinBuildingBlock = new HashSet<>(); + for(Arc arc: getBuildingBlockArcs(buildingBlock)){ + for(Transition transition: buildingBlock.getTransitions()){ + for(Place place: buildingBlock.getPlaces()){ + if(transition.equals(arc.getSource())&&place.equals(arc.getTarget())){ + outboundArcsinBuildingBlock.add((OutboundArc)arc); + } + } + } + } + return outboundArcsinBuildingBlock; + } + + /** + * Generates the Steady State Probability Distribution for a building block + * with one place, i.e., an MM1 queue + * @param buildingBlock + * @return the sspd equation for an MM1 queue in the form of a string + */ + public String generateSSPDForMM1(BuildingBlock buildingBlock){ + String output = new String(); + StringBuilder numerator = new StringBuilder(); + StringBuilder denominator = new StringBuilder(); + if(buildingBlock.getTransitions().size()==2) { + for (OutboundArc outboundArc : getOutboundArcsInBuildingBlock(buildingBlock)) { + numerator.append(outboundArc.getSource().getId()); + } + for (InboundArc inboundArc : getInboundArcsInBuildingBlock(buildingBlock)) { + denominator.append(inboundArc.getTarget().getId()+"\n"); + } + } + else if(buildingBlock.getTransitions().size()>2) { + for (OutboundArc outboundArc : getOutboundArcsInBuildingBlock(buildingBlock)) { + numerator.append(outboundArc.getSource().getId() + "+"); + } + for (InboundArc inboundArc : getInboundArcsInBuildingBlock(buildingBlock)) { + denominator.append(inboundArc.getTarget().getId() + "+"+"\n"); + } + } + output = "x_"+numerator+"="+"x_"+denominator; + return output; + } + + /** + * generates the product form rate equations for building blocks + * @param buildingBlock + * @return rate equations + */ + public Collection ProductForm(BuildingBlock buildingBlock){ + StringBuilder stringBuilder = new StringBuilder(),rate = new StringBuilder(); + Collection stringBuilders = new HashSet<>(),rates = new HashSet<>(); + Collection inputTransitions = new HashSet<>(), outputTransitions=new HashSet<>(); + for(Arc arc: getOutboundArcsInBuildingBlock(buildingBlock)){ + inputTransitions.add((Transition)arc.getSource()); + } + for(Arc arc: getInboundArcsInBuildingBlock(buildingBlock)){ + outputTransitions.add((Transition)arc.getTarget()); + + } + for(Transition i_transition:inputTransitions){ + for(Transition o_transition: outputTransitions){ + if(petriNet.outboundArcs(i_transition).size()==petriNet.inboundArcs(o_transition).size()){ + for(Arc arc: petriNet.outboundArcs(i_transition)){ + for (Arc arc1: petriNet.inboundArcs(o_transition)){ + if(arc.getTarget().equals(arc1.getSource())){ + stringBuilder.append(i_transition.getId()+"/"+o_transition.getId()+" "); + stringBuilders.add(stringBuilder); + rate.append("x_"+i_transition.getId()+" = "+"x_"+o_transition.getId()+"\n"); + rates.add(rate); + } + } + } + } + } + } + return rates; + } + + + + + + } + + + + + + + + + + + + + -}