diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c64baf..fa1947a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED TRUE) find_package(SDL2 CONFIG REQUIRED) find_package(SDL2_ttf CONFIG REQUIRED) +add_definitions(-DROOT_DIR="${CMAKE_SOURCE_DIR}") + add_subdirectory(extern/pugixml-1.13) add_subdirectory(extern/lorina/lib) diff --git a/assets/img/gates.bmp b/assets/img/gates.bmp new file mode 100644 index 0000000..e0d0169 Binary files /dev/null and b/assets/img/gates.bmp differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cd9317d..6a8b9cd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,4 +4,5 @@ target_link_libraries(main SDL2::SDL2 SDL2_ttf::SDL2_ttf pugixml::pugixml - Lorina) \ No newline at end of file + Lorina + cli11) \ No newline at end of file diff --git a/src/layout.cpp b/src/layout.cpp index d217b49..d2ba56a 100644 --- a/src/layout.cpp +++ b/src/layout.cpp @@ -13,10 +13,8 @@ #include #include -bool algorithmDFS( - const TreeNode &node, - std::vector &nodes, - std::vector &usedId) { +bool algorithmDFS(const TreeNode &node, std::vector &nodes, + std::vector &usedId) { usedId[node.id] = true; for (TreeNode::Id succId : node.succ) { if (usedId[succId]) { @@ -53,10 +51,8 @@ struct EdgeCount { int degIn = 0; }; -void removeEdgeCount( - int i, - std::vector &edgeCounts, - std::vector &nodes) { +void removeEdgeCount(int i, std::vector &edgeCounts, + std::vector &nodes) { const TreeNode &node = nodes[i]; for (TreeNode::Id id : node.succ) { edgeCounts[id].degIn--; @@ -73,10 +69,9 @@ bool comparatorId(TreeNode &first, TreeNode &second) { return first.id < second.id; } -size_t dispatchSinks( - std::vector &nodes, - std::vector &edgeCounts, - std::vector &s2) { +size_t dispatchSinks(std::vector &nodes, + std::vector &edgeCounts, + std::vector &s2) { size_t decrlenNodes = 0; for (size_t i = 0; i < edgeCounts.size();) { if (edgeCounts[i].degOut == 0) { @@ -92,10 +87,9 @@ size_t dispatchSinks( return decrlenNodes; } -size_t dispatchSources( - std::vector &nodes, - std::vector &edgeCounts, - std::vector &s1) { +size_t dispatchSources(std::vector &nodes, + std::vector &edgeCounts, + std::vector &s1) { size_t decrlenNodes = 0; for (size_t i = 0; i < edgeCounts.size();) { if (edgeCounts[i].degIn == 0) { @@ -181,10 +175,7 @@ void greedyFAS( } // Assigning a layer and numbers in this layer for each vertex of the graph -void algorithmASAP( - std::vector &nodes, - std::vector> &deletedEdges, - std::vector &lensLayer) { +void algorithmASAP(std::vector &nodes, std::vector &lensLayer) { std::vector removedNodes(nodes.size(), -1); std::vector degInNodes; @@ -218,19 +209,10 @@ void algorithmASAP( lensLayer.push_back(nodesInLayer); nodesInLayer = 0; } - - for (auto [src, dst] : deletedEdges) { - nodes[src].succ.push_back(dst); - nodes[dst].pred.push_back(src); - } } -void addLineSegment( - std::vector &nodes, - std::vector &lensLayer, - size_t idStart, - size_t idEnd, - bool isDownward) { +void addLineSegment(std::vector &nodes, std::vector &lensLayer, + size_t idStart, size_t idEnd, bool isDownward) { int order; if (isDownward) { order = 1; @@ -246,7 +228,7 @@ void addLineSegment( i += order) { TreeNode dummy = {}; dummy.isDummy = true; - dummy.id = static_cast(nodes.size()); + dummy.id = nodes.size(); dummy.layer = i; dummy.number = lensLayer[i]; lensLayer[i]++; @@ -285,19 +267,19 @@ bool addDummyNodes(std::vector &nodes, std::vector &lensLayer) { return true; } -void addAllDummyNodes( - std::vector &nodes, - std::vector &lensLayer) { +void addAllDummyNodes(std::vector &nodes, + std::vector &lensLayer) { bool allDummysAdded = false; while (!allDummysAdded) { allDummysAdded = addDummyNodes(nodes, lensLayer); } } -TreeNode::Id Net::addNode() { +TreeNode::Id Net::addNode(Type type) { Id id = static_cast(nodes.size()); nodes.emplace_back(); nodes.back().id = id; + nodes.back().type = type; return id; } @@ -343,13 +325,412 @@ const TreeNode *Net::getNode(TreeNode::Id id) const { return nullptr; } +bool comparatorPred(std::pair f, + std::pair s) { + if (f.second == s.second) { + return f.first > s.first; + } + return f.second > s.second; +} + +void getIdOrderPred(std::vector &nodes, + std::vector &orderedId, + std::vector &sourcesNodes) { + std::vector> pi = {}; + for (TreeNode &node : nodes) { + if (std::find(sourcesNodes.begin(), sourcesNodes.end(), node.id) == + sourcesNodes.end()) { + auto idAndPred = std::make_pair(node.id, node.pred.size()); + pi.push_back(idAndPred); + } + } + std::sort(pi.begin(), pi.end(), comparatorPred); + + orderedId = {}; + for (size_t i = 0; i < pi.size(); i++) { + orderedId.push_back(pi[i].first); + } +} + +void selectIdAllSuccPlaced(TreeNode::Id &selectedId, + std::vector &nodesUnplacedSucc, + std::vector &orderedId) { + size_t i; + for (i = 0; i < orderedId.size(); i++) { + if (nodesUnplacedSucc[orderedId[i]] == 0) { + break; + } + } + selectedId = orderedId[i]; + nodesUnplacedSucc[orderedId[i]] = -1; +} + +bool allSuccInPrevLayers(std::vector &nodes, + std::vector &nodesInCurrentLayer, + TreeNode::Id id) { + bool allSuccInPrevLayers = true; + for (size_t succId : nodes[id].succ) { + if (nodesInCurrentLayer[succId]) { + allSuccInPrevLayers = false; + break; + } + } + return allSuccInPrevLayers; +} + +void algorithmCoffmanGraham(std::vector &nodes, + std::vector &sourcesNodes, + std::vector &lensLayer, size_t w) { + std::vector orderedId = {}; + getIdOrderPred(nodes, orderedId, sourcesNodes); + + std::vector> prevLayers = {}; + size_t countLayers = 0; + std::vector currentLayer = {}; + + std::vector nodesInCurrentLayer = {}; + nodesInCurrentLayer.resize(nodes.size(), false); + + std::vector nodesUnplacedSucc = {}; + for (size_t i = 0; i < nodes.size(); i++) { + nodesUnplacedSucc.push_back(static_cast(nodes[i].succ.size())); + } + + size_t placedCount = 0; + while (placedCount < nodes.size() - sourcesNodes.size()) { + TreeNode::Id selectedId; + selectIdAllSuccPlaced(selectedId, nodesUnplacedSucc, orderedId); + + if (currentLayer.size() < w && + allSuccInPrevLayers(nodes, nodesInCurrentLayer, selectedId)) { + currentLayer.push_back(selectedId); + + nodesInCurrentLayer[selectedId] = true; + } else { + prevLayers.push_back(currentLayer); + countLayers++; + + currentLayer = {}; + currentLayer.push_back(selectedId); + + nodesInCurrentLayer = {}; + nodesInCurrentLayer.resize(nodes.size(), false); + nodesInCurrentLayer[selectedId] = true; + } + + nodes[selectedId].layer = countLayers; + nodes[selectedId].number = static_cast(currentLayer.size()) - 1; + + for (size_t predId : nodes[selectedId].pred) { + nodesUnplacedSucc[predId]--; + } + + placedCount++; + } + prevLayers.push_back(currentLayer); + countLayers++; + + currentLayer = {}; + for (TreeNode::Id sourceId : sourcesNodes) { + currentLayer.push_back(sourceId); + nodes[sourceId].layer = countLayers; + nodes[sourceId].number = static_cast(currentLayer.size()) - 1; + } + prevLayers.push_back(currentLayer); + + for (TreeNode &node : nodes) { + node.layer = static_cast(prevLayers.size()) - node.layer - 1; + } + + lensLayer = {}; + for (size_t i = 0; i < prevLayers.size(); i++) { + lensLayer.push_back( + static_cast(prevLayers[prevLayers.size() - i - 1].size())); + } +} + +bool checkingNodesId(std::vector &nodes, size_t oldCountNodes) { + if (nodes.size() != oldCountNodes) { + return false; + } + for (size_t i = 0; i < nodes.size(); i++) { + if (nodes[i].id != i) { + return false; + } + } + return true; +} + +bool checkingConnection( + std::vector &nodes, + std::vector> &oldConnections) { + size_t countNewConnections = 0; + for (TreeNode &node : nodes) { + countNewConnections += node.succ.size(); + } + if (countNewConnections != oldConnections.size()) { + return false; + } + for (auto [src, dst] : oldConnections) { + if (std::find(nodes[src].succ.begin(), nodes[src].succ.end(), dst) == + nodes[src].succ.end() || + std::find(nodes[dst].pred.begin(), nodes[dst].pred.end(), src) == + nodes[dst].pred.end()) { + return false; + } + } + return true; +} + +bool checkingSuccInNextLayers(std::vector &nodes) { + for (TreeNode &node : nodes) { + for (TreeNode::Id succId : node.succ) { + if (node.layer >= nodes[succId].layer) { + return false; + } + } + } + return true; +} + +bool checkingWidthLimit(std::vector &nodes, size_t width) { + for (TreeNode &node : nodes) { + if (node.number >= width && node.layer != 0) { + return false; + } + } + return true; +} + +bool checkingCoordinates( + std::vector &nodes, + std::vector> &manuallyCoordinates) { + for (size_t i = 0; i < nodes.size(); i++) { + if (nodes[i].layer != manuallyCoordinates[i].first || + nodes[i].number != manuallyCoordinates[i].second) { + return false; + } + } + return true; +} + +bool nodesPlacedCorrectly( + std::vector &nodes, size_t width, size_t oldCountNodes, + std::vector> &oldConnections, + std::vector> &manuallyCoordinates) { + if (!checkingNodesId(nodes, oldCountNodes)) { + return false; + } + if (!checkingConnection(nodes, oldConnections)) { + return false; + } + if (cycleExistsDFS(nodes)) { + return false; + } + if (!checkingSuccInNextLayers(nodes)) { + return false; + } + if (!checkingWidthLimit(nodes, width)) { + // return false; + } + if (manuallyCoordinates.size() != 0) { + if (!checkingCoordinates(nodes, manuallyCoordinates)) { + return false; + } + } + return true; +} + +TreeNode::Id traceDummyNode(TreeNode::Id id, + const std::vector &nodes) { + while (nodes[id].isDummy == true) { + id = nodes[id].succ[0]; + } + return id; +} + +void reverseNode(std::vector &nodes, TreeNode::Id src, + TreeNode::Id dst) { + nodes[src].pred.push_back(dst); + nodes[src].succ.erase( + std::remove(nodes[src].succ.begin(), nodes[src].succ.end(), dst), + nodes[src].succ.end()); + + nodes[dst].succ.push_back(src); + nodes[dst].pred.erase( + std::remove(nodes[dst].pred.begin(), nodes[dst].pred.end(), src), + nodes[dst].pred.end()); +} + +void reverseBackwardEdges( + std::vector &nodes, + std::vector> &deletedEdges) { + for (auto [src, dst] : deletedEdges) { + bool isLong = true; + if (std::find(nodes[src].succ.begin(), nodes[src].succ.end(), dst) != + nodes[src].succ.end()) { + isLong = false; + } + if (!isLong) { + reverseNode(nodes, src, dst); + + continue; + } + + size_t firstDummyId; + for (size_t succId : nodes[src].succ) { + if (nodes[succId].isDummy) { + if (traceDummyNode(succId, nodes) == dst) { + firstDummyId = succId; + break; + } + } + } + + size_t prevId = src, nextDummyId = firstDummyId; + while (nodes[nextDummyId].isDummy) { + size_t tmpId = nodes[nextDummyId].succ[0]; + reverseNode(nodes, prevId, nextDummyId); + prevId = nextDummyId; + nextDummyId = tmpId; + } + reverseNode(nodes, prevId, dst); + } +} + +int promoteNode(std::vector &nodes, std::vector &layering, + std::vector &shiftId, bool &flagSource, size_t id) { + if (nodes[id].pred.empty() || flagSource) { + flagSource = true; + return 0; + } + int dummyDiff = 0; + for (TreeNode::Id predId : nodes[id].pred) { + if (layering[predId] == layering[id] - 1) { + dummyDiff += promoteNode(nodes, layering, shiftId, flagSource, predId); + } + } + + shiftId.push_back(id); + + dummyDiff += nodes[id].succ.size() - nodes[id].pred.size(); + return dummyDiff; +} + +void removeEmptyLayers(std::vector &nodes, + std::vector &lensLayer) { + std::vector layerDiff; + layerDiff.resize(lensLayer.size(), 0); + + int d = 0; + for (size_t i = 0; i < lensLayer.size(); ++i) { + if (lensLayer[i] == 0) { + ++d; + } else { + layerDiff[i] = d; + } + } + + if (d > 0) { + lensLayer.erase(std::remove(lensLayer.begin(), lensLayer.end(), 0), + lensLayer.end()); + for (TreeNode &node : nodes) { + node.layer -= layerDiff[node.layer]; + } + } +} + +void layeringPromotion(std::vector &nodes, + std::vector &lensLayer) { + std::vector layering = {}; + for (TreeNode &node : nodes) { + layering.push_back(node.layer); + } + std::vector shiftId = {}; + size_t promotions = 1; + while (promotions != 0) { + promotions = 0; + for (TreeNode &node : nodes) { + if (node.pred.size() > 0) { + bool flagSource = false; + shiftId = {}; + if (promoteNode(nodes, layering, shiftId, flagSource, node.id) < 0 && + !flagSource) { + for (size_t id : shiftId) { + layering[id]--; + } + promotions++; + } + } + } + } + + int minLayer = *std::min_element(layering.begin(), layering.end()); + int maxLayer = *std::max_element(layering.begin(), layering.end()); + maxLayer -= minLayer; + + lensLayer = {}; + lensLayer.resize(maxLayer + 1, 0); + + for (size_t id = 0; id < nodes.size(); id++) { + nodes[id].layer = layering[id]; + nodes[id].number = lensLayer[nodes[id].layer]; + lensLayer[nodes[id].layer]++; + } + + removeEmptyLayers(nodes, lensLayer); +} + // Assigning a layer and a number, introducing dummy vertices -void Net::assignLayers() { +void Net::assignLayers(size_t widthLimitation, bool testNodesPlacement) { + std::vector sourcesNodes = {}; + for (TreeNode &node : nodes) { + if (node.pred.size() == 0) { + sourcesNodes.push_back(node.id); + } + } + std::vector> deletedEdges = {}; greedyFAS(nodes, deletedEdges); std::vector lensLayer = {}; - algorithmASAP(nodes, deletedEdges, lensLayer); + + if (testNodesPlacement) { + size_t oldCountNodes = nodes.size(); + std::vector> oldConnections = {}; + for (TreeNode &node : nodes) { + for (TreeNode::Id succId : node.succ) { + auto connection = std::make_pair(node.id, succId); + oldConnections.push_back(connection); + } + } + std::vector> manuallyCoordinates = {}; + + algorithmCoffmanGraham(nodes, sourcesNodes, lensLayer, widthLimitation); + + if (nodesPlacedCorrectly(nodes, widthLimitation, oldCountNodes, + oldConnections, manuallyCoordinates)) { + printf("\nSuccess: Nodes are plased correctly\n"); + } else { + printf("\nFail\n"); + } + } else { + algorithmCoffmanGraham(nodes, sourcesNodes, lensLayer, widthLimitation); + } + + for (auto [src, dst] : deletedEdges) { + nodes[src].succ.push_back(dst); + nodes[dst].pred.push_back(src); + } + + reverseBackwardEdges(nodes, deletedEdges); + for (std::pair &pair : deletedEdges) { + std::swap(pair.first, pair.second); + } + + layeringPromotion(nodes, lensLayer); + + reverseBackwardEdges(nodes, deletedEdges); addAllDummyNodes(nodes, lensLayer); } @@ -361,15 +742,19 @@ enum { GetMiddle = 2 }; -void initPositionAndSize( - std::vector &nodes, - std::vector &normalizedElements, - float nCellSize) { +void initPositionAndSize(std::vector &nodes, + std::vector &normalizedElements, + float nCellSize, bool initDummy) { for (TreeNode &node : nodes) { - NormalizedElement nElement = {}; + Element nElement = {}; nElement.id = node.id; + nElement.scrType.setType(node.type); if (node.isDummy) { + if (!initDummy) { + continue; + } + NormalizedPoint nPoint = {}; nPoint.nX = nCellSize * node.number + (nCellSize / ReductionWidth) / ReductionRelationToGap; @@ -393,28 +778,36 @@ void initPositionAndSize( } } -void initConnections( - std::vector &nodes, - std::vector &normalizedElements) { +void initConnections(const std::vector &nodes, + std::vector &normalizedElements, bool initDummy) { int countConnections = 0; - for (size_t i = 0; i < nodes.size(); i++) { - for (size_t &succId : nodes[i].succ) { - NormalizedConnection connection = {}; + for (size_t i = 0; i < normalizedElements.size(); i++) { + for (size_t succId : nodes[normalizedElements[i].id].succ) { + Connection connection = {}; connection.id = countConnections; - connection.startElementId = nodes[i].id; + connection.startElementId = normalizedElements[i].id; + if (!initDummy) { + succId = traceDummyNode(succId, nodes); + } connection.endElementId = succId; NormalizedPoint nPointStart = {}; nPointStart.nX = normalizedElements[i].nPoint.nX + normalizedElements[i].nW / GetMiddle; - nPointStart.nY = normalizedElements[i].nPoint.nY + - normalizedElements[i].nH; + nPointStart.nY = + normalizedElements[i].nPoint.nY + normalizedElements[i].nH; NormalizedPoint nPointEnd = {}; - nPointEnd.nX = normalizedElements[succId].nPoint.nX + - normalizedElements[succId].nW / GetMiddle; - nPointEnd.nY = normalizedElements[succId].nPoint.nY; + size_t j; + for (j = 0; j < normalizedElements.size(); j++) { + if (normalizedElements[j].id == succId) { + break; + } + } + nPointEnd.nX = normalizedElements[j].nPoint.nX + + normalizedElements[j].nW / GetMiddle; + nPointEnd.nY = normalizedElements[j].nPoint.nY; connection.nVertices.push_back(nPointStart); connection.nVertices.push_back(nPointEnd); @@ -427,7 +820,7 @@ void initConnections( } void Net::netTreeNodesToNormalizedElements( - std::vector &normalizedElements) { + std::vector &normalizedElements, bool showDummy) { float maxNumber = -1, maxLayer = -1; for (TreeNode &node : nodes) { if (node.layer > maxLayer) { @@ -445,7 +838,7 @@ void Net::netTreeNodesToNormalizedElements( nCellSize = 1 / (maxNumber + 1); } - initPositionAndSize(nodes, normalizedElements, nCellSize); + initPositionAndSize(nodes, normalizedElements, nCellSize, showDummy); - initConnections(nodes, normalizedElements); + initConnections(nodes, normalizedElements, showDummy); } diff --git a/src/layout.h b/src/layout.h index 0bb0e6b..68a0c31 100644 --- a/src/layout.h +++ b/src/layout.h @@ -19,6 +19,7 @@ struct TreeNode { std::vector succ = {}; std::vector pred = {}; Id id = 0; + Type type = NONE; int layer = 0; int number = 0; bool isDummy = false; @@ -42,7 +43,7 @@ struct Net { const std::vector &getSuccessors(Id id) const; const std::vector &getPredecessors(Id id) const; - Id addNode(); + Id addNode(Type type); TreeNode *getNode(Id id) { const Net &net = *this; @@ -51,9 +52,10 @@ struct Net { const TreeNode *getNode(Id id) const; - void assignLayers(); + void assignLayers(size_t widthLimitation, bool testNodesPlacement); void netTreeNodesToNormalizedElements( - std::vector &normalizedElements); + std::vector &normalizedElements, + bool showDummy); std::vector> getNodesByLayer(); }; diff --git a/src/main.cpp b/src/main.cpp index 7c79ccb..8c9aa81 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,3 +1,4 @@ + //===----------------------------------------------------------------------===// // // Part of the Utopia EDA Project, under the Apache License v2.0 @@ -8,12 +9,15 @@ #define SDL_MAIN_HANDLED #include "pugixml.hpp" +#include #include #include #include - #include +#include +#include + #include "layout.h" #include "netfmt_bench.h" #include "main.h" @@ -22,7 +26,7 @@ enum StatusCode { SUCCESS = 0, FILENAME_NOT_PROVIDED, - PARSER_FAILURE, + RAW_PARSER_FAILURE, SDL_INIT_FAILURE, BENCH_READER_ERROR }; @@ -30,24 +34,52 @@ enum StatusCode { const char *statusMessages[] = { "Success\n", "Filename was not provided\n", - "Parser failure\n", - "SDL could not be initialized\n" + "Raw parser failure\n", + "SDL could not be initialized\n", + "Bench reader error\n" }; const char *const parserElementId = "e_id"; -const char *const parserConnetionId = "c_id"; +const char *const parserConnectionId = "c_id"; const char *const parserX = "x"; const char *const parserY = "y"; const char *const parserHeight = "height"; const char *const parserWidth = "width"; const char *const parserEndElement = "end_element"; +const char *const parserLogicScheme = "logic_scheme"; +const char *const parserElements = "elements"; +const char *const parserConnections = "connections"; +const char *const parserOutlineColor = "outline_color"; +const char *const parserFillColor = "fill_color"; +const char *const parserColor = "color"; +const char *const parserBackColor = "background_color"; +const char *const parserR = "r"; +const char *const parserG = "g"; +const char *const parserB = "b"; const float zoomInScalingFactor = 1.1f; const float zoomOutScalingFactor = 0.9f; const float mouseWheelScalingFactor = 0.1f; -const std::string printCompactMode = "--compact"; -const std::string printDefaultMode = "--default"; +const float inf = std::numeric_limits::infinity(); + +const unsigned int framesNum = 100; + +const std::string optionFile = "file"; +const std::string flagFPS = "--fps"; +const std::string flagRaw = "--raw"; +const std::string flagCompact = "--compact"; +const std::string flagMinimize = "--minimize"; +const std::string flagColors = "--colors"; +const std::string flagDummy = "--dummy"; +const std::string flagTexture = "--texturize"; +const std::string flagWidthLimitation = "--limit"; +const std::string flagTestNodesPlacement = "--testNodesPlacement"; + +const std::string texturePath = + std::string(ROOT_DIR) + + std::string("/assets/img/gates.bmp"); +SDL_Texture *gatesTexture = NULL; float normalizedToScreenX(const float nX, const int screenW) { return nX * screenW; @@ -57,23 +89,58 @@ float normalizedToScreenY(const float nY, const int screenH) { return nY * screenH; } -void NormalizedElement::move(const int dx, const int dy) { +void ScreenType::setType(Type type) { + switch (type) { + case INPUT: + textureRect = {0, 1838, 604, 186}; + break; + case OUTPUT: + textureRect = {988, 1838, 604, 186}; + break; + case AND: + textureRect = {0, 0, 607, 321}; + break; + case NAND: + textureRect = {832, 0, 653, 321}; + break; + case OR: + textureRect = {30, 701, 623, 321}; + break; + case NOR: + textureRect = {861, 701, 672, 321}; + break; + case NOT: + textureRect = {0, 2122, 505, 278}; + break; + case DFF: + textureRect = {0, 1176, 512, 506}; + break; + default: + break; + } +} + +Type ScreenType::getType() const { + return type; +} + +void Element::move(const int dx, const int dy) { scrRect.x += dx; scrRect.y += dy; - for (NormalizedConnection &connectionToMove : connections) { + for (Connection &connectionToMove : connections) { connectionToMove.move(dx, dy); } } -void NormalizedConnection::move(const int dx, const int dy) { +void Connection::move(const int dx, const int dy) { for (SDL_FPoint &vertexToMove : scrVertices) { vertexToMove.x += dx; vertexToMove.y += dy; } } -void NormalizedElement::scale( +void Element::scale( const float scalingFactor, const int mouseX, const int mouseY) { @@ -82,12 +149,12 @@ void NormalizedElement::scale( scrRect.w *= scalingFactor; scrRect.h *= scalingFactor; - for (NormalizedConnection &connectionToScale : connections) { + for (Connection &connectionToScale : connections) { connectionToScale.scale(scalingFactor, mouseX, mouseY); } } -void NormalizedConnection::scale( +void Connection::scale( const float scalingFactor, const int mouseX, const int mouseY) { @@ -97,7 +164,7 @@ void NormalizedConnection::scale( } } -void NormalizedConnection::normalizedToScreen( +void Connection::normalizedToScreen( const int screenW, const int screenH) { for (const NormalizedPoint &nVertex : nVertices) { @@ -108,7 +175,7 @@ void NormalizedConnection::normalizedToScreen( } } -void NormalizedElement::normalizedToScreen( +void Element::normalizedToScreen( const int screenW, const int screenH) { scrRect.x = normalizedToScreenX(nPoint.nX, screenW); @@ -117,48 +184,103 @@ void NormalizedElement::normalizedToScreen( scrRect.h = normalizedToScreenY(nH, screenH); } -void drawBackground(SDL_Renderer *renderer) { - SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); +void drawBackground(SDL_Renderer *renderer, + const SDL_Color &backgroundColor, + const bool drawColor) { + if (drawColor) { + SDL_SetRenderDrawColor(renderer, + backgroundColor.r, + backgroundColor.g, + backgroundColor.b, + SDL_ALPHA_OPAQUE); + } else { + SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); + } SDL_RenderClear(renderer); } int parseInput( - const char *filename, - std::vector &elementsToParse) { + std::istream &stream, + std::vector &elementsToParse, + SDL_Color &backgroundColor) { pugi::xml_document file; - if (!file.load_file(filename)) { - return PARSER_FAILURE; + if (!file.load(stream)) { + return RAW_PARSER_FAILURE; } - pugi::xml_node elements = file.child("logic_scheme").child("elements"); + pugi::xml_node parsedBackColor = file.child(parserLogicScheme).child(parserBackColor); + backgroundColor.r = parsedBackColor.attribute(parserR).as_int(255); + backgroundColor.g = parsedBackColor.attribute(parserG).as_int(255); + backgroundColor.b = parsedBackColor.attribute(parserB).as_int(255); + + pugi::xml_node elements = file.child(parserLogicScheme).child(parserElements); // Parsing elements from given file for (pugi::xml_node element = elements.first_child(); element; element = element.next_sibling()) { - NormalizedElement parsedElement; - parsedElement.id = atoi(element.attribute(parserElementId).value()); - parsedElement.nPoint.nX = std::stof(element.attribute(parserX).value()); - parsedElement.nPoint.nY = std::stof(element.attribute(parserY).value()); - parsedElement.nH = std::stof(element.attribute(parserHeight).value()); - parsedElement.nW = std::stof(element.attribute(parserWidth).value()); - + Element parsedElement; + parsedElement.id = element.attribute(parserElementId).as_int(-1); + parsedElement.nPoint.nX = element.attribute(parserX).as_float(); + parsedElement.nPoint.nY = element.attribute(parserY).as_float(); + parsedElement.nH = element.attribute(parserHeight).as_float(); + parsedElement.nW = element.attribute(parserWidth).as_float(); + + // Reading outline color from the document and if there is not one detected + // Defaults to cyan RGB(3, 161, 252) + pugi::xml_node outlineColor = element.child(parserOutlineColor); + if (outlineColor) { + parsedElement.outlineColor.r = outlineColor.attribute(parserR).as_int(); + parsedElement.outlineColor.g = outlineColor.attribute(parserG).as_int(); + parsedElement.outlineColor.b = outlineColor.attribute(parserB).as_int(); + } + else { + parsedElement.outlineColor.r = 3; + parsedElement.outlineColor.g = 161; + parsedElement.outlineColor.b = 252; + } + // Reading fill color from the document and if there is not one detected + // Defaults to cyan RGB(3, 161, 252) + pugi::xml_node fillColor = element.child(parserFillColor); + if (fillColor) { + parsedElement.fillColor.r = fillColor.attribute(parserR).as_int(); + parsedElement.fillColor.g = fillColor.attribute(parserG).as_int(); + parsedElement.fillColor.b = fillColor.attribute(parserB).as_int(); + } else { + parsedElement.fillColor.r = 3; + parsedElement.fillColor.g = 161; + parsedElement.fillColor.b = 252; + } // Parsing connections for given element - for (pugi::xml_node connection = element.first_child(); + pugi::xml_node connections = element.child(parserConnections); + for (pugi::xml_node connection = connections.first_child(); connection; connection = connection.next_sibling()) { - NormalizedConnection parsedConnection; - parsedConnection.id = atoi(connection.attribute(parserConnetionId).value()); + Connection parsedConnection; + parsedConnection.id = atoi(connection.attribute(parserConnectionId).value()); parsedConnection.startElementId = parsedElement.id; parsedConnection.endElementId = atoi(connection.attribute(parserEndElement).value()); + // Reading color from the document and if there is not one detected + // Defaults to black RGB(0, 0, 0) + pugi::xml_node color = connection.child(parserColor); + if (color) { + parsedConnection.color.r = color.attribute(parserR).as_int(); + parsedConnection.color.g = color.attribute(parserG).as_int(); + parsedConnection.color.b = color.attribute(parserB).as_int(); + } else { + parsedConnection.color.r = 0; + parsedConnection.color.g = 0; + parsedConnection.color.b = 0; + } // Parsing nVertices for given connection - for (pugi::xml_node vertex = connection.first_child(); + pugi::xml_node vertices = connection.child("vertices"); + for (pugi::xml_node vertex = vertices.first_child(); vertex; vertex = vertex.next_sibling()) { NormalizedPoint parsedVertex; - parsedVertex.nX = std::stof(vertex.attribute(parserX).value()); - parsedVertex.nY = std::stof(vertex.attribute(parserY).value()); + parsedVertex.nX = vertex.attribute(parserX).as_float(); + parsedVertex.nY = vertex.attribute(parserY).as_float(); parsedConnection.nVertices.push_back(parsedVertex); } parsedElement.connections.push_back(parsedConnection); @@ -170,12 +292,12 @@ int parseInput( std::ostream &operator<<( std::ostream &out, - const NormalizedElement &elementToPrint) { + const Element &elementToPrint) { out << "Element id: " << elementToPrint.id << " x: " << elementToPrint.nPoint.nX << " y: " << elementToPrint.nPoint.nY << std::endl; - for (const NormalizedConnection &connection : elementToPrint.connections) { + for (const Connection &connection : elementToPrint.connections) { out << " Connection id: " << connection.id; for (size_t i = 0; i < connection.nVertices.size(); i++) { out << " x" << i << ": " << connection.nVertices[i].nX @@ -187,11 +309,11 @@ std::ostream &operator<<( } void print( - const std::string &printMode, - const std::vector &elementsToPrint) { - if (printMode == printCompactMode) { + const std::vector &elementsToPrint, + bool printCompact) { + if (printCompact) { size_t connectionsCount = 0; - for (const NormalizedElement &element : elementsToPrint) { + for (const Element &element : elementsToPrint) { connectionsCount += element.connections.size(); } std::cout << "Number of elements: " @@ -199,43 +321,168 @@ void print( << "\nNumber of connections: " << connectionsCount << std::endl; - } else if (printMode == printDefaultMode) { - for (const NormalizedElement &element : elementsToPrint) { + } else { + for (const Element &element : elementsToPrint) { std::cout << element; } } } void convertNormToScreen( - std::vector &elementsToConvert, + std::vector &elementsToConvert, const int screenW, const int screenH) { // Converting normalized coordinates to screen - for (NormalizedElement &nElem : elementsToConvert) { + for (Element &nElem : elementsToConvert) { nElem.normalizedToScreen(screenW, screenH); - for (NormalizedConnection &nConnection : nElem.connections) { + for (Connection &nConnection : nElem.connections) { nConnection.normalizedToScreen(screenW, screenH); } } } +float maxi(const float arr[], int n) { + float m = 0; + for (int i = 0; i < n; ++i) + if (m < arr[i]) + m = arr[i]; + return m; +} + +float mini(const float arr[], int n) { + float m = 1; + for (int i = 0; i < n; ++i) + if (m > arr[i]) + m = arr[i]; + return m; +} + +bool checkSegmentRectCollision( + SDL_FPoint &point1, + SDL_FPoint &point2, + const int screenW, + const int screenH) { + float x1 = point1.x; + float y1 = point1.y; + float x2 = point2.x; + float y2 = point2.y; + + float p1 = -(x2 - x1); + float p2 = -p1; + float p3 = -(y2 - y1); + float p4 = -p3; + + float q1 = x1; + float q2 = screenW - x1; + float q3 = y1; + float q4 = screenH - y1; + + float posarr[5], negarr[5]; + int posind = 1, negind = 1; + posarr[0] = 1; + negarr[0] = 0; + + if ((p1 == 0 && q1 < 0) || (p3 == 0 && q3 < 0)) { + return false; + } + if (p1 != 0) { + float r1 = q1 / p1; + float r2 = q2 / p2; + if (p1 < 0) { + negarr[negind++] = r1; + posarr[posind++] = r2; + } else { + negarr[negind++] = r2; + posarr[posind++] = r1; + } + } + if (p3 != 0) { + float r3 = q3 / p3; + float r4 = q4 / p4; + if (p3 < 0) { + negarr[negind++] = r3; + posarr[posind++] = r4; + } else { + negarr[negind++] = r4; + posarr[posind++] = r3; + } + } + float rn1, rn2; + + rn1 = maxi(negarr, negind); + rn2 = mini(posarr, posind); + + if (rn1 > rn2) { + return false; + } + point1.x = x1 + p2 * rn1; + point1.y = y1 + p4 * rn1; + + point2.x = x1 + p2 * rn2; + point2.y = y1 + p4 * rn2; + + return true; +} + void drawFrame( SDL_Renderer *renderer, - const std::vector &elementsToDraw) { - drawBackground(renderer); + const std::vector &elementsToDraw, + const SDL_Color &backgroundColor, + const int screenW, + const int screenH, + const bool drawColor, + const bool texturize) { + drawBackground(renderer, backgroundColor, drawColor); SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE); - for (const NormalizedElement &elementToDraw : elementsToDraw) { - SDL_RenderDrawRectF(renderer, &elementToDraw.scrRect); - for (const NormalizedConnection &connectionToDraw : elementToDraw.connections) { + for (const Element &elementToDraw : elementsToDraw) { + if (drawColor && !texturize) { + SDL_SetRenderDrawColor(renderer, + elementToDraw.fillColor.r, + elementToDraw.fillColor.g, + elementToDraw.fillColor.b, + SDL_ALPHA_OPAQUE); + SDL_RenderFillRectF(renderer, &elementToDraw.scrRect); + + SDL_SetRenderDrawColor(renderer, + elementToDraw.outlineColor.r, + elementToDraw.outlineColor.g, + elementToDraw.outlineColor.b, + SDL_ALPHA_OPAQUE); + } + if (texturize) { + SDL_RenderCopyF(renderer, + gatesTexture, + &elementToDraw.scrType.textureRect, + &elementToDraw.scrRect); + } else { + SDL_RenderDrawRectF(renderer, &elementToDraw.scrRect); + } + for (const Connection &connectionToDraw : elementToDraw.connections) { + if (drawColor) { + SDL_SetRenderDrawColor(renderer, + connectionToDraw.color.r, + connectionToDraw.color.g, + connectionToDraw.color.b, + SDL_ALPHA_OPAQUE); + } for (size_t i = 1; i < connectionToDraw.scrVertices.size(); i++) { - SDL_RenderDrawLineF(renderer, - connectionToDraw.scrVertices[i - 1].x, - connectionToDraw.scrVertices[i - 1].y, - connectionToDraw.scrVertices[i].x, - connectionToDraw.scrVertices[i].y); + SDL_FPoint point1 = connectionToDraw.scrVertices[i - 1]; + SDL_FPoint point2 = connectionToDraw.scrVertices[i]; + + bool collision = checkSegmentRectCollision(point1, + point2, + screenW, + screenH); + if (collision) { + SDL_RenderDrawLineF(renderer, + point1.x, + point1.y, + point2.x, + point2.y); + } } } } @@ -244,11 +491,11 @@ void drawFrame( void scaleViewport( const float scalingFactor, - std::vector &elementsToScale) { + std::vector &elementsToScale) { int mouseX, mouseY; SDL_GetMouseState(&mouseX, &mouseY); - for (NormalizedElement &elementToScale : elementsToScale) { + for (Element &elementToScale : elementsToScale) { elementToScale.scale(scalingFactor, mouseX, mouseY); } } @@ -256,8 +503,8 @@ void scaleViewport( void moveViewport( const int dx, const int dy, - std::vector &elementsToScale) { - for (NormalizedElement &elementToScale : elementsToScale) { + std::vector &elementsToScale) { + for (Element &elementToScale : elementsToScale) { elementToScale.move(dx, dy); } } @@ -266,35 +513,111 @@ float scaleMouseWheel(const Sint32 mouseWheelY) { return 1 + mouseWheelY * mouseWheelScalingFactor; } -int main(int argc, char *argv[]) { - // Parse text file - if (argc < 2) { - std::cerr << statusMessages[FILENAME_NOT_PROVIDED]; - return FILENAME_NOT_PROVIDED; - } - - std::string printMode = printDefaultMode; - if (argc >= 3) { - printMode = argv[2]; - } - - Net net = {}; - std::ifstream ifs(argv[1]); - if (!readNetFromBench(ifs, net)) { - return BENCH_READER_ERROR; +void defaultColor(std::vector &elementsToColor, SDL_Color &backgroundColor) { + for (Element &elementToColor : elementsToColor) { + elementToColor.fillColor = {3, 161, 252, 255}; + elementToColor.outlineColor = {3, 161, 252, 255}; + for (Connection &connectionToColor : elementToColor.connections) { + connectionToColor.color = {0, 0, 0, 255}; + } } + backgroundColor = {255, 255, 255, 255}; +} - net.assignLayers(); - minimizeIntersections(net); - std::vector normalizedElements = {}; - net.netTreeNodesToNormalizedElements(normalizedElements); - +int main(int argc, char *argv[]) { + std::cout << ROOT_DIR; + CLI::App cliApp; + + std::string filename; + cliApp.add_option(optionFile, + filename, + "File to parse")->required(); + + bool parseRaw = false; + auto cliRaw = cliApp.add_flag(flagRaw, + parseRaw, + "Parse graph represented as FLG file"); + + bool printCompact = false; + cliApp.add_flag(flagCompact, + printCompact, + "Print quantity of elements and connections"); + + bool drawColor = false; + cliApp.add_flag(flagColors, + drawColor, + "Draw color"); + + bool showFPS = false; + cliApp.add_flag(flagFPS, + showFPS, + "Show average frame time, FPS and BENCH file processing time"); + + bool processMinimize = false; + cliApp.add_flag(flagMinimize, + processMinimize, + "Minimize intersections")->excludes(cliRaw); + + bool showDummy = false; + cliApp.add_flag(flagDummy, + showDummy, + "Show dummy nodes")->excludes(cliRaw); + + bool texturize = false; + cliApp.add_flag(flagTexture, + texturize, + "Texturize nodes"); + + size_t widthLimitation = 1000; + cliApp.add_option(flagWidthLimitation, + widthLimitation, + "Graph width limitation"); + + bool testNodesPlacement = false; + cliApp.add_flag(flagTestNodesPlacement, + testNodesPlacement, + "Testing nodes placement"); + + CLI11_PARSE(cliApp, argc, argv); + + std::ifstream ifs(filename); + std::vector normalizedElements = {}; + SDL_Color backgroundColor; + if (parseRaw) { + if (parseInput(ifs, normalizedElements, backgroundColor)) { + std::cerr << statusMessages[RAW_PARSER_FAILURE]; + return RAW_PARSER_FAILURE; + } + } else { + Net net = {}; + if (!readNetFromBench(ifs, net)) { + std::cerr << statusMessages[BENCH_READER_ERROR]; + return BENCH_READER_ERROR; + } + auto start = std::chrono::high_resolution_clock::now(); + net.assignLayers(widthLimitation, testNodesPlacement); + if (processMinimize) { + minimizeIntersections(net); + } + net.netTreeNodesToNormalizedElements(normalizedElements, showDummy); + auto stop = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(stop - start).count(); + if (showFPS) { + std::cout << "BENCH processing time: " + << duration + << " ms." + << std::endl; + } + defaultColor(normalizedElements, backgroundColor); + } // Prepare draw data and draw if (SDL_Init(SDL_INIT_VIDEO) < 0) { std::cerr << statusMessages[SDL_INIT_FAILURE]; return SDL_INIT_FAILURE; } + print(normalizedElements, printCompact); + std::cout << statusMessages[SUCCESS]; // Get screen dimensions @@ -307,9 +630,12 @@ int main(int argc, char *argv[]) { SDL_CreateWindow("test-viz", 0, 0, screenW, screenH, SDL_WINDOW_SHOWN); SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + SDL_Surface *gatesSurface = SDL_LoadBMP(texturePath.c_str()); + gatesTexture = SDL_CreateTextureFromSurface(renderer, gatesSurface); + SDL_FreeSurface(gatesSurface); convertNormToScreen(normalizedElements, screenW, screenH); - drawFrame(renderer, normalizedElements); + drawFrame(renderer, normalizedElements, backgroundColor, screenW, screenH, drawColor, texturize); // Event loop bool isRunning = true; @@ -318,7 +644,26 @@ int main(int argc, char *argv[]) { int mouseY1 = 0; int mouseX2 = 0; int mouseY2 = 0; + + auto start = std::chrono::high_resolution_clock::now(); + unsigned int count = 0; while (isRunning) { + if (count == framesNum) { + auto stop = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(stop - start).count(); + auto avgFrameTime = duration / count; + auto avgFPS = 1000/avgFrameTime; + start = std::chrono::high_resolution_clock::now(); + count = 0; + if (showFPS) { + std::cout << "Avg frame time: " + << avgFrameTime + << " ms. FPS:" + << avgFPS + << std::endl; + } + } + count++; SDL_Event event; // User input handler while (SDL_PollEvent(&event)) { @@ -335,7 +680,6 @@ int main(int argc, char *argv[]) { mouseY2 = 0; } else if (isDragging && SDL_GetMouseState(&mouseX2, &mouseY2)) { moveViewport(mouseX2 - mouseX1, mouseY2 - mouseY1, normalizedElements); - drawFrame(renderer, normalizedElements); SDL_GetMouseState(&mouseX1, &mouseY1); } else if (event.type == SDL_KEYDOWN) { // Keyboard input handler @@ -350,15 +694,16 @@ int main(int argc, char *argv[]) { isRunning = false; break; } - drawFrame(renderer, normalizedElements); } else if (event.type == SDL_MOUSEWHEEL) { scaleViewport(scaleMouseWheel(event.wheel.y), normalizedElements); - drawFrame(renderer, normalizedElements); } } + drawFrame(renderer, normalizedElements, backgroundColor, screenW, screenH, drawColor, texturize); } // Shutdown SDL_DestroyWindow(window); + SDL_DestroyRenderer(renderer); + SDL_DestroyTexture(gatesTexture); SDL_Quit(); return 0; } diff --git a/src/main.h b/src/main.h index 8af0ddb..f8bc53f 100644 --- a/src/main.h +++ b/src/main.h @@ -11,6 +11,29 @@ #include +enum Type { + NONE = 0, + INPUT, + OUTPUT, + NOT, + AND, + OR, + NAND, + NOR, + DFF +}; + +struct ScreenType { + SDL_Rect textureRect; + + ScreenType(): type(NONE) {} + void setType(Type type); + Type getType() const; + +private: + Type type; +}; + struct NormalizedPoint { float nX; float nY; @@ -18,27 +41,36 @@ struct NormalizedPoint { NormalizedPoint(): nX(0), nY(0) {} }; -struct NormalizedConnection { +struct Connection { unsigned int id; unsigned int startElementId; unsigned int endElementId; + SDL_Color color; std::vector nVertices; std::vector scrVertices; - NormalizedConnection(): id(-1), startElementId(-1), endElementId(-1) {} + Connection(): id(-1), startElementId(-1), endElementId(-1) { + color = {255, 255, 255, 255}; + } void normalizedToScreen(const int screenW, const int screenH); void scale(const float scalingFactor, const int mouseX, const int mouseY); void move(const int dx, const int dy); }; -struct NormalizedElement { +struct Element { unsigned int id; NormalizedPoint nPoint; float nW, nH; SDL_FRect scrRect; - std::vector connections; + SDL_Color outlineColor; + SDL_Color fillColor; + std::vector connections; + ScreenType scrType; - NormalizedElement(): id(-1), nW(0), nH(0) {} + Element(): id(-1), nW(0), nH(0) { + outlineColor = {255, 255, 255, 255}; + fillColor = {0, 0, 0, 255}; + } void normalizedToScreen(const int screenW, const int screenH); void scale(const float scalingFactor, const int mouseX, const int mouseY); void move(const int dx, const int dy); diff --git a/src/minimization.cpp b/src/minimization.cpp index 9057d17..f4cb0ce 100644 --- a/src/minimization.cpp +++ b/src/minimization.cpp @@ -127,7 +127,7 @@ int AdditionalNetFeatures::crossCounting() { for (size_t i = 0; i < netEdges.size(); ++i) { std::sort(netEdges[i].begin(), netEdges[i].end(), lexicographicSortCondition); - const int numLeaves = nearestPow2(netEdges[i].size()); + const int numLeaves = nearestPow2(nodesByLayer[i + 1].size()); const int firstLeafIndex = numLeaves - 1; const int treeSize = numLeaves * 2 - 1; @@ -136,6 +136,9 @@ int AdditionalNetFeatures::crossCounting() { for (size_t k = 0; k < netEdges[i].size(); k++) { int index = netEdges[i][k].second -> number + firstLeafIndex; + // if (index > accTree.size()) { + // printf("Out of size\n"); + // } ++accTree[index]; while (index > 0) { if (index % 2) @@ -282,4 +285,4 @@ void minimizeIntersections(Net &net) { portOrderOptimization(net, features.nodesByLayer); printf("\nintersections: %i\n", features.intersections); -} \ No newline at end of file +} diff --git a/src/netfmt_bench.cpp b/src/netfmt_bench.cpp index f44316b..7963cf0 100644 --- a/src/netfmt_bench.cpp +++ b/src/netfmt_bench.cpp @@ -30,15 +30,15 @@ class BenchNetReader: public lorina::bench_reader { } virtual void on_input(const std::string &name) const override { - UNUSED(getNode(name)); + UNUSED(getNode(name, INPUT)); } virtual void on_output(const std::string &name) const override { - UNUSED(getNode(name)); + UNUSED(getNode(name, OUTPUT)); } virtual void on_dff_input(const std::string &input) const override { - UNUSED(getNode(input)); + UNUSED(getNode(input, DFF)); } virtual void on_dff( @@ -50,9 +50,19 @@ class BenchNetReader: public lorina::bench_reader { const std::vector &inputs, const std::string &output, const std::string &type) const override { - UNUSED(type); - - TreeNode *dst = getNode(output); + Type numType = NONE; + if (type == "NOT") { + numType = NOT; + } else if (type == "AND") { + numType = AND; + } else if (type == "OR") { + numType = OR; + } else if (type == "NAND") { + numType = NAND; + } else if (type == "NOR") { + numType = NOR; + } + TreeNode *dst = getNode(output, numType); for (const std::string &input: inputs) { linkNodes(getNode(input), dst); } @@ -69,14 +79,14 @@ class BenchNetReader: public lorina::bench_reader { dst->pred.push_back(src->id); } - TreeNode *getNode(const std::string &name) const { + TreeNode *getNode(const std::string &name, Type type = NONE) const { Net::Id id; auto it = nodeMap.find(name); if (it != nodeMap.end()) { id = it->second; } else { - id = net.addNode(); + id = net.addNode(type); nodeMap.emplace(name, id); } return net.getNode(id); diff --git a/test/bench.cpp b/test/bench.cpp index 5555aac..cd21a33 100644 --- a/test/bench.cpp +++ b/test/bench.cpp @@ -52,6 +52,7 @@ class bench_statistics_reader : public bench_reader { gate_lines.emplace_back( inputs, output, type ); ++_stats.number_of_lines; + std::cout << type << std::endl; } virtual void on_assign( const std::string& input, const std::string& output ) const override diff --git a/test/test.xml b/test/test.xml index 72d1827..91ea630 100644 --- a/test/test.xml +++ b/test/test.xml @@ -1,34 +1,58 @@ + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + - - - - + + + + + + + +