]> Some of my projects - graph.git/commitdiff
Done
authorAPTX <marek321@gmail.com>
Thu, 15 Dec 2011 20:19:55 +0000 (21:19 +0100)
committerAPTX <marek321@gmail.com>
Thu, 15 Dec 2011 20:19:55 +0000 (21:19 +0100)
12 files changed:
edge.cpp
edge.h
graph.cpp
graph.h
mainwindow.cpp
mainwindow.h
mainwindow.ui
node.cpp
node.h
nodemodel.cpp
pmc.cpp
pmc.h

index beb35b538a97a51d9a24f9b8d9c7de098d582de3..f8bdd21ceb415adc8f1d4d306f57e65991a41da9 100644 (file)
--- a/edge.cpp
+++ b/edge.cpp
@@ -14,16 +14,57 @@ void Edge::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWid
 {
        Q_UNUSED(option);
        Q_UNUSED(widget);
-       painter->setPen(m_color);
-       painter->drawLine(m_startNode->pos(), m_endNode->pos());
+
+       static const double Pi = 3.14159265358979323846264338327950288419717;
+       static double TwoPi = 2.0 * Pi;
+
+       QPointF sourcePoint = m_startNode->pos();
+       QPointF destPoint = m_endNode->pos();
+
+       {
+               QLineF line(sourcePoint, destPoint);
+               qreal length = line.length();
+
+               if (length <= Node::size)
+                       return;
+
+               prepareGeometryChange();
+
+               QPointF edgeOffset((line.dx() * Node::size / 2) / length, (line.dy() * Node::size / 2) / length);
+               sourcePoint = line.p1() + edgeOffset;
+               destPoint = line.p2() - edgeOffset;
+       }
+       QLineF line(sourcePoint, destPoint);
+
+       // Draw the line itself
+       painter->setPen(QPen(m_color, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
+       painter->drawLine(line);
+
+       // Draw the arrows
+       double angle = ::acos(line.dx() / line.length());
+       if (line.dy() >= 0)
+               angle = TwoPi - angle;
+       QPointF destArrowP1 = destPoint + QPointF(sin(angle - Pi / 3) * arrowSize,
+                                                                                         cos(angle - Pi / 3) * arrowSize);
+       QPointF destArrowP2 = destPoint + QPointF(sin(angle - Pi + Pi / 3) * arrowSize,
+                                                                                         cos(angle - Pi + Pi / 3) * arrowSize);
+
+       painter->setBrush(m_color);
+       painter->drawPolygon(QPolygonF() << line.p1());
+       painter->drawPolygon(QPolygonF() << line.p2() << destArrowP1 << destArrowP2);
+
 //     painter->drawText(boundingRect(), Qt::AlignCenter, QString::number(m_weight));
 }
 
 QRectF Edge::boundingRect() const
 {
-       QPointF tl(qMin(m_startNode->x(), m_endNode->x()), qMin(m_startNode->y(), m_endNode->y()));
-       QPointF br(qMax(m_startNode->x(), m_endNode->x()), qMax(m_startNode->y(), m_endNode->y()));
-       return QRectF(tl, br);
+       qreal penWidth = 1;
+       qreal extra = (penWidth + arrowSize) / 2.0;
+
+       return QRectF(m_startNode->pos(), QSizeF(m_endNode->pos().x() - m_startNode->pos().x(),
+                                                                         m_endNode->pos().y() - m_startNode->pos().y()))
+               .normalized()
+               .adjusted(-extra, -extra, extra, extra);
 }
 
 QPainterPath Edge::shape() const
diff --git a/edge.h b/edge.h
index 90b8cee7cdb9d57ca8bb874771e5a0f2e15e3707..64b94f8d04584549a4154f52035f63dc4b83b6c9 100644 (file)
--- a/edge.h
+++ b/edge.h
@@ -63,6 +63,8 @@ private:
        QColor m_color;
        Node *m_startNode;
        Node *m_endNode;
+
+       static const int arrowSize = 10;
 };
 
 QDataStream &operator<<(QDataStream &s, const Edge &edge);
index 8c632024f60985c9e2f36f91f65f1384ada0d282..b3af7ef19a7d24df41c58557d0819beaca6a591d 100644 (file)
--- a/graph.cpp
+++ b/graph.cpp
@@ -10,7 +10,7 @@
 
 Graph::Graph(QObject *parent) :
        QGraphicsScene(parent), m_nodeModel(new NodeModel(this, this)),
-       m_edgeModel(new EdgeModel(this, this)), m_mode(EditMode), lastNode(1), startNode(0)
+       m_edgeModel(new EdgeModel(this, this)), m_mode(EditMode), m_addBothEdges(false), lastNode(1), startNode(0)
 {
 
 }
@@ -74,6 +74,7 @@ Node *Graph::addNode(const QPointF &pos, const QString &label, const QColor &col
        m_nodeList.append(node);
        addItem(node);
        m_nodeModel->endInsertRows();
+       emit graphChanged();
        return node;
 }
 
@@ -94,6 +95,7 @@ Edge *Graph::addEdge(Node *start, Node *end, int weight, const QColor &color)
        m_edgeList.append(edge);
        addItem(edge);
        m_edgeModel->endInsertRows();
+       emit graphChanged();
        return edge;
 }
 
@@ -113,6 +115,7 @@ void Graph::removeNode(Node *node)
        m_nodeList.removeAt(i);
        m_nodeModel->endRemoveRows();
        node->deleteLater();
+       emit graphChanged();
 }
 
 void Graph::removeEdge(Edge *edge)
@@ -129,6 +132,7 @@ void Graph::removeEdge(Edge *edge)
        m_edgeList.removeAt(i);
        m_edgeModel->endRemoveRows();
        edge->deleteLater();
+       emit graphChanged();
 }
 
 void Graph::clear()
@@ -141,6 +145,7 @@ void Graph::clear()
 
        lastNode = 1;
        startNode = 0;
+       emit graphChanged();
 }
 
 void Graph::save(QIODevice *dev) const
@@ -204,7 +209,13 @@ bool Graph::load(QIODevice *dev)
 
        m_nodeModel->reset();
        m_edgeModel->reset();
-       return false;
+       return true;
+}
+
+void Graph::update(const QRectF &rect)
+{
+       nodeColorChanged();
+       QGraphicsScene::update(rect);
 }
 
 void Graph::mousePressEvent(QGraphicsSceneMouseEvent *event)
@@ -253,7 +264,8 @@ void Graph::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
                                if (startNode != node)
                                {
                                        addEdge(startNode, node);
-                                       addEdge(node, startNode);
+                                       if (m_addBothEdges)
+                                               addEdge(node, startNode);
                                }
                                startNode = 0;
                        }
@@ -282,6 +294,12 @@ void Graph::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
        event->ignore();
 }
 
+void Graph::nodeColorChanged() const
+{
+       m_nodeModel->dataChanged(m_nodeModel->index(0, 1), m_nodeModel->index(m_nodeList.count() - 1, 1));
+       labelChanged();
+}
+
 void Graph::labelChanged() const
 {
        m_edgeModel->dataChanged(m_edgeModel->index(0, 0), m_edgeModel->index(m_edgeList.count() - 1, 1));
diff --git a/graph.h b/graph.h
index 5e2ec643104247b049260469033c90a11412b65f..9df696a6060ff441532c22bab555b6936ee1f51a 100644 (file)
--- a/graph.h
+++ b/graph.h
@@ -14,6 +14,7 @@ class Graph : public QGraphicsScene
        friend EdgeModel;
     Q_OBJECT
        Q_PROPERTY(Mode mode READ mode WRITE setMode)
+       Q_PROPERTY(bool addBothEdges READ addBothEdges WRITE setAddBothEdges)
 
 public:
        enum Mode {
@@ -35,7 +36,13 @@ public:
                return m_mode;
        }
 
+       bool addBothEdges() const
+       {
+               return m_addBothEdges;
+       }
+
 signals:
+       void graphChanged();
     
 public slots:
        void complete();
@@ -50,17 +57,28 @@ public slots:
        void setMode(Mode mode)
        {
                m_mode = mode;
+               startNode = 0;
        }
 
+       void setAddBothEdges(bool arg)
+       {
+               m_addBothEdges = arg;
+       }
+
+
        void save(QIODevice *dev) const;
        bool load(QIODevice *dev);
 
+       void update(const QRectF &rect = QRectF());
+
+
 protected:
        void mousePressEvent(QGraphicsSceneMouseEvent *event);
        void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
        void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
 
 private:
+       void nodeColorChanged() const;
        void labelChanged() const;
 
        NodeList m_nodeList;
@@ -75,6 +93,7 @@ private:
 
        // For adding edges
        Node *startNode;
+       bool m_addBothEdges;
 };
 #else
 class Graph;
index ab5f00a1709d0602c362b63baf430300ed5fa7fa..e920570b4f97207d353b04aa0a360c1c95cc17b0 100644 (file)
@@ -25,6 +25,7 @@ MainWindow::MainWindow(QWidget *parent) :
        modes->addAction(ui->actionEditMode);
        modes->addAction(ui->actionAddNodeMode);
        modes->addAction(ui->actionAddEdgeMode);
+       modes->addAction(ui->actionAddBothEdgeMode);
        modes->addAction(ui->actionRemoveMode);
        ui->actionEditMode->setChecked(true);
        ui->modeToolBar->addActions(modes->actions());
@@ -38,7 +39,11 @@ MainWindow::MainWindow(QWidget *parent) :
        pmc = new PMC(graph, this);
 
        connect(modes, SIGNAL(triggered(QAction*)), this, SLOT(modeChanged(QAction*)));
+       connect(graph, SIGNAL(graphChanged()), this, SLOT(graphChanged()));
+       connect(pmc, SIGNAL(log(QString)), this, SLOT(pmcLog(QString)));
 
+       graph->setSceneRect(QRectF(-500, -500, 1000, 1000));
+/*
        Node *n1, *n2;
        Edge *e;
        n1 = graph->addNode();
@@ -49,7 +54,7 @@ MainWindow::MainWindow(QWidget *parent) :
 
        e = graph->addEdge(n1, n2);
        e->setColor(QColor(0,0,255));
-
+*/
        nodeProxy = new QSortFilterProxyModel(this);
        edgeProxy = new QSortFilterProxyModel(this);
 
@@ -74,13 +79,35 @@ void MainWindow::modeChanged(QAction *action)
        if (action == ui->actionAddNodeMode)
                graph->setMode(Graph::AddNodeMode);
        else if (action == ui->actionAddEdgeMode)
+       {
+               graph->setMode(Graph::AddEdgeMode);
+               graph->setAddBothEdges(false);
+       }
+       else if (action == ui->actionAddBothEdgeMode)
+       {
                graph->setMode(Graph::AddEdgeMode);
+               graph->setAddBothEdges(true);
+       }
        else if (action == ui->actionRemoveMode)
                graph->setMode(Graph::RemoveNode);
        else
                graph->setMode(Graph::EditMode);
 }
 
+void MainWindow::graphChanged()
+{
+       if (pmc->finished())
+               ui->pmcLog->clear();
+       pmc->reset();
+       updateLabels();
+}
+
+void MainWindow::pmcLog(const QString &log)
+{
+       ui->pmcLog->append(log);
+//     qDebug() << log;
+}
+
 void MainWindow::on_actionNew_triggered()
 {
        graph->clear();
@@ -177,12 +204,35 @@ void MainWindow::on_actionClearAll_triggered()
        graph->clear();
 }
 
+void MainWindow::on_m_valueChanged(int m)
+{
+       pmc->setM(m);
+}
 
+void MainWindow::on_pmcRun_clicked()
+{
+       pmc->setM(ui->m->value());
+       pmc->run();
+       ui->statusBar->showMessage(tr("PMC run complete"));
+       updateLabels();
+       graph->update();
+}
 
 void MainWindow::on_pmcStep_clicked()
 {
+       pmc->setM(ui->m->value());
        if (pmc->step())
                ui->statusBar->showMessage(tr("Last Step complete"));
        else
                ui->statusBar->showMessage(tr("Step complete"));
+       updateLabels();
+       graph->update();
+}
+
+
+void MainWindow::updateLabels()
+{
+       ui->mRange->setText(QString("0..%1").arg(pmc->maxM()));
+       ui->pmcFailed->setText(pmc->failed() ? "<b><font color=\"red\">Yes" : "<b><font color=\"green\">No");
+       ui->pmcFinished->setText(pmc->finished() ? "<b><font color=\"green\">Yes" : "<b>No");
 }
index 67c0983d15436018c099f3f57f00984ad62d7b03..fd2f0e48d29b2b838685673ac8fbcc47c7ae3a1b 100644 (file)
@@ -23,6 +23,8 @@ public:
     
 private slots:
        void modeChanged(QAction *action);
+       void graphChanged();
+       void pmcLog(const QString &log);
 
        void on_actionNew_triggered();
        void on_actionOpen_triggered();
@@ -35,9 +37,13 @@ private slots:
        void on_actionGenerateGraph_triggered();
        void on_actionClearAll_triggered();
 
+       void on_m_valueChanged(int m);
+       void on_pmcRun_clicked();
        void on_pmcStep_clicked();
 
 private:
+       void updateLabels();
+
     Ui::MainWindow *ui;
 
        QSortFilterProxyModel *nodeProxy;
index d60cdba551d1224902aec6dc55f507ccaf570d8f..f25c5280311e08acb7aac1be29a37914ee46f934 100644 (file)
   <widget class="QDockWidget" name="dockWidget">
    <property name="minimumSize">
     <size>
-     <width>80</width>
+     <width>365</width>
      <height>195</height>
     </size>
    </property>
     <number>8</number>
    </attribute>
    <widget class="QWidget" name="dockWidgetContents_3">
-    <widget class="QPushButton" name="pmcStep">
-     <property name="geometry">
-      <rect>
-       <x>70</x>
-       <y>0</y>
-       <width>75</width>
-       <height>23</height>
-      </rect>
-     </property>
-     <property name="text">
-      <string>Step</string>
-     </property>
-    </widget>
+    <layout class="QHBoxLayout" name="horizontalLayout_3">
+     <item>
+      <layout class="QVBoxLayout" name="verticalLayout_4">
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_2">
+         <item>
+          <widget class="QPushButton" name="pmcRun">
+           <property name="text">
+            <string>Run</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="pmcStep">
+           <property name="text">
+            <string>Step</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <widget class="QGroupBox" name="groupBox">
+         <property name="title">
+          <string>Input</string>
+         </property>
+         <layout class="QFormLayout" name="formLayout">
+          <item row="0" column="0">
+           <widget class="QLabel" name="label_2">
+            <property name="text">
+             <string>m range:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="1">
+           <widget class="QLabel" name="mRange">
+            <property name="text">
+             <string>0..1</string>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="0">
+           <widget class="QLabel" name="label">
+            <property name="text">
+             <string>m:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="1">
+           <widget class="QSpinBox" name="m">
+            <property name="value">
+             <number>2</number>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <spacer name="verticalSpacer">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </item>
+     <item>
+      <widget class="QGroupBox" name="groupBox_2">
+       <property name="title">
+        <string>Log</string>
+       </property>
+       <layout class="QHBoxLayout" name="horizontalLayout">
+        <item>
+         <widget class="QTextEdit" name="pmcLog">
+          <property name="readOnly">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item>
+      <layout class="QVBoxLayout" name="verticalLayout_5">
+       <item>
+        <widget class="QGroupBox" name="groupBox_3">
+         <property name="title">
+          <string>Status:</string>
+         </property>
+         <layout class="QFormLayout" name="formLayout_2">
+          <item row="0" column="0">
+           <widget class="QLabel" name="label_3">
+            <property name="text">
+             <string>Finished:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="1">
+           <widget class="QLabel" name="pmcFinished">
+            <property name="text">
+             <string>No</string>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="0">
+           <widget class="QLabel" name="label_4">
+            <property name="text">
+             <string>Failed:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="1">
+           <widget class="QLabel" name="pmcFailed">
+            <property name="text">
+             <string>No</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <spacer name="verticalSpacer_2">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </item>
+    </layout>
    </widget>
   </widget>
   <action name="actionEditMode">
     <string>Ctrl+Shift+S</string>
    </property>
   </action>
+  <action name="actionAddBothEdgeMode">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>Add Both Edges Mode</string>
+   </property>
+   <property name="toolTip">
+    <string>Add Both Edges Mode</string>
+   </property>
+  </action>
  </widget>
  <layoutdefault spacing="6" margin="11"/>
  <resources/>
index ab17af3e8068d0bffb8a7a88d5a083867edee688..28cc07c0bd93c07f294ad77c33de59fdc823321f 100644 (file)
--- a/node.cpp
+++ b/node.cpp
@@ -15,8 +15,10 @@ void Node::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWid
        Q_UNUSED(option);
        Q_UNUSED(widget);
 
-       QBrush b(m_color);
-       painter->setBrush(b);
+       QRadialGradient gradient(-3, -3, 10);
+       gradient.setColorAt(0, Qt::white);
+       gradient.setColorAt(1, m_color);
+       painter->setBrush(gradient);
        painter->drawEllipse(QRectF(-size/2, -size/2, size, size));
        painter->drawText(QPointF(size/2, size), m_label);
 }
diff --git a/node.h b/node.h
index 7b1be17becec228df5f976e7ab4fe445bdaee411..7e8f3ab3f8a3567caba9febb6521128d5bab86c3 100644 (file)
--- a/node.h
+++ b/node.h
@@ -63,6 +63,9 @@ public slots:
                m_color = color;
        }
 
+public:
+       static const qreal size;
+
 private:
        QString m_label;
        QColor m_color;
@@ -70,7 +73,6 @@ private:
        EdgeList m_outgoingEdges;
        EdgeList m_incomingEdges;
 
-       static const qreal size;
 };
 
 QDataStream &operator<<(QDataStream &s, const Node &node);
index 10a7d77973cef33479ed0f0394ce359302c08f76..20bde30057ae41fa37862c9c7a20116d234f1537 100644 (file)
@@ -13,7 +13,9 @@ NodeModel::NodeModel(Graph *graph, QObject *parent) :
 
 Qt::ItemFlags NodeModel::flags(const QModelIndex &index) const
 {
-       return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
+       if (index.column() < 4)
+               return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
+       return QAbstractTableModel::flags(index);
 }
 
 QVariant NodeModel::headerData(int section, Qt::Orientation orientation, int role) const
@@ -33,6 +35,10 @@ QVariant NodeModel::headerData(int section, Qt::Orientation orientation, int rol
                        return "X";
                case 3:
                        return "Y";
+               case 4:
+                       return "In Degree";
+               case 5:
+                       return "Out Degree";
                default:
                break;
        }
@@ -46,7 +52,7 @@ int NodeModel::rowCount(const QModelIndex &) const
 
 int NodeModel::columnCount(const QModelIndex &) const
 {
-       return 4;
+       return 6;
 }
 
 QVariant NodeModel::data(const QModelIndex &index, int role) const
@@ -66,6 +72,10 @@ QVariant NodeModel::data(const QModelIndex &index, int role) const
                                return n->x();
                        case 3:
                                return n->y();
+                       case 4:
+                               return n->incomingEdges().count();
+                       case 5:
+                               return n->outgoingEdges().count();
                        default:
                        break;
                }
diff --git a/pmc.cpp b/pmc.cpp
index 8505781a85cd7231098ce4fb0fab25429fca81d4..1d4d65d4cff14ee8e23492779ae19c4d108434aa 100644 (file)
--- a/pmc.cpp
+++ b/pmc.cpp
 #include "node.h"
 #include "edge.h"
 
+#include "combination.h"
+
+#include <QApplication>
+#include <QDebug>
+
 PMC::PMC(Graph *g, QObject *parent) :
-       QObject(parent), m_graph(g)
+       QObject(parent), m_graph(g), m_m(0)
+{
+}
+
+bool cmp(Node *a, Node *b)
 {
+       return a->incomingEdges().count() > b->incomingEdges().count();
 }
 
+void PMC::run()
+{
+       while(!step())
+               QApplication::processEvents();
+}
+
+
 bool PMC::step()
 {
-       Node *next = findHighestDegree();
+       QVector<Node *> nodes = m_graph->nodes().toVector();
+       NodeList nodesByIncomingCount = m_graph->nodes();
 
-       if (!next)
-               return true;
 
+       qSort(nodesByIncomingCount.begin(), nodesByIncomingCount.end(), cmp);
 
-       Edge *e = next->incomingEdges().first();
-//     Node *otherNode = e->startNode();
-       m_graph->removeEdge(e);
+       // Check if possible
+       bool can = true;
+       bool allAtM = true;
+       for (int i = 0; i < nodesByIncomingCount.count(); ++i)
+       {
+               Node *n = nodesByIncomingCount[i];
+               if (n->incomingEdges().count() != m())
+                       allAtM = false;
+               if (n->incomingEdges().count() == m())
+               {
+                       n->setColor(Qt::green);
+                       continue;
+               }
+               if (n->incomingEdges().count() > m())
+                       continue;
+               n->setColor(Qt::red);
+               can = false;
+       }
+       if (!can || allAtM)
+       {
+               if (!can)
+                       emit log(tr("Node with less than m incoming edges found. END"));
+               if (allAtM)
+                       emit log(tr("Done"));
+               m_failed = !allAtM;
+               m_finished = true;
+               return true;
+       }
 
-       if (next->incomingEdges().count() == m())
-               next->setColor(Qt::green);
-       else
-               next->setColor(Qt::yellow);
-       next->update();
-       return false;
-}
+       qSort(nodes.begin(), nodes.end());
+       QVector<Node *> combination(nodes.count() - 2 * m() + m() - 1);
 
-Node *PMC::findHighestDegree() const
-{
-       Node *ret = 0;
-       foreach(Node *n, m_graph->nodes())
+       for (int i = 0; i < nodesByIncomingCount.count(); ++i)
        {
-               if (n->incomingEdges().count() <= m())
+               Node *n = nodesByIncomingCount[i];
+
+               if (n->incomingEdges().count() < m())
+               {
+                       n->setColor(Qt::red);
+                       continue;
+               }
+               n->setColor(Qt::yellow);
+
+               for (int j = 0; j < n->incomingEdges().count(); ++j)
                {
-                       if (n->incomingEdges().count() < m())
+                       Edge *e = n->incomingEdges()[j];
+
+                       Node *otherNode = e->startNode();
+
+                       bool removable = true;
+                       // HAKIMI
+                       for (int p = 0; p < m() - 1; ++p)
                        {
-                               n->setColor(Qt::red);
-                               n->update();
+                               int Ep = nodes.count() - 2 * m() + p;
+                               qCopy(nodes.begin(), nodes.begin() + Ep, combination.begin());
+                               do {
+                                       int sum = 0;
+                                       for (int k = 0; k < Ep; ++k)
+                                               sum += combination.at(k)->outgoingEdges().count();
+                                       if (combination.contains(otherNode))
+                                               --sum;
+
+                                       if (sum <= p)
+                                       {
+                                               removable = false;
+                                               break;
+                                       }
+
+                               } while(stdcomb::next_combination(nodes.begin(), nodes.end(), combination.begin(), combination.begin() + Ep));
+                               if (!removable)
+                                       break;
                        }
-                       continue;
+
+                       if (removable)
+                       {
+                               emit log(tr("Removing edge %1->%2 from %3").arg(e->startNode()->label(), e->endNode()->label(), n->label()));
+                               m_graph->removeEdge(e);
+
+                               if (n->incomingEdges().count() == m())
+                               {
+                                       emit log(tr("%1 is now at m incoming edges").arg(n->label()));
+                                       n->setColor(Qt::green);
+                               }
+                               return false;
+                       }
+                       else
+                               emit log(tr("Cannot remove edge %1->%2 from %3").arg(e->startNode()->label(), e->endNode()->label(), n->label()));
+
                }
-               if (ret == 0)
-                       ret = n;
-               if (n->incomingEdges().count() > n->outgoingEdges().count())
-                       ret = n;
+               emit log(tr("No edges to remove from %1").arg(n->label()));
        }
-       return ret;
+       emit log(tr("Could not remove any edge and requirements not met. END"));
+       m_failed = true;
+       m_finished = true;
+       return true;
+}
+
+void PMC::reset()
+{
+       m_failed = false;
+       m_finished = false;
 }
 
 int PMC::m() const
 {
-       return (m_graph->nodes().count() - 1) / 2;
+       return m_m;
 }
 
-int PMC::p() const
+
+int PMC::maxM() const
 {
-       return m_graph->nodes().count() - 2 * m();
+       return (m_graph->nodes().count() - 1) / 2;
 }
diff --git a/pmc.h b/pmc.h
index 85b7844ca04be65c57200b4bc819e7cfef329fd4..f888d42350fc4b4266c82f355374a758e4b77cef 100644 (file)
--- a/pmc.h
+++ b/pmc.h
@@ -9,20 +9,44 @@ class Node;
 class PMC : public QObject
 {
        Q_OBJECT
+       Q_PROPERTY(int m READ m WRITE setM)
+       Q_PROPERTY(bool failed READ failed)
+       Q_PROPERTY(bool finished READ finished)
+
 public:
        explicit PMC(Graph *g, QObject *parent = 0);
-       
+
+       int m() const;
+       int maxM() const;
+
+       bool failed() const
+       {
+               return m_failed;
+       }
+
+       bool finished() const
+       {
+               return m_finished;
+       }
+
 signals:
+       void log(const QString &log);
        
 public slots:
+       void run();
        bool step();
+       void reset();
 
-private:
-       Node *findHighestDegree() const;
-       int m() const;
-       int p() const;
+       void setM(int m)
+       {
+               m_m = m;
+       }
 
+private:
        Graph *m_graph;
+       int m_m;
+       bool m_failed;
+       bool m_finished;
 };
 
 #endif // PMC_H