/** \file
* \brief Declration of stress minimized layout based on majorization.
* It can be applied to connected as well as unconnected graphs. If
* the graph is disconnected either the infinite distances will be
* replaced by the average edge costs times sqrt(n) or the components
* will be processed separately.
*
* \author Mark Ortmann, University of Konstanz
*
* \par License:
* This file is part of the Open Graph Drawing Framework (OGDF).
*
* \par
* Copyright (C)
* See README.md in the OGDF root directory for details.
*
* \par
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* Version 2 or 3 as published by the Free Software Foundation;
* see the file LICENSE.txt included in the packaging of this file
* for details.
*
* \par
* 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.
*
* \par
* You should have received a copy of the GNU General Public
* License along with this program; if not, see
* http://www.gnu.org/copyleft/gpl.html
*/
#pragma once
#include
#include
#include
#include
#include
namespace ogdf {
//! Energy-based layout using stress minimization.
/**
* @ingroup gd-energy
*/
class OGDF_EXPORT StressMinimization: public LayoutModule {
public:
enum class TerminationCriterion {
None, PositionDifference, Stress
};
//! Constructor: Constructs instance of stress majorization.
StressMinimization() :
m_hasEdgeCostsAttribute(false), m_hasInitialLayout(false), m_numberOfIterations(
200), m_edgeCosts(100), m_avgEdgeCosts(-1), m_componentLayout(
false), m_terminationCriterion(TerminationCriterion::None), m_fixXCoords(false), m_fixYCoords(
false), m_fixZCoords(false) {
}
//! Destructor.
~StressMinimization() {
}
//! Calls the layout algorithm with uniform edge costs.
virtual void call(GraphAttributes& GA) override;
//! Tells whether the current layout should be used or the initial layout
//! needs to be computed.
inline void hasInitialLayout(bool hasInitialLayout);
//! Tells whether the x coordinates are allowed to be modified or not.
inline void fixXCoordinates(bool fix);
//! Tells whether the y coordinates are allowed to be modified or not.
inline void fixYCoordinates(bool fix);
//! Tells whether the z coordinates are allowed to be modified or not.
inline void fixZCoordinates(bool fix);
//! Sets whether the graph's components should be layouted separately or a dummy
//! distance should be used for nodes within different components.
inline void layoutComponentsSeparately(bool separate);
//! Sets the desired distance between adjacent nodes. If the new value is smaller or equal
//! 0 the default value (100) is used.
inline void setEdgeCosts(double edgeCosts);
//! Sets a fixed number of iterations for stress majorization. If the new value is smaller or equal
//! 0 the default value (200) is used.
inline void setIterations(int numberOfIterations);
//! Tells which TerminationCriterion should be used
inline void convergenceCriterion(TerminationCriterion criterion);
//! Tells whether the edge costs are uniform or defined by some edge costs attribute.
inline void useEdgeCostsAttribute(bool useEdgeCostsAttribute);
private:
//! Convergence constant.
const static double EPSILON;
//! Default number of pivots used for the initial Pivot-MDS layout
const static int DEFAULT_NUMBER_OF_PIVOTS;
//! Tells whether the stress minimization is based on uniform edge costs or a
//! edge costs attribute
bool m_hasEdgeCostsAttribute;
//! Tells whether an initial layout has to be computed or not.
bool m_hasInitialLayout;
//! Number of iterations performed by the stress minimization.
int m_numberOfIterations;
//! The weight of an edge.
double m_edgeCosts;
//! The average edge costs. Needed to define distances of nodes belonging to
//! different graph components.
double m_avgEdgeCosts;
//! Indicates whether the components should be treated separately.
bool m_componentLayout;
//! Indicates whether epsilon convergence is used or not.
TerminationCriterion m_terminationCriterion;
//! Indicates whether the x coordinates will be modified or not.
bool m_fixXCoords;
//! Indicates whether the y coordinates will be modified or not.
bool m_fixYCoords;
//! Indicates whether the z coordinates will be modified or not.
bool m_fixZCoords;
//! Calculates the stress for the given layout
double calcStress(const GraphAttributes& GA,
NodeArray >& shortestPathMatrix,
NodeArray >& weightMatrix);
//! Runs the stress for a given Graph, shortest path and weight matrix.
void call(GraphAttributes& GA,
NodeArray >& shortestPathMatrix,
NodeArray >& weightMatrix);
//! Calculates the weight matrix of the shortest path matrix. This is done by w_ij = s_ij^{-2}
void calcWeights(const Graph& G,
NodeArray >& shortestPathMatrix,
NodeArray >& weightMatrix);
//! Calculates the intial layout of the graph if necessary.
void computeInitialLayout(GraphAttributes& GA);
//! Convenience method copying the layout of the graph in case of epsilon convergence.
void copyLayout(const GraphAttributes& GA, NodeArray& newX,
NodeArray& newY);
//! Convenience method copying the layout of the graph in case of epsilon convergence for 3D.
void copyLayout(const GraphAttributes& GA, NodeArray& newX,
NodeArray& newY, NodeArray& newZ);
//! Checks for epsilon convergence and whether the performed number of iterations
//! exceed the predefined maximum number of iterations.
bool finished(GraphAttributes& GA, int numberOfPerformedIterations,
NodeArray& prevXCoords, NodeArray& prevYCoords,
const double prevStress, const double curStress);
//! Convenience method to initialize the matrices.
void initMatrices(const Graph& G,
NodeArray >& shortestPathMatrix,
NodeArray >& weightMatrix);
//! Minimizes the stress for each component separately given
//! the shortest path matrix and the weight matrix.
void minimizeStress(GraphAttributes& GA,
NodeArray >& shortestPathMatrix,
NodeArray >& weightMatrix);
//! Runs the next iteration of the stress minimization process. Note that serial update
//! is used.
void nextIteration(GraphAttributes& GA,
NodeArray >& shortestPathMatrix,
NodeArray >& weightMatrix);
//! Replaces infinite distances to the given value
void replaceInfinityDistances(
NodeArray >& shortestPathMatrix, double newVal);
}
;
void StressMinimization::fixXCoordinates(bool fix) {
m_fixXCoords = fix;
}
void StressMinimization::fixYCoordinates(bool fix) {
m_fixYCoords = fix;
}
void StressMinimization::hasInitialLayout(bool hasInitialLayout) {
m_hasInitialLayout = hasInitialLayout;
}
void StressMinimization::layoutComponentsSeparately(bool separate) {
m_componentLayout = separate;
}
void StressMinimization::setEdgeCosts(double edgeCosts) {
m_edgeCosts = (edgeCosts > 0) ? edgeCosts : 100;
}
void StressMinimization::setIterations(int numberOfIterations) {
m_numberOfIterations = (numberOfIterations > 0) ? numberOfIterations : 100;
}
void StressMinimization::convergenceCriterion(TerminationCriterion criterion) {
m_terminationCriterion = criterion;
}
void StressMinimization::useEdgeCostsAttribute(bool useEdgeCostsAttribute) {
m_hasEdgeCostsAttribute = useEdgeCostsAttribute;
}
}