diff --git a/data/examples/complex.flowshop b/data/examples/complex.flowshop new file mode 100644 index 0000000..f0a731b --- /dev/null +++ b/data/examples/complex.flowshop @@ -0,0 +1,10 @@ +Flowshop 6 8 + Piece1 Piece2 Piece3 Piece4 Piece5 Piece6 +Machine1 2.0 3.9 0.95 1.1 0.7 1.4 +Machine2 nan nan 2.0 1.2 nan 1.7 +Machine3 3.7 nan 2.2 nan 6.4 nan +Machine4 nan nan 2.0 nan 1.0 1.0 +Machine5 1.7 3.1 3.0 nan 1.3 nan +Machine6 0.5 3.2 4.3 1.9 1.6 0.4 +Machine7 1.0 1.0 1.0 1.0 1.0 1.0 +Machine8 1.5 1.5 1.5 1.2 1.2 1.2 diff --git a/data/examples/simple.flowshop b/data/examples/simple.flowshop index 61e207f..0a2dc68 100644 --- a/data/examples/simple.flowshop +++ b/data/examples/simple.flowshop @@ -1,9 +1,5 @@ -8 6 -2 3.9 0.95 1.1 0.7 1.4 --Inf -Inf 2 1.2 -Inf 1.7 -3.7 -Inf 2.2 -Inf 6.4 -Inf --Inf -Inf 2 -Inf 1 1 -1.7 3.1 3 -Inf 1.3 -Inf -0.5 3.2 4.3 1.9 1.6 0.4 -1 1 1 1 1 1 -1.5 1.5 1.5 1.2 1.2 1.2 +Flowshop 3 3 + Part1 Part2 Part3 +Machine1 nan 1.0 5.0 +Machine2 3.0 2.0 3.0 +Machine3 4.0 3.0 nan diff --git a/src/Net/Imports/ImportFlowshop.cpp b/src/Net/Imports/ImportFlowshop.cpp index c989e1d..96fcf03 100644 --- a/src/Net/Imports/ImportFlowshop.cpp +++ b/src/Net/Imports/ImportFlowshop.cpp @@ -1,107 +1,171 @@ +//============================================================================= +// TimedPetriNetEditor: A timed Petri net editor. +// Copyright 2021 -- 2023 Quentin Quadrat +// +// This file is part of TimedPetriNetEditor. +// +// TimedPetriNetEditor is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GNU Emacs. If not, see . +//============================================================================= + +#include "Imports.hpp" +#include "TimedPetriNetEditor/PetriNet.hpp" +#include +#include +#include + +namespace tpne { + //------------------------------------------------------------------------------ -// See http://jpquadrat.free.fr/chine.pdf flowshop_graph() function -// TODO ./build/TimedPetriEditor foo.flowshop -bool PetriNet::importFlowshop(std::string const& filename) +std::vector splitLine(std::ifstream& file) { - static_assert(std::numeric_limits::is_iec559, "IEEE 754 required"); + std::string s; + + std::getline(file, s); + std::cout << "Line " << s << std::endl; + std::stringstream ss(s); + std::vector v; - std::ifstream ifs{ filename }; - if (!ifs) + while (std::getline(ss, s)) { - std::cerr << "Could not open matrix file '" - << filename << "' for reading" - << std::endl; - return false; + std::cout << s << std::endl; + v.push_back(s); } - // Dense matrix - std::vector> matrix; - size_t rows, columns; + return v; +} + +//------------------------------------------------------------------------------ +std::string importFlowshop(Net& net, std::string const& filename) +{ + struct DataMatrix + { + std::vector columnNames; + std::vector rowNames; + std::vector> data; + }; + + DataMatrix matrix; + std::stringstream error; - // Read the number of rows and columns and resize the vector of data - if (!(ifs >> rows >> columns)) + // Check if file exists + std::ifstream file(filename); + if (!file) { - m_message.str(""); - m_message << "Malformed matrix dimension. Needed rows columns information" - << std::endl; - return false; + error << "Failed opening '" << filename << "'. Reason was '" + << strerror(errno) << "'" << std::endl; + return error.str(); } - // Read all data and store them into the matrix - matrix.resize(rows, std::vector(columns)); - for (std::vector& row : matrix) + // Extract number of transitions and number of lines + size_t transitions, lines, rows; + std::string type; + + if (!(file >> type >> rows >> lines)) { - for (double& col : row) - { - std::string text; - ifs >> text; - col = std::stod(text.c_str()); - std::cout << ' ' << col; - } - std::cout << std::endl; + error << "Malformed header. Needed 'Flowshop number_transitions number_lines'" + << std::endl; + return error.str(); } + if (type != "Flowshop") + { + error << "Malformed token. Expected to extract token 'TimedEventGraph'" + << std::endl; + return error.str(); + } + + // windows screen. + // FIXME: get the exact dimension Editor::viewSize() + // FIXME: initial frame iteration: the screen size is not at its final size + const size_t w = 600u; const size_t h = 600u; + const size_t margin = 50u; + // Since the file does not give position, we place them as square + size_t dx = (w - 2u * margin) / rows; + size_t dy = (h - 2u * margin) / lines; + size_t x = margin + dx; size_t y = margin + dy; + + size_t id = 0u; + std::string line; + + // End the current line + getline(file, line); - // Construct the flowshop - float x, y; - const size_t machines = rows; - const size_t pieces = columns; - const float SPACING = 100.0f; - size_t id = 0u; // Place unique identifier - size_t m, p; // iterators - std::vector places; - - // Add places of the matrix - x = 2.0f * SPACING; y = SPACING - 50.0f; - for (m = 0u; m < machines; ++m) // TODO inverser l'ordre + // Read the column names + if (getline(file, line)) { - x = 2.0f * SPACING; - for (p = 0u; p < pieces; ++p) + std::istringstream columnNamesStream(line); + std::string columnName; + while (columnNamesStream >> columnName) { - if (matrix[m][p] != -std::numeric_limits::infinity()) - { - // Place caption "m1p2" for "Machine1--Piece2" - //std::string caption("m" + std::to_string(m) + "p" + std::to_string(p)); - std::string caption(std::to_string(id) + ": " + std::to_string(m * pieces + p)); - places.push_back(&addPlace(id++, caption, x, y, 0u)); - } - x += SPACING; + matrix.columnNames.push_back(columnName); } - y += SPACING; } - // Link arcs between places: this will add the transitions - for (m = 0u; m < 2u/*machines - 1u*/; ++m) + // Read the following lines to obtain the row names and the data + while (getline(file, line)) { - for (p = 0u; p < pieces - 1u; ++p) + std::istringstream lineStream(line); + std::string rowName; + if (lineStream >> rowName) { - size_t next = p + 1u; - while ((next < pieces - 1u) && (matrix[m][next] == -std::numeric_limits::infinity())) + matrix.rowNames.push_back(rowName); + + std::vector row; + std::string value; + while (lineStream >> value) { - next += 1u; - } + row.push_back(stof(value)); - Node* from = findNode(places[m * pieces + p]->key); - Node* to = findNode(places[m * pieces + next]->key); - std::cout << "M" << m << ": " << - addArc(*from, *to, float(matrix[m][p]), false); + if (value != "nan") + { + net.addPlace(id, Transition::to_str(id), x, y, 0); + id++; + } + x += dx; + } + matrix.data.push_back(row); + } + else + { + error << "Malformed line '" << line << "'" << std::endl; + return error.str(); } + x = margin + dx; + y += dy; } - // Construct the flowshop: Place the machines (inputs) - x = SPACING; y = SPACING; - for (size_t i = 0u; i < machines; ++i) + float ymax = y; + float xmax = margin + dx + dx * rows; + + // Place this code outside the getline() loop to have id of internal transitions + // starting from 0. + x = margin + dx - dx / 2.0f; y = margin; + for (const auto& columnName : matrix.columnNames) { - addPlace(p++, "Machine " + std::to_string(i), x, y, 0u); // FIXME id - y += SPACING; + net.addPlace(id++, columnName, x, y, 0); + //net.addPlace(id++, columnName, x, ymax, 0); + x += dx; } - // Construct the flowshop: Place the pieces (inputs) - x += SPACING / 2.0f; - for (size_t i = 0u; i < pieces; ++i) + x = margin; y = margin + dy + dy / 2.0f; + for (const auto& rowName : matrix.rowNames) { - addPlace(p++, "Piece " + std::to_string(i), x, y, 0u); // FIXME id - x += SPACING; + net.addPlace(id++, rowName, x, y, 0); + //net.addPlace(id++, rowName, xmax, y, 0); + y += dy; } - return true; + return {}; } + +} // namespace tpne diff --git a/src/Net/Imports/Imports.cpp b/src/Net/Imports/Imports.cpp index afa7c04..6d5ae5d 100644 --- a/src/Net/Imports/Imports.cpp +++ b/src/Net/Imports/Imports.cpp @@ -28,7 +28,7 @@ std::vector const& importers() static const std::vector s_importers = { { "JSON", ".json", importFromJSON }, { "Petri Net Markup Language", ".pnml", importFromPNML }, - // FIXME add a filter to eliminate it in the case the net is not event graph + { "Flowshop", ".flowshop", importFlowshop }, { "Timed Event Graph", ".teg", importFromTimedEventGraph } }; diff --git a/src/Net/Imports/Imports.hpp b/src/Net/Imports/Imports.hpp index 01d14af..e10ac79 100644 --- a/src/Net/Imports/Imports.hpp +++ b/src/Net/Imports/Imports.hpp @@ -34,6 +34,8 @@ std::string importFromJSON(Net& net, std::string const& filename); std::string importFromTimedEventGraph(Net& net, std::string const& filename); //! \brief Import https://gitlab.com/porky11/pn-editor std::string importFromPNML(Net& net, std::string const& filename); +//! \brief Import +std::string importFlowshop(Net& net, std::string const& filename); //! \brief Interface for importing a Petri file. //! \param[inout] net the net we are importing. Better to call net.clear() diff --git a/src/Net/Makefile b/src/Net/Makefile index 9134867..38cd3b9 100644 --- a/src/Net/Makefile +++ b/src/Net/Makefile @@ -65,13 +65,13 @@ LINKER_FLAGS += -ldl -lpthread ################################################### # Make the list of compiled files for the library # -IMPORT_FORMATS += ImportJSON.o ImportPNML.o ImportTimedEventGraph.o ExportTimedEventGraph.o -EXPORT_FORMATS += ExportJSON.o ExportPNML.o ExportSymfony.o ExportPnEditor.o -EXPORT_FORMATS += ExportPetriLaTeX.o ExportJulia.o ExportGraphviz.o ExportDrawIO.o -EXPORT_FORMATS += ExportGrafcetCpp.o +LIB_OBJS += ImportJSON.o ImportPNML.o ImportTimedEventGraph.o ExportTimedEventGraph.o +LIB_OBJS += ExportJSON.o ExportPNML.o ExportSymfony.o ExportPnEditor.o +LIB_OBJS += ExportPetriLaTeX.o ExportJulia.o ExportGraphviz.o ExportDrawIO.o +LIB_OBJS += ExportGrafcetCpp.o ImportFlowshop.o LIB_OBJS += Path.o Howard.o Utils.o TimedTokens.o Receptivities.o LIB_OBJS += PetriNet.o Algorithms.o Simulation.o History.o -LIB_OBJS += $(IMPORT_FORMATS) Imports.o $(EXPORT_FORMATS) Exports.o +LIB_OBJS += Imports.o Exports.o ################################################### # Compile the project, the static and shared libraries