parent
e9113ec822
commit
dd628b6af7
|
@ -1224,4 +1224,10 @@ https://www.reddit.com/r/gamedev/comments/5iuf3h/i_am_writting_a_3d_monster_mode
|
|||
<pre>
|
||||
A Fast Parallel Algorithm for Thinning Digital Patterns
|
||||
https://dl.acm.org/citation.cfm?id=358023
|
||||
</pre>
|
||||
|
||||
<h1>Huang, Jingwei and Zhou, Yichao and Niessner, Matthias and Shewchuk, Jonathan Richard and Guibas, Leonidas J.</h1>
|
||||
<pre>
|
||||
QuadriFlow: A Scalable and Robust Method for Quadrangulation
|
||||
http://stanford.edu/~jingweih/papers/quadriflow/
|
||||
</pre>
|
54
dust3d.pro
54
dust3d.pro
|
@ -483,10 +483,64 @@ HEADERS += src/imageskeletonextractor.h
|
|||
SOURCES += src/contourtopartconverter.cpp
|
||||
HEADERS += src/contourtopartconverter.h
|
||||
|
||||
SOURCES += src/remesher.cpp
|
||||
HEADERS += src/remesher.h
|
||||
|
||||
SOURCES += src/main.cpp
|
||||
|
||||
HEADERS += src/version.h
|
||||
|
||||
INCLUDEPATH += thirdparty/QuadriFlow
|
||||
INCLUDEPATH += thirdparty/QuadriFlow/3rd/pcg32
|
||||
INCLUDEPATH += thirdparty/QuadriFlow/3rd/pss
|
||||
INCLUDEPATH += thirdparty/QuadriFlow/3rd/lemon-1.3.1
|
||||
|
||||
SOURCES += thirdparty/QuadriFlow/src/adjacent-matrix.cpp
|
||||
HEADERS += thirdparty/QuadriFlow/src/adjacent-matrix.hpp
|
||||
|
||||
HEADERS += thirdparty/QuadriFlow/src/compare-key.hpp
|
||||
|
||||
HEADERS += thirdparty/QuadriFlow/src/config.hpp
|
||||
|
||||
SOURCES += thirdparty/QuadriFlow/src/dedge.cpp
|
||||
HEADERS += thirdparty/QuadriFlow/src/dedge.hpp
|
||||
|
||||
HEADERS += thirdparty/QuadriFlow/src/disajoint-tree.hpp
|
||||
|
||||
HEADERS += thirdparty/QuadriFlow/src/dset.hpp
|
||||
|
||||
HEADERS += thirdparty/QuadriFlow/src/field-math.hpp
|
||||
|
||||
HEADERS += thirdparty/QuadriFlow/src/flow.hpp
|
||||
|
||||
SOURCES += thirdparty/QuadriFlow/src/hierarchy.cpp
|
||||
HEADERS += thirdparty/QuadriFlow/src/hierarchy.hpp
|
||||
|
||||
SOURCES += thirdparty/QuadriFlow/src/loader.cpp
|
||||
HEADERS += thirdparty/QuadriFlow/src/loader.hpp
|
||||
|
||||
SOURCES += thirdparty/QuadriFlow/src/localsat.cpp
|
||||
HEADERS += thirdparty/QuadriFlow/src/localsat.hpp
|
||||
|
||||
SOURCES += thirdparty/QuadriFlow/src/merge-vertex.cpp
|
||||
HEADERS += thirdparty/QuadriFlow/src/merge-vertex.hpp
|
||||
|
||||
SOURCES += thirdparty/QuadriFlow/src/optimizer.cpp
|
||||
HEADERS += thirdparty/QuadriFlow/src/optimizer.hpp
|
||||
|
||||
SOURCES += thirdparty/QuadriFlow/src/parametrizer.cpp
|
||||
SOURCES += thirdparty/QuadriFlow/src/parametrizer-flip.cpp
|
||||
SOURCES += thirdparty/QuadriFlow/src/parametrizer-int.cpp
|
||||
SOURCES += thirdparty/QuadriFlow/src/parametrizer-mesh.cpp
|
||||
SOURCES += thirdparty/QuadriFlow/src/parametrizer-scale.cpp
|
||||
SOURCES += thirdparty/QuadriFlow/src/parametrizer-sing.cpp
|
||||
HEADERS += thirdparty/QuadriFlow/src/parametrizer.hpp
|
||||
|
||||
HEADERS += thirdparty/QuadriFlow/src/serialize.hpp
|
||||
|
||||
SOURCES += thirdparty/QuadriFlow/src/subdivide.cpp
|
||||
HEADERS += thirdparty/QuadriFlow/src/subdivide.hpp
|
||||
|
||||
INCLUDEPATH += thirdparty/bullet3/src
|
||||
|
||||
SOURCES += thirdparty/bullet3/src/LinearMath/btAlignedAllocator.cpp
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "imageforever.h"
|
||||
#include "gridmeshbuilder.h"
|
||||
#include "triangulatefaces.h"
|
||||
#include "remesher.h"
|
||||
|
||||
MeshGenerator::MeshGenerator(Snapshot *snapshot) :
|
||||
m_snapshot(snapshot)
|
||||
|
@ -1310,6 +1311,25 @@ void MeshGenerator::generate()
|
|||
m_outcome->vertices = combinedVertices;
|
||||
m_outcome->triangles = combinedFaces;
|
||||
m_outcome->paintMaps = componentCache.outcomePaintMaps;
|
||||
|
||||
/*
|
||||
Remesher remesher;
|
||||
remesher.setMesh(combinedVertices, combinedFaces);
|
||||
remesher.remesh();
|
||||
m_outcome->vertices = remesher.getRemeshedVertices();
|
||||
const auto &remeshedFaces = remesher.getRemeshedFaces();
|
||||
m_outcome->triangleAndQuads = remeshedFaces;
|
||||
m_outcome->triangles.clear();
|
||||
m_outcome->triangles.reserve(remeshedFaces.size() * 2);
|
||||
for (const auto &it: remeshedFaces) {
|
||||
m_outcome->triangles.push_back(std::vector<size_t> {
|
||||
it[0], it[1], it[2]
|
||||
});
|
||||
m_outcome->triangles.push_back(std::vector<size_t> {
|
||||
it[2], it[3], it[0]
|
||||
});
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// Recursively check uncombined components
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
#include <config.hpp>
|
||||
#include <field-math.hpp>
|
||||
#include <optimizer.hpp>
|
||||
#include <parametrizer.hpp>
|
||||
#ifdef WITH_CUDA
|
||||
#include <cuda_runtime.h>
|
||||
#endif
|
||||
#include "remesher.h"
|
||||
|
||||
using namespace qflow;
|
||||
|
||||
Remesher::~Remesher()
|
||||
{
|
||||
}
|
||||
|
||||
void Remesher::setMesh(const std::vector<QVector3D> &vertices,
|
||||
const std::vector<std::vector<size_t>> &triangles)
|
||||
{
|
||||
m_vertices = vertices;
|
||||
m_triangles = triangles;
|
||||
}
|
||||
|
||||
const std::vector<QVector3D> &Remesher::getRemeshedVertices()
|
||||
{
|
||||
return m_remeshedVertices;
|
||||
}
|
||||
const std::vector<std::vector<size_t>> &Remesher::getRemeshedFaces()
|
||||
{
|
||||
return m_remeshedFaces;
|
||||
}
|
||||
|
||||
void Remesher::remesh()
|
||||
{
|
||||
Parametrizer field;
|
||||
|
||||
#ifdef WITH_CUDA
|
||||
cudaFree(0);
|
||||
#endif
|
||||
|
||||
field.V.resize(3, m_vertices.size());
|
||||
field.F.resize(3, m_triangles.size());
|
||||
for (decltype(m_vertices.size()) i = 0; i < m_vertices.size(); i++) {
|
||||
const auto &vertex = m_vertices[i];
|
||||
field.V.col(i) << (double)vertex.x(), (double)vertex.y(), (double)vertex.z();
|
||||
}
|
||||
for (decltype(m_triangles.size()) i = 0; i < m_triangles.size(); i++) {
|
||||
const auto &face = m_triangles[i];
|
||||
field.F.col(i) << (uint32_t)face[0], (uint32_t)face[1], (uint32_t)face[2];
|
||||
}
|
||||
field.NormalizeMesh();
|
||||
|
||||
int faces = -1;
|
||||
field.Initialize(faces);
|
||||
|
||||
if (field.flag_preserve_boundary) {
|
||||
Hierarchy& hierarchy = field.hierarchy;
|
||||
hierarchy.clearConstraints();
|
||||
for (uint32_t i = 0; i < 3 * hierarchy.mF.cols(); ++i) {
|
||||
if (hierarchy.mE2E[i] == -1) {
|
||||
uint32_t i0 = hierarchy.mF(i % 3, i / 3);
|
||||
uint32_t i1 = hierarchy.mF((i + 1) % 3, i / 3);
|
||||
Vector3d p0 = hierarchy.mV[0].col(i0), p1 = hierarchy.mV[0].col(i1);
|
||||
Vector3d edge = p1 - p0;
|
||||
if (edge.squaredNorm() > 0) {
|
||||
edge.normalize();
|
||||
hierarchy.mCO[0].col(i0) = p0;
|
||||
hierarchy.mCO[0].col(i1) = p1;
|
||||
hierarchy.mCQ[0].col(i0) = hierarchy.mCQ[0].col(i1) = edge;
|
||||
hierarchy.mCQw[0][i0] = hierarchy.mCQw[0][i1] = hierarchy.mCOw[0][i0] = hierarchy.mCOw[0][i1] =
|
||||
1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
hierarchy.propagateConstraints();
|
||||
}
|
||||
|
||||
Optimizer::optimize_orientations(field.hierarchy);
|
||||
field.ComputeOrientationSingularities();
|
||||
|
||||
if (field.flag_adaptive_scale == 1) {
|
||||
field.EstimateSlope();
|
||||
}
|
||||
|
||||
Optimizer::optimize_scale(field.hierarchy, field.rho, field.flag_adaptive_scale);
|
||||
field.flag_adaptive_scale = 1;
|
||||
|
||||
Optimizer::optimize_positions(field.hierarchy, field.flag_adaptive_scale);
|
||||
field.ComputePositionSingularities();
|
||||
|
||||
field.ComputeIndexMap();
|
||||
|
||||
m_remeshedVertices.reserve(field.O_compact.size());
|
||||
for (size_t i = 0; i < field.O_compact.size(); ++i) {
|
||||
auto t = field.O_compact[i] * field.normalize_scale + field.normalize_offset;
|
||||
m_remeshedVertices.push_back(QVector3D(t[0], t[1], t[2]));
|
||||
}
|
||||
m_remeshedFaces.reserve(field.F_compact.size());
|
||||
for (size_t i = 0; i < field.F_compact.size(); ++i) {
|
||||
m_remeshedFaces.push_back(std::vector<size_t> {
|
||||
(size_t)field.F_compact[i][0],
|
||||
(size_t)field.F_compact[i][1],
|
||||
(size_t)field.F_compact[i][2],
|
||||
(size_t)field.F_compact[i][3]
|
||||
});
|
||||
}
|
||||
|
||||
printf("m_remeshedVertices.size:%lu\r\n", m_remeshedVertices.size());
|
||||
printf("m_remeshedFaces.size:%lu\r\n", m_remeshedFaces.size());
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef DUST3D_REMESHER_H
|
||||
#define DUST3D_REMESHER_H
|
||||
#include <QObject>
|
||||
#include <vector>
|
||||
#include <QVector3D>
|
||||
|
||||
class Remesher : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~Remesher();
|
||||
void setMesh(const std::vector<QVector3D> &vertices,
|
||||
const std::vector<std::vector<size_t>> &triangles);
|
||||
void remesh();
|
||||
const std::vector<QVector3D> &getRemeshedVertices();
|
||||
const std::vector<std::vector<size_t>> &getRemeshedFaces();
|
||||
private:
|
||||
std::vector<QVector3D> m_vertices;
|
||||
std::vector<std::vector<size_t>> m_triangles;
|
||||
std::vector<QVector3D> m_remeshedVertices;
|
||||
std::vector<std::vector<size_t>> m_remeshedFaces;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,5 @@
|
|||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
IndentWidth: 4
|
||||
Standard: Cpp11
|
||||
ColumnLimit: 99
|
|
@ -0,0 +1,293 @@
|
|||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
*.o
|
||||
*.or
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
data/
|
||||
[Bb]uild/
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
**/Properties/launchSettings.json
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
open-wbo
|
||||
open-wbo_*
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
|
@ -0,0 +1,29 @@
|
|||
cmake_minimum_required(VERSION 3.1)
|
||||
project(MapleCOMSPS_LRB)
|
||||
|
||||
find_package(ZLIB)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
include_directories(${ZLIB_INCLUDE_DIRS})
|
||||
|
||||
set(
|
||||
minisat_SRC
|
||||
core/Solver.cc
|
||||
simp/Main.cc
|
||||
simp/SimpSolver.cc
|
||||
utils/Options.cc
|
||||
utils/System.cc
|
||||
)
|
||||
|
||||
add_executable(
|
||||
minisat
|
||||
${minisat_SRC}
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
minisat
|
||||
${ZLIB_LIBRARIES}
|
||||
)
|
|
@ -0,0 +1,23 @@
|
|||
MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
|
||||
Copyright (c) 2007-2010 Niklas Sorensson
|
||||
|
||||
Chanseok Oh's MiniSat Patch Series -- Copyright (c) 2015, Chanseok Oh
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,24 @@
|
|||
================================================================================
|
||||
DIRECTORY OVERVIEW:
|
||||
|
||||
mtl/ Mini Template Library
|
||||
utils/ Generic helper code (I/O, Parsing, CPU-time, etc)
|
||||
core/ A core version of the solver
|
||||
simp/ An extended solver with simplification capabilities
|
||||
README
|
||||
LICENSE
|
||||
|
||||
================================================================================
|
||||
BUILDING: (release version: without assertions, statically linked, etc)
|
||||
|
||||
export MROOT=<minisat-dir> (or setenv in cshell)
|
||||
cd { core | simp }
|
||||
gmake rs
|
||||
cp minisat_static <install-dir>/minisat
|
||||
|
||||
================================================================================
|
||||
EXAMPLES:
|
||||
|
||||
Run minisat with same heuristics as version 2.0:
|
||||
|
||||
> minisat <cnf-file> -no-luby -rinc=1.5 -phase-saving=0 -rnd-freq=0.02
|
|
@ -0,0 +1,89 @@
|
|||
/****************************************************************************************[Dimacs.h]
|
||||
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
|
||||
Copyright (c) 2007-2010, Niklas Sorensson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#ifndef Minisat_Dimacs_h
|
||||
#define Minisat_Dimacs_h
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "utils/ParseUtils.h"
|
||||
#include "core/SolverTypes.h"
|
||||
|
||||
namespace Minisat {
|
||||
|
||||
//=================================================================================================
|
||||
// DIMACS Parser:
|
||||
|
||||
template<class B, class Solver>
|
||||
static void readClause(B& in, Solver& S, vec<Lit>& lits) {
|
||||
int parsed_lit, var;
|
||||
lits.clear();
|
||||
for (;;){
|
||||
parsed_lit = parseInt(in);
|
||||
if (parsed_lit == 0) break;
|
||||
var = abs(parsed_lit)-1;
|
||||
while (var >= S.nVars()) S.newVar();
|
||||
lits.push( (parsed_lit > 0) ? mkLit(var) : ~mkLit(var) );
|
||||
}
|
||||
}
|
||||
|
||||
template<class B, class Solver>
|
||||
static void parse_DIMACS_main(B& in, Solver& S) {
|
||||
vec<Lit> lits;
|
||||
int vars = 0;
|
||||
int clauses = 0;
|
||||
int cnt = 0;
|
||||
for (;;){
|
||||
skipWhitespace(in);
|
||||
if (*in == EOF) break;
|
||||
else if (*in == 'p'){
|
||||
if (eagerMatch(in, "p cnf")){
|
||||
vars = parseInt(in);
|
||||
clauses = parseInt(in);
|
||||
// SATRACE'06 hack
|
||||
// if (clauses > 4000000)
|
||||
// S.eliminate(true);
|
||||
}else{
|
||||
printf("PARSE ERROR! Unexpected char: %c\n", *in), exit(3);
|
||||
}
|
||||
} else if (*in == 'c' || *in == 'p')
|
||||
skipLine(in);
|
||||
else{
|
||||
cnt++;
|
||||
readClause(in, S, lits);
|
||||
S.addClause_(lits); }
|
||||
}
|
||||
if (vars != S.nVars())
|
||||
fprintf(stderr, "WARNING! DIMACS header mismatch: wrong number of variables.\n");
|
||||
if (cnt != clauses)
|
||||
fprintf(stderr, "WARNING! DIMACS header mismatch: wrong number of clauses.\n");
|
||||
}
|
||||
|
||||
// Inserts problem into solver.
|
||||
//
|
||||
template<class Solver>
|
||||
static void parse_DIMACS(gzFile input_stream, Solver& S) {
|
||||
StreamBuffer in(input_stream);
|
||||
parse_DIMACS_main(in, S); }
|
||||
|
||||
//=================================================================================================
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,202 @@
|
|||
/*****************************************************************************************[Main.cc]
|
||||
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
|
||||
Copyright (c) 2007-2010, Niklas Sorensson
|
||||
|
||||
Chanseok Oh's MiniSat Patch Series -- Copyright (c) 2015, Chanseok Oh
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "utils/System.h"
|
||||
#include "utils/ParseUtils.h"
|
||||
#include "utils/Options.h"
|
||||
#include "core/Dimacs.h"
|
||||
#include "core/Solver.h"
|
||||
|
||||
using namespace Minisat;
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
|
||||
void printStats(Solver& solver)
|
||||
{
|
||||
double cpu_time = cpuTime();
|
||||
// double mem_used = memUsedPeak();
|
||||
// printf("c restarts : %"PRIu64"\n", solver.starts);
|
||||
// printf("c conflicts : %-12"PRIu64" (%.0f /sec)\n", solver.conflicts , solver.conflicts /cpu_time);
|
||||
// printf("c decisions : %-12"PRIu64" (%4.2f %% random) (%.0f /sec)\n", solver.decisions, (float)solver.rnd_decisions*100 / (float)solver.decisions, solver.decisions /cpu_time);
|
||||
// printf("c propagations : %-12"PRIu64" (%.0f /sec)\n", solver.propagations, solver.propagations/cpu_time);
|
||||
// printf("c conflict literals : %-12"PRIu64" (%4.2f %% deleted)\n", solver.tot_literals, (solver.max_literals - solver.tot_literals)*100 / (double)solver.max_literals);
|
||||
// if (mem_used != 0) printf("c Memory used : %.2f MB\n", mem_used);
|
||||
printf("c CPU time : %g s\n", cpu_time);
|
||||
}
|
||||
|
||||
|
||||
static Solver* solver;
|
||||
// Terminate by notifying the solver and back out gracefully. This is mainly to have a test-case
|
||||
// for this feature of the Solver as it may take longer than an immediate call to '_exit()'.
|
||||
static void SIGINT_interrupt(int signum) { solver->interrupt(); }
|
||||
|
||||
// Note that '_exit()' rather than 'exit()' has to be used. The reason is that 'exit()' calls
|
||||
// destructors and may cause deadlocks if a malloc/free function happens to be running (these
|
||||
// functions are guarded by locks for multithreaded use).
|
||||
static void SIGINT_exit(int signum) {
|
||||
printf("\n"); printf("c *** INTERRUPTED ***\n");
|
||||
if (solver->verbosity > 0){
|
||||
printStats(*solver);
|
||||
printf("\n"); printf("c *** INTERRUPTED ***\n"); }
|
||||
_exit(1); }
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
// Main:
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
try {
|
||||
setUsageHelp("USAGE: %s [options] <input-file> <result-output-file>\n\n where input may be either in plain or gzipped DIMACS.\n");
|
||||
printf("c This is COMiniSatPS.\n");
|
||||
|
||||
#if defined(__linux__)
|
||||
fpu_control_t oldcw, newcw;
|
||||
_FPU_GETCW(oldcw); newcw = (oldcw & ~_FPU_EXTENDED) | _FPU_DOUBLE; _FPU_SETCW(newcw);
|
||||
printf("c WARNING: for repeatability, setting FPU to use double precision\n");
|
||||
#endif
|
||||
// Extra options:
|
||||
//
|
||||
IntOption verb ("MAIN", "verb", "Verbosity level (0=silent, 1=some, 2=more).", 1, IntRange(0, 2));
|
||||
IntOption cpu_lim("MAIN", "cpu-lim","Limit on CPU time allowed in seconds.\n", INT32_MAX, IntRange(0, INT32_MAX));
|
||||
IntOption mem_lim("MAIN", "mem-lim","Limit on memory usage in megabytes.\n", INT32_MAX, IntRange(0, INT32_MAX));
|
||||
|
||||
parseOptions(argc, argv, true);
|
||||
|
||||
Solver S;
|
||||
double initial_time = cpuTime();
|
||||
|
||||
S.verbosity = verb;
|
||||
|
||||
solver = &S;
|
||||
// Use signal handlers that forcibly quit until the solver will be able to respond to
|
||||
// interrupts:
|
||||
signal(SIGINT, SIGINT_exit);
|
||||
signal(SIGXCPU,SIGINT_exit);
|
||||
|
||||
// Set limit on CPU-time:
|
||||
if (cpu_lim != INT32_MAX){
|
||||
rlimit rl;
|
||||
getrlimit(RLIMIT_CPU, &rl);
|
||||
if (rl.rlim_max == RLIM_INFINITY || (rlim_t)cpu_lim < rl.rlim_max){
|
||||
rl.rlim_cur = cpu_lim;
|
||||
if (setrlimit(RLIMIT_CPU, &rl) == -1)
|
||||
printf("c WARNING! Could not set resource limit: CPU-time.\n");
|
||||
} }
|
||||
|
||||
// Set limit on virtual memory:
|
||||
if (mem_lim != INT32_MAX){
|
||||
rlim_t new_mem_lim = (rlim_t)mem_lim * 1024*1024;
|
||||
rlimit rl;
|
||||
getrlimit(RLIMIT_AS, &rl);
|
||||
if (rl.rlim_max == RLIM_INFINITY || new_mem_lim < rl.rlim_max){
|
||||
rl.rlim_cur = new_mem_lim;
|
||||
if (setrlimit(RLIMIT_AS, &rl) == -1)
|
||||
printf("c WARNING! Could not set resource limit: Virtual memory.\n");
|
||||
} }
|
||||
|
||||
if (argc == 1)
|
||||
printf("c Reading from standard input... Use '--help' for help.\n");
|
||||
|
||||
gzFile in = (argc == 1) ? gzdopen(0, "rb") : gzopen(argv[1], "rb");
|
||||
if (in == NULL)
|
||||
printf("c ERROR! Could not open file: %s\n", argc == 1 ? "<stdin>" : argv[1]), exit(1);
|
||||
|
||||
if (S.verbosity > 0){
|
||||
printf("c ============================[ Problem Statistics ]=============================\n");
|
||||
printf("c | |\n"); }
|
||||
|
||||
parse_DIMACS(in, S);
|
||||
gzclose(in);
|
||||
FILE* res = (argc >= 3) ? fopen(argv[2], "wb") : NULL;
|
||||
|
||||
if (S.verbosity > 0){
|
||||
printf("c | Number of variables: %12d |\n", S.nVars());
|
||||
printf("c | Number of clauses: %12d |\n", S.nClauses()); }
|
||||
|
||||
double parsed_time = cpuTime();
|
||||
if (S.verbosity > 0){
|
||||
printf("c | Parse time: %12.2f s |\n", parsed_time - initial_time);
|
||||
printf("c | |\n"); }
|
||||
|
||||
// Change to signal-handlers that will only notify the solver and allow it to terminate
|
||||
// voluntarily:
|
||||
signal(SIGINT, SIGINT_interrupt);
|
||||
signal(SIGXCPU,SIGINT_interrupt);
|
||||
|
||||
if (!S.simplify()){
|
||||
if (res != NULL) fprintf(res, "UNSAT\n"), fclose(res);
|
||||
if (S.verbosity > 0){
|
||||
printf("c ===============================================================================\n");
|
||||
printf("c Solved by unit propagation\n");
|
||||
printStats(S);
|
||||
printf("\n"); }
|
||||
printf("s UNSATISFIABLE\n");
|
||||
exit(20);
|
||||
}
|
||||
|
||||
vec<Lit> dummy;
|
||||
lbool ret = S.solveLimited(dummy);
|
||||
if (S.verbosity > 0){
|
||||
printStats(S);
|
||||
printf("\n"); }
|
||||
printf(ret == l_True ? "s SATISFIABLE\n" : ret == l_False ? "s UNSATISFIABLE\n" : "s UNKNOWN\n");
|
||||
if (ret == l_True){
|
||||
printf("v ");
|
||||
for (int i = 0; i < S.nVars(); i++)
|
||||
if (S.model[i] != l_Undef)
|
||||
printf("%s%s%d", (i==0)?"":" ", (S.model[i]==l_True)?"":"-", i+1);
|
||||
printf(" 0\n");
|
||||
}
|
||||
|
||||
if (res != NULL){
|
||||
if (ret == l_True){
|
||||
fprintf(res, "SAT\n");
|
||||
for (int i = 0; i < S.nVars(); i++)
|
||||
if (S.model[i] != l_Undef)
|
||||
fprintf(res, "%s%s%d", (i==0)?"":" ", (S.model[i]==l_True)?"":"-", i+1);
|
||||
fprintf(res, " 0\n");
|
||||
}else if (ret == l_False)
|
||||
fprintf(res, "UNSAT\n");
|
||||
else
|
||||
fprintf(res, "INDET\n");
|
||||
fclose(res);
|
||||
}
|
||||
|
||||
#ifdef NDEBUG
|
||||
exit(ret == l_True ? 10 : ret == l_False ? 20 : 0); // (faster than "return", which will invoke the destructor for 'Solver')
|
||||
#else
|
||||
return (ret == l_True ? 10 : ret == l_False ? 20 : 0);
|
||||
#endif
|
||||
} catch (OutOfMemoryException&){
|
||||
printf("c ===============================================================================\n");
|
||||
printf("s UNKNOWN\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
EXEC = minisat
|
||||
DEPDIR = mtl utils
|
||||
|
||||
include $(MROOT)/mtl/template.mk
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,524 @@
|
|||
/****************************************************************************************[Solver.h]
|
||||
MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
|
||||
Copyright (c) 2007-2010, Niklas Sorensson
|
||||
|
||||
Chanseok Oh's MiniSat Patch Series -- Copyright (c) 2015, Chanseok Oh
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#ifndef Minisat_Solver_h
|
||||
#define Minisat_Solver_h
|
||||
|
||||
#define BIN_DRUP
|
||||
|
||||
#define GLUCOSE23
|
||||
//#define INT_QUEUE_AVG
|
||||
//#define LOOSE_PROP_STAT
|
||||
|
||||
#ifdef GLUCOSE23
|
||||
#define INT_QUEUE_AVG
|
||||
#define LOOSE_PROP_STAT
|
||||
#endif
|
||||
|
||||
#include "mtl/Vec.h"
|
||||
#include "mtl/Heap.h"
|
||||
#include "mtl/Alg.h"
|
||||
#include "utils/Options.h"
|
||||
#include "core/SolverTypes.h"
|
||||
|
||||
|
||||
// Don't change the actual numbers.
|
||||
#define LOCAL 0
|
||||
#define TIER2 2
|
||||
#define CORE 3
|
||||
|
||||
namespace Minisat {
|
||||
|
||||
//=================================================================================================
|
||||
// Solver -- the main class:
|
||||
|
||||
class Solver {
|
||||
private:
|
||||
template<typename T>
|
||||
class MyQueue {
|
||||
int max_sz, q_sz;
|
||||
int ptr;
|
||||
int64_t sum;
|
||||
vec<T> q;
|
||||
public:
|
||||
MyQueue(int sz) : max_sz(sz), q_sz(0), ptr(0), sum(0) { assert(sz > 0); q.growTo(sz); }
|
||||
inline bool full () const { return q_sz == max_sz; }
|
||||
#ifdef INT_QUEUE_AVG
|
||||
inline T avg () const { assert(full()); return sum / max_sz; }
|
||||
#else
|
||||
inline double avg () const { assert(full()); return sum / (double) max_sz; }
|
||||
#endif
|
||||
inline void clear() { sum = 0; q_sz = 0; ptr = 0; }
|
||||
void push(T e) {
|
||||
if (q_sz < max_sz) q_sz++;
|
||||
else sum -= q[ptr];
|
||||
sum += e;
|
||||
q[ptr++] = e;
|
||||
if (ptr == max_sz) ptr = 0;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
// Constructor/Destructor:
|
||||
//
|
||||
Solver();
|
||||
virtual ~Solver();
|
||||
|
||||
// Problem specification:
|
||||
//
|
||||
Var newVar (bool polarity = true, bool dvar = true); // Add a new variable with parameters specifying variable mode.
|
||||
|
||||
bool addClause (const vec<Lit>& ps); // Add a clause to the solver.
|
||||
bool addEmptyClause(); // Add the empty clause, making the solver contradictory.
|
||||
bool addClause (Lit p); // Add a unit clause to the solver.
|
||||
bool addClause (Lit p, Lit q); // Add a binary clause to the solver.
|
||||
bool addClause (Lit p, Lit q, Lit r); // Add a ternary clause to the solver.
|
||||
bool addClause_( vec<Lit>& ps); // Add a clause to the solver without making superflous internal copy. Will
|
||||
// change the passed vector 'ps'.
|
||||
|
||||
// Solving:
|
||||
//
|
||||
bool simplify (bool do_stamping = false); // Removes already satisfied clauses.
|
||||
bool solve (const vec<Lit>& assumps); // Search for a model that respects a given set of assumptions.
|
||||
lbool solveLimited (const vec<Lit>& assumps); // Search for a model that respects a given set of assumptions (With resource constraints).
|
||||
bool solve (); // Search without assumptions.
|
||||
bool solve (Lit p); // Search for a model that respects a single assumption.
|
||||
bool solve (Lit p, Lit q); // Search for a model that respects two assumptions.
|
||||
bool solve (Lit p, Lit q, Lit r); // Search for a model that respects three assumptions.
|
||||
bool okay () const; // FALSE means solver is in a conflicting state
|
||||
|
||||
void toDimacs (FILE* f, const vec<Lit>& assumps); // Write CNF to file in DIMACS-format.
|
||||
void toDimacs (const char *file, const vec<Lit>& assumps);
|
||||
void toDimacs (FILE* f, Clause& c, vec<Var>& map, Var& max);
|
||||
|
||||
// Convenience versions of 'toDimacs()':
|
||||
void toDimacs (const char* file);
|
||||
void toDimacs (const char* file, Lit p);
|
||||
void toDimacs (const char* file, Lit p, Lit q);
|
||||
void toDimacs (const char* file, Lit p, Lit q, Lit r);
|
||||
|
||||
// Variable mode:
|
||||
//
|
||||
void setPolarity (Var v, bool b); // Declare which polarity the decision heuristic should use for a variable. Requires mode 'polarity_user'.
|
||||
void setDecisionVar (Var v, bool b); // Declare if a variable should be eligible for selection in the decision heuristic.
|
||||
|
||||
// Read state:
|
||||
//
|
||||
lbool value (Var x) const; // The current value of a variable.
|
||||
lbool value (Lit p) const; // The current value of a literal.
|
||||
lbool modelValue (Var x) const; // The value of a variable in the last model. The last call to solve must have been satisfiable.
|
||||
lbool modelValue (Lit p) const; // The value of a literal in the last model. The last call to solve must have been satisfiable.
|
||||
int nAssigns () const; // The current number of assigned literals.
|
||||
int nClauses () const; // The current number of original clauses.
|
||||
int nLearnts () const; // The current number of learnt clauses.
|
||||
int nVars () const; // The current number of variables.
|
||||
int nFreeVars () const;
|
||||
|
||||
// Resource contraints:
|
||||
//
|
||||
void setConfBudget(int64_t x);
|
||||
void setPropBudget(int64_t x);
|
||||
void budgetOff();
|
||||
void interrupt(); // Trigger a (potentially asynchronous) interruption of the solver.
|
||||
void clearInterrupt(); // Clear interrupt indicator flag.
|
||||
|
||||
// Memory managment:
|
||||
//
|
||||
virtual void garbageCollect();
|
||||
void checkGarbage(double gf);
|
||||
void checkGarbage();
|
||||
|
||||
// Extra results: (read-only member variable)
|
||||
//
|
||||
vec<lbool> model; // If problem is satisfiable, this vector contains the model (if any).
|
||||
vec<Lit> conflict; // If problem is unsatisfiable (possibly under assumptions),
|
||||
// this vector represent the final conflict clause expressed in the assumptions.
|
||||
|
||||
// Mode of operation:
|
||||
//
|
||||
FILE* drup_file;
|
||||
int verbosity;
|
||||
double step_size;
|
||||
double step_size_dec;
|
||||
double min_step_size;
|
||||
int timer;
|
||||
double var_decay;
|
||||
double clause_decay;
|
||||
double random_var_freq;
|
||||
double random_seed;
|
||||
bool VSIDS;
|
||||
int ccmin_mode; // Controls conflict clause minimization (0=none, 1=basic, 2=deep).
|
||||
int phase_saving; // Controls the level of phase saving (0=none, 1=limited, 2=full).
|
||||
bool rnd_pol; // Use random polarities for branching heuristics.
|
||||
bool rnd_init_act; // Initialize variable activities with a small random value.
|
||||
double garbage_frac; // The fraction of wasted memory allowed before a garbage collection is triggered.
|
||||
|
||||
int restart_first; // The initial restart limit. (default 100)
|
||||
double restart_inc; // The factor with which the restart limit is multiplied in each restart. (default 1.5)
|
||||
double learntsize_factor; // The intitial limit for learnt clauses is a factor of the original clauses. (default 1 / 3)
|
||||
double learntsize_inc; // The limit for learnt clauses is multiplied with this factor each restart. (default 1.1)
|
||||
|
||||
int learntsize_adjust_start_confl;
|
||||
double learntsize_adjust_inc;
|
||||
|
||||
// Statistics: (read-only member variable)
|
||||
//
|
||||
uint64_t solves, starts, decisions, rnd_decisions, propagations, conflicts, conflicts_VSIDS;
|
||||
uint64_t dec_vars, clauses_literals, learnts_literals, max_literals, tot_literals;
|
||||
|
||||
vec<uint32_t> picked;
|
||||
vec<uint32_t> conflicted;
|
||||
vec<uint32_t> almost_conflicted;
|
||||
|
||||
protected:
|
||||
|
||||
// Helper structures:
|
||||
//
|
||||
struct VarData { CRef reason; int level; };
|
||||
static inline VarData mkVarData(CRef cr, int l){ VarData d = {cr, l}; return d; }
|
||||
|
||||
struct Watcher {
|
||||
CRef cref;
|
||||
Lit blocker;
|
||||
Watcher(CRef cr, Lit p) : cref(cr), blocker(p) {}
|
||||
bool operator==(const Watcher& w) const { return cref == w.cref; }
|
||||
bool operator!=(const Watcher& w) const { return cref != w.cref; }
|
||||
};
|
||||
|
||||
struct WatcherDeleted
|
||||
{
|
||||
const ClauseAllocator& ca;
|
||||
WatcherDeleted(const ClauseAllocator& _ca) : ca(_ca) {}
|
||||
bool operator()(const Watcher& w) const { return ca[w.cref].mark() == 1; }
|
||||
};
|
||||
|
||||
struct VarOrderLt {
|
||||
const vec<double>& activity;
|
||||
bool operator () (Var x, Var y) const { return activity[x] > activity[y]; }
|
||||
VarOrderLt(const vec<double>& act) : activity(act) { }
|
||||
};
|
||||
|
||||
// Solver state:
|
||||
//
|
||||
bool ok; // If FALSE, the constraints are already unsatisfiable. No part of the solver state may be used!
|
||||
vec<CRef> clauses; // List of problem clauses.
|
||||
vec<CRef> learnts_core, // List of learnt clauses.
|
||||
learnts_tier2,
|
||||
learnts_local;
|
||||
double cla_inc; // Amount to bump next clause with.
|
||||
vec<double> activity_CHB, // A heuristic measurement of the activity of a variable.
|
||||
activity_VSIDS;
|
||||
double var_inc; // Amount to bump next variable with.
|
||||
OccLists<Lit, vec<Watcher>, WatcherDeleted>
|
||||
watches_bin, // Watches for binary clauses only.
|
||||
watches; // 'watches[lit]' is a list of constraints watching 'lit' (will go there if literal becomes true).
|
||||
vec<lbool> assigns; // The current assignments.
|
||||
vec<char> polarity; // The preferred polarity of each variable.
|
||||
vec<char> decision; // Declares if a variable is eligible for selection in the decision heuristic.
|
||||
vec<Lit> trail; // Assignment stack; stores all assigments made in the order they were made.
|
||||
vec<int> trail_lim; // Separator indices for different decision levels in 'trail'.
|
||||
vec<VarData> vardata; // Stores reason and level for each variable.
|
||||
int qhead; // Head of queue (as index into the trail -- no more explicit propagation queue in MiniSat).
|
||||
int simpDB_assigns; // Number of top-level assignments since last execution of 'simplify()'.
|
||||
int64_t simpDB_props; // Remaining number of propagations that must be made before next execution of 'simplify()'.
|
||||
vec<Lit> assumptions; // Current set of assumptions provided to solve by the user.
|
||||
Heap<VarOrderLt> order_heap_CHB, // A priority queue of variables ordered with respect to the variable activity.
|
||||
order_heap_VSIDS;
|
||||
double progress_estimate;// Set by 'search()'.
|
||||
bool remove_satisfied; // Indicates whether possibly inefficient linear scan for satisfied clauses should be performed in 'simplify'.
|
||||
|
||||
int core_lbd_cut;
|
||||
float global_lbd_sum;
|
||||
MyQueue<int> lbd_queue; // For computing moving averages of recent LBD values.
|
||||
|
||||
uint64_t next_T2_reduce,
|
||||
next_L_reduce;
|
||||
|
||||
ClauseAllocator ca;
|
||||
|
||||
// Temporaries (to reduce allocation overhead). Each variable is prefixed by the method in which it is
|
||||
// used, exept 'seen' wich is used in several places.
|
||||
//
|
||||
vec<char> seen;
|
||||
vec<Lit> analyze_stack;
|
||||
vec<Lit> analyze_toclear;
|
||||
vec<Lit> add_tmp;
|
||||
vec<Lit> add_oc;
|
||||
|
||||
vec<uint64_t> seen2; // Mostly for efficient LBD computation. 'seen2[i]' will indicate if decision level or variable 'i' has been seen.
|
||||
uint64_t counter; // Simple counter for marking purpose with 'seen2'.
|
||||
|
||||
double max_learnts;
|
||||
double learntsize_adjust_confl;
|
||||
int learntsize_adjust_cnt;
|
||||
|
||||
// Resource contraints:
|
||||
//
|
||||
int64_t conflict_budget; // -1 means no budget.
|
||||
int64_t propagation_budget; // -1 means no budget.
|
||||
bool asynch_interrupt;
|
||||
|
||||
// Main internal methods:
|
||||
//
|
||||
void insertVarOrder (Var x); // Insert a variable in the decision order priority queue.
|
||||
Lit pickBranchLit (); // Return the next decision variable.
|
||||
void newDecisionLevel (); // Begins a new decision level.
|
||||
void uncheckedEnqueue (Lit p, CRef from = CRef_Undef); // Enqueue a literal. Assumes value of literal is undefined.
|
||||
bool enqueue (Lit p, CRef from = CRef_Undef); // Test if fact 'p' contradicts current state, enqueue otherwise.
|
||||
CRef propagate (); // Perform unit propagation. Returns possibly conflicting clause.
|
||||
void cancelUntil (int level); // Backtrack until a certain level.
|
||||
void analyze (CRef confl, vec<Lit>& out_learnt, int& out_btlevel, int& out_lbd); // (bt = backtrack)
|
||||
void analyzeFinal (Lit p, vec<Lit>& out_conflict); // COULD THIS BE IMPLEMENTED BY THE ORDINARIY "analyze" BY SOME REASONABLE GENERALIZATION?
|
||||
bool litRedundant (Lit p, uint32_t abstract_levels); // (helper method for 'analyze()')
|
||||
lbool search (int& nof_conflicts); // Search for a given number of conflicts.
|
||||
lbool solve_ (); // Main solve method (assumptions given in 'assumptions').
|
||||
void reduceDB (); // Reduce the set of learnt clauses.
|
||||
void reduceDB_Tier2 ();
|
||||
void removeSatisfied (vec<CRef>& cs); // Shrink 'cs' to contain only non-satisfied clauses.
|
||||
void safeRemoveSatisfiedCompact(vec<CRef>& cs, unsigned valid_mark);
|
||||
void rebuildOrderHeap ();
|
||||
bool binResMinimize (vec<Lit>& out_learnt); // Further learnt clause minimization by binary resolution.
|
||||
|
||||
// Maintaining Variable/Clause activity:
|
||||
//
|
||||
void varDecayActivity (); // Decay all variables with the specified factor. Implemented by increasing the 'bump' value instead.
|
||||
void varBumpActivity (Var v, double mult); // Increase a variable with the current 'bump' value.
|
||||
void claDecayActivity (); // Decay all clauses with the specified factor. Implemented by increasing the 'bump' value instead.
|
||||
void claBumpActivity (Clause& c); // Increase a clause with the current 'bump' value.
|
||||
|
||||
// Operations on clauses:
|
||||
//
|
||||
void attachClause (CRef cr); // Attach a clause to watcher lists.
|
||||
void detachClause (CRef cr, bool strict = false); // Detach a clause to watcher lists.
|
||||
void removeClause (CRef cr); // Detach and free a clause.
|
||||
void removeClauseHack (CRef cr, Lit watched0, Lit watched1);
|
||||
bool locked (const Clause& c) const; // Returns TRUE if a clause is a reason for some implication in the current state.
|
||||
bool satisfied (const Clause& c) const; // Returns TRUE if a clause is satisfied in the current state.
|
||||
|
||||
void relocAll (ClauseAllocator& to);
|
||||
|
||||
// Misc:
|
||||
//
|
||||
int decisionLevel () const; // Gives the current decisionlevel.
|
||||
uint32_t abstractLevel (Var x) const; // Used to represent an abstraction of sets of decision levels.
|
||||
CRef reason (Var x) const;
|
||||
int level (Var x) const;
|
||||
double progressEstimate () const; // DELETE THIS ?? IT'S NOT VERY USEFUL ...
|
||||
bool withinBudget () const;
|
||||
|
||||
template<class V> int computeLBD(const V& c) {
|
||||
int lbd = 0;
|
||||
|
||||
counter++;
|
||||
for (int i = 0; i < c.size(); i++){
|
||||
int l = level(var(c[i]));
|
||||
if (l != 0 && seen2[l] != counter){
|
||||
seen2[l] = counter;
|
||||
lbd++; } }
|
||||
|
||||
return lbd;
|
||||
}
|
||||
|
||||
#ifdef BIN_DRUP
|
||||
static int buf_len;
|
||||
static unsigned char drup_buf[];
|
||||
static unsigned char* buf_ptr;
|
||||
|
||||
static inline void byteDRUP(Lit l){
|
||||
unsigned int u = 2 * (var(l) + 1) + sign(l);
|
||||
do{
|
||||
*buf_ptr++ = u & 0x7f | 0x80; buf_len++;
|
||||
u = u >> 7;
|
||||
}while (u);
|
||||
*(buf_ptr - 1) &= 0x7f; // End marker of this unsigned number.
|
||||
}
|
||||
|
||||
template<class V>
|
||||
static inline void binDRUP(unsigned char op, const V& c, FILE* drup_file){
|
||||
assert(op == 'a' || op == 'd');
|
||||
*buf_ptr++ = op; buf_len++;
|
||||
for (int i = 0; i < c.size(); i++) byteDRUP(c[i]);
|
||||
*buf_ptr++ = 0; buf_len++;
|
||||
if (buf_len > 1048576) binDRUP_flush(drup_file);
|
||||
}
|
||||
|
||||
static inline void binDRUP_strengthen(const Clause& c, Lit l, FILE* drup_file){
|
||||
*buf_ptr++ = 'a'; buf_len++;
|
||||
for (int i = 0; i < c.size(); i++)
|
||||
if (c[i] != l) byteDRUP(c[i]);
|
||||
*buf_ptr++ = 0; buf_len++;
|
||||
if (buf_len > 1048576) binDRUP_flush(drup_file);
|
||||
}
|
||||
|
||||
static inline void binDRUP_flush(FILE* drup_file){
|
||||
fwrite(drup_buf, sizeof(unsigned char), buf_len, drup_file);
|
||||
buf_ptr = drup_buf; buf_len = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Static helpers:
|
||||
//
|
||||
|
||||
// Returns a random float 0 <= x < 1. Seed must never be 0.
|
||||
static inline double drand(double& seed) {
|
||||
seed *= 1389796;
|
||||
int q = (int)(seed / 2147483647);
|
||||
seed -= (double)q * 2147483647;
|
||||
return seed / 2147483647; }
|
||||
|
||||
// Returns a random integer 0 <= x < size. Seed must never be 0.
|
||||
static inline int irand(double& seed, int size) {
|
||||
return (int)(drand(seed) * size); }
|
||||
|
||||
// For (advanced) stamping.
|
||||
struct Frame {
|
||||
enum TYPE { START = 0, ENTER = 1, RETURN = 2, CLOSE = 3 };
|
||||
Lit curr, next;
|
||||
unsigned type : 3;
|
||||
unsigned learnt : 1;
|
||||
Frame(TYPE t, Lit p, Lit q, unsigned l) : curr(p), next(q), type(t), learnt(l) {}
|
||||
};
|
||||
|
||||
vec<int32_t> discovered;
|
||||
vec<int32_t> finished;
|
||||
vec<int32_t> observed;
|
||||
vec<char> flag;
|
||||
vec<Lit> root;
|
||||
vec<Lit> parent;
|
||||
|
||||
vec<Frame> rec_stack;
|
||||
vec<Lit> scc; // Strongly connected component.
|
||||
|
||||
bool stampAll(bool use_bin_learnts);
|
||||
int stamp(Lit p, int stamp_time, bool use_bin_learnts);
|
||||
inline bool implExistsByBin(Lit p, bool use_bin_learnts) const;
|
||||
inline bool isRoot(Lit p, bool use_bin_learnts) const;
|
||||
};
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
// Implementation of inline methods:
|
||||
|
||||
inline CRef Solver::reason(Var x) const { return vardata[x].reason; }
|
||||
inline int Solver::level (Var x) const { return vardata[x].level; }
|
||||
|
||||
inline void Solver::insertVarOrder(Var x) {
|
||||
Heap<VarOrderLt>& order_heap = VSIDS ? order_heap_VSIDS : order_heap_CHB;
|
||||
if (!order_heap.inHeap(x) && decision[x]) order_heap.insert(x); }
|
||||
|
||||
inline void Solver::varDecayActivity() {
|
||||
var_inc *= (1 / var_decay); }
|
||||
|
||||
inline void Solver::varBumpActivity(Var v, double mult) {
|
||||
if ( (activity_VSIDS[v] += var_inc * mult) > 1e100 ) {
|
||||
// Rescale:
|
||||
for (int i = 0; i < nVars(); i++)
|
||||
activity_VSIDS[i] *= 1e-100;
|
||||
var_inc *= 1e-100; }
|
||||
|
||||
// Update order_heap with respect to new activity:
|
||||
if (order_heap_VSIDS.inHeap(v)) order_heap_VSIDS.decrease(v); }
|
||||
|
||||
inline void Solver::claDecayActivity() { cla_inc *= (1 / clause_decay); }
|
||||
inline void Solver::claBumpActivity (Clause& c) {
|
||||
if ( (c.activity() += cla_inc) > 1e20 ) {
|
||||
// Rescale:
|
||||
for (int i = 0; i < learnts_local.size(); i++)
|
||||
ca[learnts_local[i]].activity() *= 1e-20;
|
||||
cla_inc *= 1e-20; } }
|
||||
|
||||
inline void Solver::checkGarbage(void){ return checkGarbage(garbage_frac); }
|
||||
inline void Solver::checkGarbage(double gf){
|
||||
if (ca.wasted() > ca.size() * gf)
|
||||
garbageCollect(); }
|
||||
|
||||
// NOTE: enqueue does not set the ok flag! (only public methods do)
|
||||
inline bool Solver::enqueue (Lit p, CRef from) { return value(p) != l_Undef ? value(p) != l_False : (uncheckedEnqueue(p, from), true); }
|
||||
inline bool Solver::addClause (const vec<Lit>& ps) { ps.copyTo(add_tmp); return addClause_(add_tmp); }
|
||||
inline bool Solver::addEmptyClause () { add_tmp.clear(); return addClause_(add_tmp); }
|
||||
inline bool Solver::addClause (Lit p) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp); }
|
||||
inline bool Solver::addClause (Lit p, Lit q) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp); }
|
||||
inline bool Solver::addClause (Lit p, Lit q, Lit r) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp); }
|
||||
inline bool Solver::locked (const Clause& c) const {
|
||||
int i = c.size() != 2 ? 0 : (value(c[0]) == l_True ? 0 : 1);
|
||||
return value(c[i]) == l_True && reason(var(c[i])) != CRef_Undef && ca.lea(reason(var(c[i]))) == &c;
|
||||
}
|
||||
inline void Solver::newDecisionLevel() { trail_lim.push(trail.size()); }
|
||||
|
||||
inline int Solver::decisionLevel () const { return trail_lim.size(); }
|
||||
inline uint32_t Solver::abstractLevel (Var x) const { return 1 << (level(x) & 31); }
|
||||
inline lbool Solver::value (Var x) const { return assigns[x]; }
|
||||
inline lbool Solver::value (Lit p) const { return assigns[var(p)] ^ sign(p); }
|
||||
inline lbool Solver::modelValue (Var x) const { return model[x]; }
|
||||
inline lbool Solver::modelValue (Lit p) const { return model[var(p)] ^ sign(p); }
|
||||
inline int Solver::nAssigns () const { return trail.size(); }
|
||||
inline int Solver::nClauses () const { return clauses.size(); }
|
||||
inline int Solver::nLearnts () const { return learnts_core.size() + learnts_tier2.size() + learnts_local.size(); }
|
||||
inline int Solver::nVars () const { return vardata.size(); }
|
||||
inline int Solver::nFreeVars () const { return (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]); }
|
||||
inline void Solver::setPolarity (Var v, bool b) { polarity[v] = b; }
|
||||
inline void Solver::setDecisionVar(Var v, bool b)
|
||||
{
|
||||
if ( b && !decision[v]) dec_vars++;
|
||||
else if (!b && decision[v]) dec_vars--;
|
||||
|
||||
decision[v] = b;
|
||||
if (b && !order_heap_CHB.inHeap(v)){
|
||||
order_heap_CHB.insert(v);
|
||||
order_heap_VSIDS.insert(v); }
|
||||
}
|
||||
inline void Solver::setConfBudget(int64_t x){ conflict_budget = conflicts + x; }
|
||||
inline void Solver::setPropBudget(int64_t x){ propagation_budget = propagations + x; }
|
||||
inline void Solver::interrupt(){ asynch_interrupt = true; }
|
||||
inline void Solver::clearInterrupt(){ asynch_interrupt = false; }
|
||||
inline void Solver::budgetOff(){ conflict_budget = propagation_budget = -1; }
|
||||
inline bool Solver::withinBudget() const {
|
||||
return !asynch_interrupt &&
|
||||
(conflict_budget < 0 || conflicts < (uint64_t)conflict_budget) &&
|
||||
(propagation_budget < 0 || propagations < (uint64_t)propagation_budget); }
|
||||
|
||||
// FIXME: after the introduction of asynchronous interrruptions the solve-versions that return a
|
||||
// pure bool do not give a safe interface. Either interrupts must be possible to turn off here, or
|
||||
// all calls to solve must return an 'lbool'. I'm not yet sure which I prefer.
|
||||
inline bool Solver::solve () { budgetOff(); assumptions.clear(); return solve_() == l_True; }
|
||||
inline bool Solver::solve (Lit p) { budgetOff(); assumptions.clear(); assumptions.push(p); return solve_() == l_True; }
|
||||
inline bool Solver::solve (Lit p, Lit q) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); return solve_() == l_True; }
|
||||
inline bool Solver::solve (Lit p, Lit q, Lit r) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); assumptions.push(r); return solve_() == l_True; }
|
||||
inline bool Solver::solve (const vec<Lit>& assumps){ budgetOff(); assumps.copyTo(assumptions); return solve_() == l_True; }
|
||||
inline lbool Solver::solveLimited (const vec<Lit>& assumps){ assumps.copyTo(assumptions); return solve_(); }
|
||||
inline bool Solver::okay () const { return ok; }
|
||||
|
||||
inline void Solver::toDimacs (const char* file){ vec<Lit> as; toDimacs(file, as); }
|
||||
inline void Solver::toDimacs (const char* file, Lit p){ vec<Lit> as; as.push(p); toDimacs(file, as); }
|
||||
inline void Solver::toDimacs (const char* file, Lit p, Lit q){ vec<Lit> as; as.push(p); as.push(q); toDimacs(file, as); }
|
||||
inline void Solver::toDimacs (const char* file, Lit p, Lit q, Lit r){ vec<Lit> as; as.push(p); as.push(q); as.push(r); toDimacs(file, as); }
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
// Debug etc:
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,426 @@
|
|||
/***********************************************************************************[SolverTypes.h]
|
||||
MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
|
||||
Copyright (c) 2007-2010, Niklas Sorensson
|
||||
|
||||
Chanseok Oh's MiniSat Patch Series -- Copyright (c) 2015, Chanseok Oh
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
|
||||
#ifndef Minisat_SolverTypes_h
|
||||
#define Minisat_SolverTypes_h
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "mtl/IntTypes.h"
|
||||
#include "mtl/Alg.h"
|
||||
#include "mtl/Vec.h"
|
||||
#include "mtl/Map.h"
|
||||
#include "mtl/Alloc.h"
|
||||
|
||||
namespace Minisat {
|
||||
|
||||
//=================================================================================================
|
||||
// Variables, literals, lifted booleans, clauses:
|
||||
|
||||
|
||||
// NOTE! Variables are just integers. No abstraction here. They should be chosen from 0..N,
|
||||
// so that they can be used as array indices.
|
||||
|
||||
typedef int Var;
|
||||
#define var_Undef (-1)
|
||||
|
||||
|
||||
struct Lit {
|
||||
int x;
|
||||
|
||||
// Use this as a constructor:
|
||||
friend Lit mkLit(Var var, bool sign);
|
||||
|
||||
bool operator == (Lit p) const { return x == p.x; }
|
||||
bool operator != (Lit p) const { return x != p.x; }
|
||||
bool operator < (Lit p) const { return x < p.x; } // '<' makes p, ~p adjacent in the ordering.
|
||||
};
|
||||
|
||||
|
||||
inline Lit mkLit (Var var, bool sign = false) { Lit p; p.x = var + var + (int)sign; return p; }
|
||||
inline Lit operator ~(Lit p) { Lit q; q.x = p.x ^ 1; return q; }
|
||||
inline Lit operator ^(Lit p, bool b) { Lit q; q.x = p.x ^ (unsigned int)b; return q; }
|
||||
inline bool sign (Lit p) { return p.x & 1; }
|
||||
inline int var (Lit p) { return p.x >> 1; }
|
||||
|
||||
// Mapping Literals to and from compact integers suitable for array indexing:
|
||||
inline int toInt (Var v) { return v; }
|
||||
inline int toInt (Lit p) { return p.x; }
|
||||
inline Lit toLit (int i) { Lit p; p.x = i; return p; }
|
||||
|
||||
//const Lit lit_Undef = mkLit(var_Undef, false); // }- Useful special constants.
|
||||
//const Lit lit_Error = mkLit(var_Undef, true ); // }
|
||||
|
||||
const Lit lit_Undef = { -2 }; // }- Useful special constants.
|
||||
const Lit lit_Error = { -1 }; // }
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
// Lifted booleans:
|
||||
//
|
||||
// NOTE: this implementation is optimized for the case when comparisons between values are mostly
|
||||
// between one variable and one constant. Some care had to be taken to make sure that gcc
|
||||
// does enough constant propagation to produce sensible code, and this appears to be somewhat
|
||||
// fragile unfortunately.
|
||||
|
||||
#define l_True (lbool((uint8_t)0)) // gcc does not do constant propagation if these are real constants.
|
||||
#define l_False (lbool((uint8_t)1))
|
||||
#define l_Undef (lbool((uint8_t)2))
|
||||
|
||||
class lbool {
|
||||
uint8_t value;
|
||||
|
||||
public:
|
||||
explicit lbool(uint8_t v) : value(v) { }
|
||||
|
||||
lbool() : value(0) { }
|
||||
explicit lbool(bool x) : value(!x) { }
|
||||
|
||||
bool operator == (lbool b) const { return ((b.value&2) & (value&2)) | (!(b.value&2)&(value == b.value)); }
|
||||
bool operator != (lbool b) const { return !(*this == b); }
|
||||
lbool operator ^ (bool b) const { return lbool((uint8_t)(value^(uint8_t)b)); }
|
||||
|
||||
lbool operator && (lbool b) const {
|
||||
uint8_t sel = (this->value << 1) | (b.value << 3);
|
||||
uint8_t v = (0xF7F755F4 >> sel) & 3;
|
||||
return lbool(v); }
|
||||
|
||||
lbool operator || (lbool b) const {
|
||||
uint8_t sel = (this->value << 1) | (b.value << 3);
|
||||
uint8_t v = (0xFCFCF400 >> sel) & 3;
|
||||
return lbool(v); }
|
||||
|
||||
friend int toInt (lbool l);
|
||||
friend lbool toLbool(int v);
|
||||
};
|
||||
inline int toInt (lbool l) { return l.value; }
|
||||
inline lbool toLbool(int v) { return lbool((uint8_t)v); }
|
||||
|
||||
//=================================================================================================
|
||||
// Clause -- a simple class for representing a clause:
|
||||
|
||||
class Clause;
|
||||
typedef RegionAllocator<uint32_t>::Ref CRef;
|
||||
|
||||
class Clause {
|
||||
struct {
|
||||
unsigned mark : 2;
|
||||
unsigned learnt : 1;
|
||||
unsigned has_extra : 1;
|
||||
unsigned reloced : 1;
|
||||
unsigned lbd : 26;
|
||||
unsigned removable : 1;
|
||||
unsigned size : 32; } header;
|
||||
union { Lit lit; float act; uint32_t abs; uint32_t touched; CRef rel; } data[0];
|
||||
|
||||
friend class ClauseAllocator;
|
||||
|
||||
// NOTE: This constructor cannot be used directly (doesn't allocate enough memory).
|
||||
template<class V>
|
||||
Clause(const V& ps, bool use_extra, bool learnt) {
|
||||
header.mark = 0;
|
||||
header.learnt = learnt;
|
||||
header.has_extra = learnt | use_extra;
|
||||
header.reloced = 0;
|
||||
header.size = ps.size();
|
||||
header.lbd = 0;
|
||||
header.removable = 1;
|
||||
|
||||
for (int i = 0; i < ps.size(); i++)
|
||||
data[i].lit = ps[i];
|
||||
|
||||
if (header.has_extra){
|
||||
if (header.learnt){
|
||||
data[header.size].act = 0;
|
||||
data[header.size+1].touched = 0;
|
||||
}else
|
||||
calcAbstraction(); }
|
||||
}
|
||||
|
||||
public:
|
||||
void calcAbstraction() {
|
||||
assert(header.has_extra);
|
||||
uint32_t abstraction = 0;
|
||||
for (int i = 0; i < size(); i++)
|
||||
abstraction |= 1 << (var(data[i].lit) & 31);
|
||||
data[header.size].abs = abstraction; }
|
||||
|
||||
|
||||
int size () const { return header.size; }
|
||||
void shrink (int i) { assert(i <= size()); if (header.has_extra) data[header.size-i] = data[header.size]; header.size -= i; }
|
||||
void pop () { shrink(1); }
|
||||
bool learnt () const { return header.learnt; }
|
||||
bool has_extra () const { return header.has_extra; }
|
||||
uint32_t mark () const { return header.mark; }
|
||||
void mark (uint32_t m) { header.mark = m; }
|
||||
const Lit& last () const { return data[header.size-1].lit; }
|
||||
|
||||
bool reloced () const { return header.reloced; }
|
||||
CRef relocation () const { return data[0].rel; }
|
||||
void relocate (CRef c) { header.reloced = 1; data[0].rel = c; }
|
||||
|
||||
int lbd () const { return header.lbd; }
|
||||
void set_lbd (int lbd) { header.lbd = lbd; }
|
||||
bool removable () const { return header.removable; }
|
||||
void removable (bool b) { header.removable = b; }
|
||||
|
||||
// NOTE: somewhat unsafe to change the clause in-place! Must manually call 'calcAbstraction' afterwards for
|
||||
// subsumption operations to behave correctly.
|
||||
Lit& operator [] (int i) { return data[i].lit; }
|
||||
Lit operator [] (int i) const { return data[i].lit; }
|
||||
operator const Lit* (void) const { return (Lit*)data; }
|
||||
|
||||
uint32_t& touched () { assert(header.has_extra && header.learnt); return data[header.size+1].touched; }
|
||||
float& activity () { assert(header.has_extra); return data[header.size].act; }
|
||||
uint32_t abstraction () const { assert(header.has_extra); return data[header.size].abs; }
|
||||
|
||||
Lit subsumes (const Clause& other) const;
|
||||
void strengthen (Lit p);
|
||||
};
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
// ClauseAllocator -- a simple class for allocating memory for clauses:
|
||||
|
||||
|
||||
const CRef CRef_Undef = RegionAllocator<uint32_t>::Ref_Undef;
|
||||
class ClauseAllocator : public RegionAllocator<uint32_t>
|
||||
{
|
||||
static int clauseWord32Size(int size, int extras){
|
||||
return (sizeof(Clause) + (sizeof(Lit) * (size + extras))) / sizeof(uint32_t); }
|
||||
public:
|
||||
bool extra_clause_field;
|
||||
|
||||
ClauseAllocator(uint32_t start_cap) : RegionAllocator<uint32_t>(start_cap), extra_clause_field(false){}
|
||||
ClauseAllocator() : extra_clause_field(false){}
|
||||
|
||||
void moveTo(ClauseAllocator& to){
|
||||
to.extra_clause_field = extra_clause_field;
|
||||
RegionAllocator<uint32_t>::moveTo(to); }
|
||||
|
||||
template<class Lits>
|
||||
CRef alloc(const Lits& ps, bool learnt = false)
|
||||
{
|
||||
assert(sizeof(Lit) == sizeof(uint32_t));
|
||||
assert(sizeof(float) == sizeof(uint32_t));
|
||||
int extras = learnt ? 2 : (int)extra_clause_field;
|
||||
|
||||
CRef cid = RegionAllocator<uint32_t>::alloc(clauseWord32Size(ps.size(), extras));
|
||||
new (lea(cid)) Clause(ps, extra_clause_field, learnt);
|
||||
|
||||
return cid;
|
||||
}
|
||||
|
||||
// Deref, Load Effective Address (LEA), Inverse of LEA (AEL):
|
||||
Clause& operator[](Ref r) { return (Clause&)RegionAllocator<uint32_t>::operator[](r); }
|
||||
const Clause& operator[](Ref r) const { return (Clause&)RegionAllocator<uint32_t>::operator[](r); }
|
||||
Clause* lea (Ref r) { return (Clause*)RegionAllocator<uint32_t>::lea(r); }
|
||||
const Clause* lea (Ref r) const { return (Clause*)RegionAllocator<uint32_t>::lea(r); }
|
||||
Ref ael (const Clause* t){ return RegionAllocator<uint32_t>::ael((uint32_t*)t); }
|
||||
|
||||
void free(CRef cid)
|
||||
{
|
||||
Clause& c = operator[](cid);
|
||||
int extras = c.learnt() ? 2 : (int)c.has_extra();
|
||||
RegionAllocator<uint32_t>::free(clauseWord32Size(c.size(), extras));
|
||||
}
|
||||
|
||||
void reloc(CRef& cr, ClauseAllocator& to)
|
||||
{
|
||||
Clause& c = operator[](cr);
|
||||
|
||||
if (c.reloced()) { cr = c.relocation(); return; }
|
||||
|
||||
cr = to.alloc(c, c.learnt());
|
||||
c.relocate(cr);
|
||||
|
||||
// Copy extra data-fields:
|
||||
// (This could be cleaned-up. Generalize Clause-constructor to be applicable here instead?)
|
||||
to[cr].mark(c.mark());
|
||||
if (to[cr].learnt()){
|
||||
to[cr].touched() = c.touched();
|
||||
to[cr].activity() = c.activity();
|
||||
to[cr].set_lbd(c.lbd());
|
||||
to[cr].removable(c.removable());
|
||||
}
|
||||
else if (to[cr].has_extra()) to[cr].calcAbstraction();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
// OccLists -- a class for maintaining occurence lists with lazy deletion:
|
||||
|
||||
template<class Idx, class Vec, class Deleted>
|
||||
class OccLists
|
||||
{
|
||||
vec<Vec> occs;
|
||||
vec<char> dirty;
|
||||
vec<Idx> dirties;
|
||||
Deleted deleted;
|
||||
|
||||
public:
|
||||
OccLists(const Deleted& d) : deleted(d) {}
|
||||
|
||||
void init (const Idx& idx){ occs.growTo(toInt(idx)+1); dirty.growTo(toInt(idx)+1, 0); }
|
||||
const Vec& operator[](const Idx& idx) const { return occs[toInt(idx)]; }
|
||||
Vec& operator[](const Idx& idx){ return occs[toInt(idx)]; }
|
||||
Vec& lookup (const Idx& idx){ if (dirty[toInt(idx)]) clean(idx); return occs[toInt(idx)]; }
|
||||
|
||||
void cleanAll ();
|
||||
void clean (const Idx& idx);
|
||||
void smudge (const Idx& idx){
|
||||
if (dirty[toInt(idx)] == 0){
|
||||
dirty[toInt(idx)] = 1;
|
||||
dirties.push(idx);
|
||||
}
|
||||
}
|
||||
|
||||
void clear(bool free = true){
|
||||
occs .clear(free);
|
||||
dirty .clear(free);
|
||||
dirties.clear(free);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class Idx, class Vec, class Deleted>
|
||||
void OccLists<Idx,Vec,Deleted>::cleanAll()
|
||||
{
|
||||
for (int i = 0; i < dirties.size(); i++)
|
||||
// Dirties may contain duplicates so check here if a variable is already cleaned:
|
||||
if (dirty[toInt(dirties[i])])
|
||||
clean(dirties[i]);
|
||||
dirties.clear();
|
||||
}
|
||||
|
||||
|
||||
template<class Idx, class Vec, class Deleted>
|
||||
void OccLists<Idx,Vec,Deleted>::clean(const Idx& idx)
|
||||
{
|
||||
Vec& vec = occs[toInt(idx)];
|
||||
int i, j;
|
||||
for (i = j = 0; i < vec.size(); i++)
|
||||
if (!deleted(vec[i]))
|
||||
vec[j++] = vec[i];
|
||||
vec.shrink(i - j);
|
||||
dirty[toInt(idx)] = 0;
|
||||
}
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
// CMap -- a class for mapping clauses to values:
|
||||
|
||||
|
||||
template<class T>
|
||||
class CMap
|
||||
{
|
||||
struct CRefHash {
|
||||
uint32_t operator()(CRef cr) const { return (uint32_t)cr; } };
|
||||
|
||||
typedef Map<CRef, T, CRefHash> HashTable;
|
||||
HashTable map;
|
||||
|
||||
public:
|
||||
// Size-operations:
|
||||
void clear () { map.clear(); }
|
||||
int size () const { return map.elems(); }
|
||||
|
||||
|
||||
// Insert/Remove/Test mapping:
|
||||
void insert (CRef cr, const T& t){ map.insert(cr, t); }
|
||||
void growTo (CRef cr, const T& t){ map.insert(cr, t); } // NOTE: for compatibility
|
||||
void remove (CRef cr) { map.remove(cr); }
|
||||
bool has (CRef cr, T& t) { return map.peek(cr, t); }
|
||||
|
||||
// Vector interface (the clause 'c' must already exist):
|
||||
const T& operator [] (CRef cr) const { return map[cr]; }
|
||||
T& operator [] (CRef cr) { return map[cr]; }
|
||||
|
||||
// Iteration (not transparent at all at the moment):
|
||||
int bucket_count() const { return map.bucket_count(); }
|
||||
const vec<typename HashTable::Pair>& bucket(int i) const { return map.bucket(i); }
|
||||
|
||||
// Move contents to other map:
|
||||
void moveTo(CMap& other){ map.moveTo(other.map); }
|
||||
|
||||
// TMP debug:
|
||||
void debug(){
|
||||
printf(" --- size = %d, bucket_count = %d\n", size(), map.bucket_count()); }
|
||||
};
|
||||
|
||||
|
||||
/*_________________________________________________________________________________________________
|
||||
|
|
||||
| subsumes : (other : const Clause&) -> Lit
|
||||
|
|
||||
| Description:
|
||||
| Checks if clause subsumes 'other', and at the same time, if it can be used to simplify 'other'
|
||||
| by subsumption resolution.
|
||||
|
|
||||
| Result:
|
||||
| lit_Error - No subsumption or simplification
|
||||
| lit_Undef - Clause subsumes 'other'
|
||||
| p - The literal p can be deleted from 'other'
|
||||
|________________________________________________________________________________________________@*/
|
||||
inline Lit Clause::subsumes(const Clause& other) const
|
||||
{
|
||||
//if (other.size() < size() || (extra.abst & ~other.extra.abst) != 0)
|
||||
//if (other.size() < size() || (!learnt() && !other.learnt() && (extra.abst & ~other.extra.abst) != 0))
|
||||
assert(!header.learnt); assert(!other.header.learnt);
|
||||
assert(header.has_extra); assert(other.header.has_extra);
|
||||
if (other.header.size < header.size || (data[header.size].abs & ~other.data[other.header.size].abs) != 0)
|
||||
return lit_Error;
|
||||
|
||||
Lit ret = lit_Undef;
|
||||
const Lit* c = (const Lit*)(*this);
|
||||
const Lit* d = (const Lit*)other;
|
||||
|
||||
for (unsigned i = 0; i < header.size; i++) {
|
||||
// search for c[i] or ~c[i]
|
||||
for (unsigned j = 0; j < other.header.size; j++)
|
||||
if (c[i] == d[j])
|
||||
goto ok;
|
||||
else if (ret == lit_Undef && c[i] == ~d[j]){
|
||||
ret = c[i];
|
||||
goto ok;
|
||||
}
|
||||
|
||||
// did not find it
|
||||
return lit_Error;
|
||||
ok:;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline void Clause::strengthen(Lit p)
|
||||
{
|
||||
remove(*this, p);
|
||||
calcAbstraction();
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,79 @@
|
|||
Release Notes for MiniSat 2.2.0
|
||||
===============================
|
||||
|
||||
Changes since version 2.0:
|
||||
|
||||
* Started using a more standard release numbering.
|
||||
|
||||
* Includes some now well-known heuristics: phase-saving and luby
|
||||
restarts. The old heuristics are still present and can be activated
|
||||
if needed.
|
||||
|
||||
* Detection/Handling of out-of-memory and vector capacity
|
||||
overflow. This is fairly new and relatively untested.
|
||||
|
||||
* Simple resource controls: CPU-time, memory, number of
|
||||
conflicts/decisions.
|
||||
|
||||
* CPU-time limiting is implemented by a more general, but simple,
|
||||
asynchronous interruption feature. This means that the solving
|
||||
procedure can be interrupted from another thread or in a signal
|
||||
handler.
|
||||
|
||||
* Improved portability with respect to building on Solaris and with
|
||||
Visual Studio. This is not regularly tested and chances are that
|
||||
this have been broken since, but should be fairly easy to fix if
|
||||
so.
|
||||
|
||||
* Changed C++ file-extention to the less problematic ".cc".
|
||||
|
||||
* Source code is now namespace-protected
|
||||
|
||||
* Introducing a new Clause Memory Allocator that brings reduced
|
||||
memory consumption on 64-bit architechtures and improved
|
||||
performance (to some extent). The allocator uses a region-based
|
||||
approach were all references to clauses are represented as a 32-bit
|
||||
index into a global memory region that contains all clauses. To
|
||||
free up and compact memory it uses a simple copying garbage
|
||||
collector.
|
||||
|
||||
* Improved unit-propagation by Blocking Literals. For each entry in
|
||||
the watcher lists, pair the pointer to a clause with some
|
||||
(arbitrary) literal from the clause. The idea is that if the
|
||||
literal is currently true (i.e. the clause is satisfied) the
|
||||
watchers of the clause does not need to be altered. This can thus
|
||||
be detected without touching the clause's memory at all. As often
|
||||
as can be done cheaply, the blocking literal for entries to the
|
||||
watcher list of a literal 'p' is set to the other literal watched
|
||||
in the corresponding clause.
|
||||
|
||||
* Basic command-line/option handling system. Makes it easy to specify
|
||||
options in the class that they affect, and whenever that class is
|
||||
used in an executable, parsing of options and help messages are
|
||||
brought in automatically.
|
||||
|
||||
* General clean-up and various minor bug-fixes.
|
||||
|
||||
* Changed implementation of variable-elimination/model-extension:
|
||||
|
||||
- The interface is changed so that arbitrary remembering is no longer
|
||||
possible. If you need to mention some variable again in the future,
|
||||
this variable has to be frozen.
|
||||
|
||||
- When eliminating a variable, only clauses that contain the variable
|
||||
with one sign is necessary to store. Thereby making the other sign
|
||||
a "default" value when extending models.
|
||||
|
||||
- The memory consumption for eliminated clauses is further improved
|
||||
by storing all eliminated clauses in a single contiguous vector.
|
||||
|
||||
* Some common utility code (I/O, Parsing, CPU-time, etc) is ripped
|
||||
out and placed in a separate "utils" directory.
|
||||
|
||||
* The DIMACS parse is refactored so that it can be reused in other
|
||||
applications (not very elegant, but at least possible).
|
||||
|
||||
* Some simple improvements to scalability of preprocessing, using
|
||||
more lazy clause removal from data-structures and a couple of
|
||||
ad-hoc limits (the longest clause that can be produced in variable
|
||||
elimination, and the longest clause used in backward subsumption).
|
|
@ -0,0 +1,84 @@
|
|||
/*******************************************************************************************[Alg.h]
|
||||
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
|
||||
Copyright (c) 2007-2010, Niklas Sorensson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#ifndef Minisat_Alg_h
|
||||
#define Minisat_Alg_h
|
||||
|
||||
#include "mtl/Vec.h"
|
||||
|
||||
namespace Minisat {
|
||||
|
||||
//=================================================================================================
|
||||
// Useful functions on vector-like types:
|
||||
|
||||
//=================================================================================================
|
||||
// Removing and searching for elements:
|
||||
//
|
||||
|
||||
template<class V, class T>
|
||||
static inline void remove(V& ts, const T& t)
|
||||
{
|
||||
int j = 0;
|
||||
for (; j < ts.size() && ts[j] != t; j++);
|
||||
assert(j < ts.size());
|
||||
for (; j < ts.size()-1; j++) ts[j] = ts[j+1];
|
||||
ts.pop();
|
||||
}
|
||||
|
||||
|
||||
template<class V, class T>
|
||||
static inline bool find(V& ts, const T& t)
|
||||
{
|
||||
int j = 0;
|
||||
for (; j < ts.size() && ts[j] != t; j++);
|
||||
return j < ts.size();
|
||||
}
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
// Copying vectors with support for nested vector types:
|
||||
//
|
||||
|
||||
// Base case:
|
||||
template<class T>
|
||||
static inline void copy(const T& from, T& to)
|
||||
{
|
||||
to = from;
|
||||
}
|
||||
|
||||
// Recursive case:
|
||||
template<class T>
|
||||
static inline void copy(const vec<T>& from, vec<T>& to, bool append = false)
|
||||
{
|
||||
if (!append)
|
||||
to.clear();
|
||||
for (int i = 0; i < from.size(); i++){
|
||||
to.push();
|
||||
copy(from[i], to.last());
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static inline void append(const vec<T>& from, vec<T>& to){ copy(from, to, true); }
|
||||
|
||||
//=================================================================================================
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,131 @@
|
|||
/*****************************************************************************************[Alloc.h]
|
||||
Copyright (c) 2008-2010, Niklas Sorensson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
|
||||
#ifndef Minisat_Alloc_h
|
||||
#define Minisat_Alloc_h
|
||||
|
||||
#include "mtl/XAlloc.h"
|
||||
#include "mtl/Vec.h"
|
||||
|
||||
namespace Minisat {
|
||||
|
||||
//=================================================================================================
|
||||
// Simple Region-based memory allocator:
|
||||
|
||||
template<class T>
|
||||
class RegionAllocator
|
||||
{
|
||||
T* memory;
|
||||
uint32_t sz;
|
||||
uint32_t cap;
|
||||
uint32_t wasted_;
|
||||
|
||||
void capacity(uint32_t min_cap);
|
||||
|
||||
public:
|
||||
// TODO: make this a class for better type-checking?
|
||||
typedef uint32_t Ref;
|
||||
enum { Ref_Undef = UINT32_MAX };
|
||||
enum { Unit_Size = sizeof(uint32_t) };
|
||||
|
||||
explicit RegionAllocator(uint32_t start_cap = 1024*1024) : memory(NULL), sz(0), cap(0), wasted_(0){ capacity(start_cap); }
|
||||
~RegionAllocator()
|
||||
{
|
||||
if (memory != NULL)
|
||||
::free(memory);
|
||||
}
|
||||
|
||||
|
||||
uint32_t size () const { return sz; }
|
||||
uint32_t wasted () const { return wasted_; }
|
||||
|
||||
Ref alloc (int size);
|
||||
void free (int size) { wasted_ += size; }
|
||||
|
||||
// Deref, Load Effective Address (LEA), Inverse of LEA (AEL):
|
||||
T& operator[](Ref r) { assert(r >= 0 && r < sz); return memory[r]; }
|
||||
const T& operator[](Ref r) const { assert(r >= 0 && r < sz); return memory[r]; }
|
||||
|
||||
T* lea (Ref r) { assert(r >= 0 && r < sz); return &memory[r]; }
|
||||
const T* lea (Ref r) const { assert(r >= 0 && r < sz); return &memory[r]; }
|
||||
Ref ael (const T* t) { assert((void*)t >= (void*)&memory[0] && (void*)t < (void*)&memory[sz-1]);
|
||||
return (Ref)(t - &memory[0]); }
|
||||
|
||||
void moveTo(RegionAllocator& to) {
|
||||
if (to.memory != NULL) ::free(to.memory);
|
||||
to.memory = memory;
|
||||
to.sz = sz;
|
||||
to.cap = cap;
|
||||
to.wasted_ = wasted_;
|
||||
|
||||
memory = NULL;
|
||||
sz = cap = wasted_ = 0;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
template<class T>
|
||||
void RegionAllocator<T>::capacity(uint32_t min_cap)
|
||||
{
|
||||
if (cap >= min_cap) return;
|
||||
|
||||
uint32_t prev_cap = cap;
|
||||
while (cap < min_cap){
|
||||
// NOTE: Multiply by a factor (13/8) without causing overflow, then add 2 and make the
|
||||
// result even by clearing the least significant bit. The resulting sequence of capacities
|
||||
// is carefully chosen to hit a maximum capacity that is close to the '2^32-1' limit when
|
||||
// using 'uint32_t' as indices so that as much as possible of this space can be used.
|
||||
uint32_t delta = ((cap >> 1) + (cap >> 3) + 2) & ~1;
|
||||
cap += delta;
|
||||
|
||||
if (cap <= prev_cap)
|
||||
throw OutOfMemoryException();
|
||||
}
|
||||
// printf(" .. (%p) cap = %u\n", this, cap);
|
||||
|
||||
assert(cap > 0);
|
||||
memory = (T*)xrealloc(memory, sizeof(T)*cap);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
typename RegionAllocator<T>::Ref
|
||||
RegionAllocator<T>::alloc(int size)
|
||||
{
|
||||
// printf("ALLOC called (this = %p, size = %d)\n", this, size); fflush(stdout);
|
||||
assert(size > 0);
|
||||
capacity(sz + size);
|
||||
|
||||
uint32_t prev_sz = sz;
|
||||
sz += size;
|
||||
|
||||
// Handle overflow:
|
||||
if (sz < prev_sz)
|
||||
throw OutOfMemoryException();
|
||||
|
||||
return prev_sz;
|
||||
}
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,148 @@
|
|||
/******************************************************************************************[Heap.h]
|
||||
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
|
||||
Copyright (c) 2007-2010, Niklas Sorensson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#ifndef Minisat_Heap_h
|
||||
#define Minisat_Heap_h
|
||||
|
||||
#include "mtl/Vec.h"
|
||||
|
||||
namespace Minisat {
|
||||
|
||||
//=================================================================================================
|
||||
// A heap implementation with support for decrease/increase key.
|
||||
|
||||
|
||||
template<class Comp>
|
||||
class Heap {
|
||||
Comp lt; // The heap is a minimum-heap with respect to this comparator
|
||||
vec<int> heap; // Heap of integers
|
||||
vec<int> indices; // Each integers position (index) in the Heap
|
||||
|
||||
// Index "traversal" functions
|
||||
static inline int left (int i) { return i*2+1; }
|
||||
static inline int right (int i) { return (i+1)*2; }
|
||||
static inline int parent(int i) { return (i-1) >> 1; }
|
||||
|
||||
|
||||
void percolateUp(int i)
|
||||
{
|
||||
int x = heap[i];
|
||||
int p = parent(i);
|
||||
|
||||
while (i != 0 && lt(x, heap[p])){
|
||||
heap[i] = heap[p];
|
||||
indices[heap[p]] = i;
|
||||
i = p;
|
||||
p = parent(p);
|
||||
}
|
||||
heap [i] = x;
|
||||
indices[x] = i;
|
||||
}
|
||||
|
||||
|
||||
void percolateDown(int i)
|
||||
{
|
||||
int x = heap[i];
|
||||
while (left(i) < heap.size()){
|
||||
int child = right(i) < heap.size() && lt(heap[right(i)], heap[left(i)]) ? right(i) : left(i);
|
||||
if (!lt(heap[child], x)) break;
|
||||
heap[i] = heap[child];
|
||||
indices[heap[i]] = i;
|
||||
i = child;
|
||||
}
|
||||
heap [i] = x;
|
||||
indices[x] = i;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
Heap(const Comp& c) : lt(c) { }
|
||||
|
||||
int size () const { return heap.size(); }
|
||||
bool empty () const { return heap.size() == 0; }
|
||||
bool inHeap (int n) const { return n < indices.size() && indices[n] >= 0; }
|
||||
int operator[](int index) const { assert(index < heap.size()); return heap[index]; }
|
||||
|
||||
|
||||
void decrease (int n) { assert(inHeap(n)); percolateUp (indices[n]); }
|
||||
void increase (int n) { assert(inHeap(n)); percolateDown(indices[n]); }
|
||||
|
||||
|
||||
// Safe variant of insert/decrease/increase:
|
||||
void update(int n)
|
||||
{
|
||||
if (!inHeap(n))
|
||||
insert(n);
|
||||
else {
|
||||
percolateUp(indices[n]);
|
||||
percolateDown(indices[n]); }
|
||||
}
|
||||
|
||||
|
||||
void insert(int n)
|
||||
{
|
||||
indices.growTo(n+1, -1);
|
||||
assert(!inHeap(n));
|
||||
|
||||
indices[n] = heap.size();
|
||||
heap.push(n);
|
||||
percolateUp(indices[n]);
|
||||
}
|
||||
|
||||
|
||||
int removeMin()
|
||||
{
|
||||
int x = heap[0];
|
||||
heap[0] = heap.last();
|
||||
indices[heap[0]] = 0;
|
||||
indices[x] = -1;
|
||||
heap.pop();
|
||||
if (heap.size() > 1) percolateDown(0);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
// Rebuild the heap from scratch, using the elements in 'ns':
|
||||
void build(const vec<int>& ns) {
|
||||
for (int i = 0; i < heap.size(); i++)
|
||||
indices[heap[i]] = -1;
|
||||
heap.clear();
|
||||
|
||||
for (int i = 0; i < ns.size(); i++){
|
||||
indices[ns[i]] = i;
|
||||
heap.push(ns[i]); }
|
||||
|
||||
for (int i = heap.size() / 2 - 1; i >= 0; i--)
|
||||
percolateDown(i);
|
||||
}
|
||||
|
||||
void clear(bool dealloc = false)
|
||||
{
|
||||
for (int i = 0; i < heap.size(); i++)
|
||||
indices[heap[i]] = -1;
|
||||
heap.clear(dealloc);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,42 @@
|
|||
/**************************************************************************************[IntTypes.h]
|
||||
Copyright (c) 2009-2010, Niklas Sorensson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#ifndef Minisat_IntTypes_h
|
||||
#define Minisat_IntTypes_h
|
||||
|
||||
#ifdef __sun
|
||||
// Not sure if there are newer versions that support C99 headers. The
|
||||
// needed features are implemented in the headers below though:
|
||||
|
||||
# include <sys/int_types.h>
|
||||
# include <sys/int_fmtio.h>
|
||||
# include <sys/int_limits.h>
|
||||
|
||||
#else
|
||||
|
||||
# include <stdint.h>
|
||||
# include <inttypes.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
#endif
|
|
@ -0,0 +1,193 @@
|
|||
/*******************************************************************************************[Map.h]
|
||||
Copyright (c) 2006-2010, Niklas Sorensson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#ifndef Minisat_Map_h
|
||||
#define Minisat_Map_h
|
||||
|
||||
#include "mtl/IntTypes.h"
|
||||
#include "mtl/Vec.h"
|
||||
|
||||
namespace Minisat {
|
||||
|
||||
//=================================================================================================
|
||||
// Default hash/equals functions
|
||||
//
|
||||
|
||||
template<class K> struct Hash { uint32_t operator()(const K& k) const { return hash(k); } };
|
||||
template<class K> struct Equal { bool operator()(const K& k1, const K& k2) const { return k1 == k2; } };
|
||||
|
||||
template<class K> struct DeepHash { uint32_t operator()(const K* k) const { return hash(*k); } };
|
||||
template<class K> struct DeepEqual { bool operator()(const K* k1, const K* k2) const { return *k1 == *k2; } };
|
||||
|
||||
static inline uint32_t hash(uint32_t x){ return x; }
|
||||
static inline uint32_t hash(uint64_t x){ return (uint32_t)x; }
|
||||
static inline uint32_t hash(int32_t x) { return (uint32_t)x; }
|
||||
static inline uint32_t hash(int64_t x) { return (uint32_t)x; }
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
// Some primes
|
||||
//
|
||||
|
||||
static const int nprimes = 25;
|
||||
static const int primes [nprimes] = { 31, 73, 151, 313, 643, 1291, 2593, 5233, 10501, 21013, 42073, 84181, 168451, 337219, 674701, 1349473, 2699299, 5398891, 10798093, 21596719, 43193641, 86387383, 172775299, 345550609, 691101253 };
|
||||
|
||||
//=================================================================================================
|
||||
// Hash table implementation of Maps
|
||||
//
|
||||
|
||||
template<class K, class D, class H = Hash<K>, class E = Equal<K> >
|
||||
class Map {
|
||||
public:
|
||||
struct Pair { K key; D data; };
|
||||
|
||||
private:
|
||||
H hash;
|
||||
E equals;
|
||||
|
||||
vec<Pair>* table;
|
||||
int cap;
|
||||
int size;
|
||||
|
||||
// Don't allow copying (error prone):
|
||||
Map<K,D,H,E>& operator = (Map<K,D,H,E>& other) { assert(0); }
|
||||
Map (Map<K,D,H,E>& other) { assert(0); }
|
||||
|
||||
bool checkCap(int new_size) const { return new_size > cap; }
|
||||
|
||||
int32_t index (const K& k) const { return hash(k) % cap; }
|
||||
void _insert (const K& k, const D& d) {
|
||||
vec<Pair>& ps = table[index(k)];
|
||||
ps.push(); ps.last().key = k; ps.last().data = d; }
|
||||
|
||||
void rehash () {
|
||||
const vec<Pair>* old = table;
|
||||
|
||||
int old_cap = cap;
|
||||
int newsize = primes[0];
|
||||
for (int i = 1; newsize <= cap && i < nprimes; i++)
|
||||
newsize = primes[i];
|
||||
|
||||
table = new vec<Pair>[newsize];
|
||||
cap = newsize;
|
||||
|
||||
for (int i = 0; i < old_cap; i++){
|
||||
for (int j = 0; j < old[i].size(); j++){
|
||||
_insert(old[i][j].key, old[i][j].data); }}
|
||||
|
||||
delete [] old;
|
||||
|
||||
// printf(" --- rehashing, old-cap=%d, new-cap=%d\n", cap, newsize);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
Map () : table(NULL), cap(0), size(0) {}
|
||||
Map (const H& h, const E& e) : hash(h), equals(e), table(NULL), cap(0), size(0){}
|
||||
~Map () { delete [] table; }
|
||||
|
||||
// PRECONDITION: the key must already exist in the map.
|
||||
const D& operator [] (const K& k) const
|
||||
{
|
||||
assert(size != 0);
|
||||
const D* res = NULL;
|
||||
const vec<Pair>& ps = table[index(k)];
|
||||
for (int i = 0; i < ps.size(); i++)
|
||||
if (equals(ps[i].key, k))
|
||||
res = &ps[i].data;
|
||||
assert(res != NULL);
|
||||
return *res;
|
||||
}
|
||||
|
||||
// PRECONDITION: the key must already exist in the map.
|
||||
D& operator [] (const K& k)
|
||||
{
|
||||
assert(size != 0);
|
||||
D* res = NULL;
|
||||
vec<Pair>& ps = table[index(k)];
|
||||
for (int i = 0; i < ps.size(); i++)
|
||||
if (equals(ps[i].key, k))
|
||||
res = &ps[i].data;
|
||||
assert(res != NULL);
|
||||
return *res;
|
||||
}
|
||||
|
||||
// PRECONDITION: the key must *NOT* exist in the map.
|
||||
void insert (const K& k, const D& d) { if (checkCap(size+1)) rehash(); _insert(k, d); size++; }
|
||||
bool peek (const K& k, D& d) const {
|
||||
if (size == 0) return false;
|
||||
const vec<Pair>& ps = table[index(k)];
|
||||
for (int i = 0; i < ps.size(); i++)
|
||||
if (equals(ps[i].key, k)){
|
||||
d = ps[i].data;
|
||||
return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
bool has (const K& k) const {
|
||||
if (size == 0) return false;
|
||||
const vec<Pair>& ps = table[index(k)];
|
||||
for (int i = 0; i < ps.size(); i++)
|
||||
if (equals(ps[i].key, k))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// PRECONDITION: the key must exist in the map.
|
||||
void remove(const K& k) {
|
||||
assert(table != NULL);
|
||||
vec<Pair>& ps = table[index(k)];
|
||||
int j = 0;
|
||||
for (; j < ps.size() && !equals(ps[j].key, k); j++);
|
||||
assert(j < ps.size());
|
||||
ps[j] = ps.last();
|
||||
ps.pop();
|
||||
size--;
|
||||
}
|
||||
|
||||
void clear () {
|
||||
cap = size = 0;
|
||||
delete [] table;
|
||||
table = NULL;
|
||||
}
|
||||
|
||||
int elems() const { return size; }
|
||||
int bucket_count() const { return cap; }
|
||||
|
||||
// NOTE: the hash and equality objects are not moved by this method:
|
||||
void moveTo(Map& other){
|
||||
delete [] other.table;
|
||||
|
||||
other.table = table;
|
||||
other.cap = cap;
|
||||
other.size = size;
|
||||
|
||||
table = NULL;
|
||||
size = cap = 0;
|
||||
}
|
||||
|
||||
// NOTE: given a bit more time, I could make a more C++-style iterator out of this:
|
||||
const vec<Pair>& bucket(int i) const { return table[i]; }
|
||||
};
|
||||
|
||||
//=================================================================================================
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,69 @@
|
|||
/*****************************************************************************************[Queue.h]
|
||||
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
|
||||
Copyright (c) 2007-2010, Niklas Sorensson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#ifndef Minisat_Queue_h
|
||||
#define Minisat_Queue_h
|
||||
|
||||
#include "mtl/Vec.h"
|
||||
|
||||
namespace Minisat {
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
template<class T>
|
||||
class Queue {
|
||||
vec<T> buf;
|
||||
int first;
|
||||
int end;
|
||||
|
||||
public:
|
||||
typedef T Key;
|
||||
|
||||
Queue() : buf(1), first(0), end(0) {}
|
||||
|
||||
void clear (bool dealloc = false) { buf.clear(dealloc); buf.growTo(1); first = end = 0; }
|
||||
int size () const { return (end >= first) ? end - first : end - first + buf.size(); }
|
||||
|
||||
const T& operator [] (int index) const { assert(index >= 0); assert(index < size()); return buf[(first + index) % buf.size()]; }
|
||||
T& operator [] (int index) { assert(index >= 0); assert(index < size()); return buf[(first + index) % buf.size()]; }
|
||||
|
||||
T peek () const { assert(first != end); return buf[first]; }
|
||||
void pop () { assert(first != end); first++; if (first == buf.size()) first = 0; }
|
||||
void insert(T elem) { // INVARIANT: buf[end] is always unused
|
||||
buf[end++] = elem;
|
||||
if (end == buf.size()) end = 0;
|
||||
if (first == end){ // Resize:
|
||||
vec<T> tmp((buf.size()*3 + 1) >> 1);
|
||||
//**/printf("queue alloc: %d elems (%.1f MB)\n", tmp.size(), tmp.size() * sizeof(T) / 1000000.0);
|
||||
int i = 0;
|
||||
for (int j = first; j < buf.size(); j++) tmp[i++] = buf[j];
|
||||
for (int j = 0 ; j < end ; j++) tmp[i++] = buf[j];
|
||||
first = 0;
|
||||
end = buf.size();
|
||||
tmp.moveTo(buf);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,98 @@
|
|||
/******************************************************************************************[Sort.h]
|
||||
Copyright (c) 2003-2007, Niklas Een, Niklas Sorensson
|
||||
Copyright (c) 2007-2010, Niklas Sorensson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#ifndef Minisat_Sort_h
|
||||
#define Minisat_Sort_h
|
||||
|
||||
#include "mtl/Vec.h"
|
||||
|
||||
//=================================================================================================
|
||||
// Some sorting algorithms for vec's
|
||||
|
||||
|
||||
namespace Minisat {
|
||||
|
||||
template<class T>
|
||||
struct LessThan_default {
|
||||
bool operator () (T x, T y) { return x < y; }
|
||||
};
|
||||
|
||||
|
||||
template <class T, class LessThan>
|
||||
void selectionSort(T* array, int size, LessThan lt)
|
||||
{
|
||||
int i, j, best_i;
|
||||
T tmp;
|
||||
|
||||
for (i = 0; i < size-1; i++){
|
||||
best_i = i;
|
||||
for (j = i+1; j < size; j++){
|
||||
if (lt(array[j], array[best_i]))
|
||||
best_i = j;
|
||||
}
|
||||
tmp = array[i]; array[i] = array[best_i]; array[best_i] = tmp;
|
||||
}
|
||||
}
|
||||
template <class T> static inline void selectionSort(T* array, int size) {
|
||||
selectionSort(array, size, LessThan_default<T>()); }
|
||||
|
||||
template <class T, class LessThan>
|
||||
void sort(T* array, int size, LessThan lt)
|
||||
{
|
||||
if (size <= 15)
|
||||
selectionSort(array, size, lt);
|
||||
|
||||
else{
|
||||
T pivot = array[size / 2];
|
||||
T tmp;
|
||||
int i = -1;
|
||||
int j = size;
|
||||
|
||||
for(;;){
|
||||
do i++; while(lt(array[i], pivot));
|
||||
do j--; while(lt(pivot, array[j]));
|
||||
|
||||
if (i >= j) break;
|
||||
|
||||
tmp = array[i]; array[i] = array[j]; array[j] = tmp;
|
||||
}
|
||||
|
||||
sort(array , i , lt);
|
||||
sort(&array[i], size-i, lt);
|
||||
}
|
||||
}
|
||||
template <class T> static inline void sort(T* array, int size) {
|
||||
sort(array, size, LessThan_default<T>()); }
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
// For 'vec's:
|
||||
|
||||
|
||||
template <class T, class LessThan> void sort(vec<T>& v, LessThan lt) {
|
||||
sort((T*)v, v.size(), lt); }
|
||||
template <class T> void sort(vec<T>& v) {
|
||||
sort(v, LessThan_default<T>()); }
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,130 @@
|
|||
/*******************************************************************************************[Vec.h]
|
||||
Copyright (c) 2003-2007, Niklas Een, Niklas Sorensson
|
||||
Copyright (c) 2007-2010, Niklas Sorensson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#ifndef Minisat_Vec_h
|
||||
#define Minisat_Vec_h
|
||||
|
||||
#include <assert.h>
|
||||
#include <new>
|
||||
|
||||
#include "mtl/IntTypes.h"
|
||||
#include "mtl/XAlloc.h"
|
||||
|
||||
namespace Minisat {
|
||||
|
||||
//=================================================================================================
|
||||
// Automatically resizable arrays
|
||||
//
|
||||
// NOTE! Don't use this vector on datatypes that cannot be re-located in memory (with realloc)
|
||||
|
||||
template<class T>
|
||||
class vec {
|
||||
T* data;
|
||||
int sz;
|
||||
int cap;
|
||||
|
||||
// Don't allow copying (error prone):
|
||||
vec<T>& operator = (vec<T>& other) { assert(0); return *this; }
|
||||
vec (vec<T>& other) { assert(0); }
|
||||
|
||||
// Helpers for calculating next capacity:
|
||||
static inline int imax (int x, int y) { int mask = (y-x) >> (sizeof(int)*8-1); return (x&mask) + (y&(~mask)); }
|
||||
//static inline void nextCap(int& cap){ cap += ((cap >> 1) + 2) & ~1; }
|
||||
static inline void nextCap(int& cap){ cap += ((cap >> 1) + 2) & ~1; }
|
||||
|
||||
public:
|
||||
// Constructors:
|
||||
vec() : data(NULL) , sz(0) , cap(0) { }
|
||||
explicit vec(int size) : data(NULL) , sz(0) , cap(0) { growTo(size); }
|
||||
vec(int size, const T& pad) : data(NULL) , sz(0) , cap(0) { growTo(size, pad); }
|
||||
~vec() { clear(true); }
|
||||
|
||||
// Pointer to first element:
|
||||
operator T* (void) { return data; }
|
||||
|
||||
// Size operations:
|
||||
int size (void) const { return sz; }
|
||||
void shrink (int nelems) { assert(nelems <= sz); for (int i = 0; i < nelems; i++) sz--, data[sz].~T(); }
|
||||
void shrink_ (int nelems) { assert(nelems <= sz); sz -= nelems; }
|
||||
int capacity (void) const { return cap; }
|
||||
void capacity (int min_cap);
|
||||
void growTo (int size);
|
||||
void growTo (int size, const T& pad);
|
||||
void clear (bool dealloc = false);
|
||||
|
||||
// Stack interface:
|
||||
void push (void) { if (sz == cap) capacity(sz+1); new (&data[sz]) T(); sz++; }
|
||||
void push (const T& elem) { if (sz == cap) capacity(sz+1); data[sz++] = elem; }
|
||||
void push_ (const T& elem) { assert(sz < cap); data[sz++] = elem; }
|
||||
void pop (void) { assert(sz > 0); sz--, data[sz].~T(); }
|
||||
// NOTE: it seems possible that overflow can happen in the 'sz+1' expression of 'push()', but
|
||||
// in fact it can not since it requires that 'cap' is equal to INT_MAX. This in turn can not
|
||||
// happen given the way capacities are calculated (below). Essentially, all capacities are
|
||||
// even, but INT_MAX is odd.
|
||||
|
||||
const T& last (void) const { return data[sz-1]; }
|
||||
T& last (void) { return data[sz-1]; }
|
||||
|
||||
// Vector interface:
|
||||
const T& operator [] (int index) const { return data[index]; }
|
||||
T& operator [] (int index) { return data[index]; }
|
||||
|
||||
// Duplicatation (preferred instead):
|
||||
void copyTo(vec<T>& copy) const { copy.clear(); copy.growTo(sz); for (int i = 0; i < sz; i++) copy[i] = data[i]; }
|
||||
void moveTo(vec<T>& dest) { dest.clear(true); dest.data = data; dest.sz = sz; dest.cap = cap; data = NULL; sz = 0; cap = 0; }
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
void vec<T>::capacity(int min_cap) {
|
||||
if (cap >= min_cap) return;
|
||||
int add = imax((min_cap - cap + 1) & ~1, ((cap >> 1) + 2) & ~1); // NOTE: grow by approximately 3/2
|
||||
if (add > INT_MAX - cap || ((data = (T*)::realloc(data, (cap += add) * sizeof(T))) == NULL) && errno == ENOMEM)
|
||||
throw OutOfMemoryException();
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
void vec<T>::growTo(int size, const T& pad) {
|
||||
if (sz >= size) return;
|
||||
capacity(size);
|
||||
for (int i = sz; i < size; i++) data[i] = pad;
|
||||
sz = size; }
|
||||
|
||||
|
||||
template<class T>
|
||||
void vec<T>::growTo(int size) {
|
||||
if (sz >= size) return;
|
||||
capacity(size);
|
||||
for (int i = sz; i < size; i++) new (&data[i]) T();
|
||||
sz = size; }
|
||||
|
||||
|
||||
template<class T>
|
||||
void vec<T>::clear(bool dealloc) {
|
||||
if (data != NULL){
|
||||
for (int i = 0; i < sz; i++) data[i].~T();
|
||||
sz = 0;
|
||||
if (dealloc) free(data), data = NULL, cap = 0; } }
|
||||
|
||||
//=================================================================================================
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,45 @@
|
|||
/****************************************************************************************[XAlloc.h]
|
||||
Copyright (c) 2009-2010, Niklas Sorensson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
|
||||
#ifndef Minisat_XAlloc_h
|
||||
#define Minisat_XAlloc_h
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace Minisat {
|
||||
|
||||
//=================================================================================================
|
||||
// Simple layer on top of malloc/realloc to catch out-of-memory situtaions and provide some typing:
|
||||
|
||||
class OutOfMemoryException{};
|
||||
static inline void* xrealloc(void *ptr, size_t size)
|
||||
{
|
||||
void* mem = realloc(ptr, size);
|
||||
if (mem == NULL && errno == ENOMEM){
|
||||
throw OutOfMemoryException();
|
||||
}else
|
||||
return mem;
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
##
|
||||
## This file is for system specific configurations. For instance, on
|
||||
## some systems the path to zlib needs to be added. Example:
|
||||
##
|
||||
## CFLAGS += -I/usr/local/include
|
||||
## LFLAGS += -L/usr/local/lib
|
|
@ -0,0 +1,107 @@
|
|||
##
|
||||
## Template makefile for Standard, Profile, Debug, Release, and Release-static versions
|
||||
##
|
||||
## eg: "make rs" for a statically linked release version.
|
||||
## "make d" for a debug version (no optimizations).
|
||||
## "make" for the standard version (optimized, but with debug information and assertions active)
|
||||
|
||||
PWD = $(shell pwd)
|
||||
EXEC ?= $(notdir $(PWD))
|
||||
|
||||
CSRCS = $(wildcard $(PWD)/*.cc)
|
||||
DSRCS = $(foreach dir, $(DEPDIR), $(filter-out $(MROOT)/$(dir)/Main.cc, $(wildcard $(MROOT)/$(dir)/*.cc)))
|
||||
CHDRS = $(wildcard $(PWD)/*.h)
|
||||
COBJS = $(CSRCS:.cc=.o) $(DSRCS:.cc=.o)
|
||||
|
||||
PCOBJS = $(addsuffix p, $(COBJS))
|
||||
DCOBJS = $(addsuffix d, $(COBJS))
|
||||
RCOBJS = $(addsuffix r, $(COBJS))
|
||||
|
||||
|
||||
CXX ?= g++
|
||||
CFLAGS ?= -Wall -Wno-parentheses
|
||||
LFLAGS ?= -Wall
|
||||
|
||||
COPTIMIZE ?= -O3
|
||||
|
||||
CFLAGS += -I$(MROOT) -D __STDC_LIMIT_MACROS -D __STDC_FORMAT_MACROS
|
||||
LFLAGS += -lz
|
||||
|
||||
.PHONY : s p d r rs clean
|
||||
|
||||
s: $(EXEC)
|
||||
p: $(EXEC)_profile
|
||||
d: $(EXEC)_debug
|
||||
r: $(EXEC)_release
|
||||
rs: $(EXEC)_static
|
||||
|
||||
libs: lib$(LIB)_standard.a
|
||||
libp: lib$(LIB)_profile.a
|
||||
libd: lib$(LIB)_debug.a
|
||||
libr: lib$(LIB)_release.a
|
||||
|
||||
## Compile options
|
||||
%.o: CFLAGS +=$(COPTIMIZE) -g -D DEBUG
|
||||
%.op: CFLAGS +=$(COPTIMIZE) -pg -g -D NDEBUG
|
||||
%.od: CFLAGS +=-O0 -g -D DEBUG
|
||||
%.or: CFLAGS +=$(COPTIMIZE) -g -D NDEBUG
|
||||
|
||||
## Link options
|
||||
$(EXEC): LFLAGS += -g
|
||||
$(EXEC)_profile: LFLAGS += -g -pg
|
||||
$(EXEC)_debug: LFLAGS += -g
|
||||
#$(EXEC)_release: LFLAGS += ...
|
||||
$(EXEC)_static: LFLAGS += --static
|
||||
|
||||
## Dependencies
|
||||
$(EXEC): $(COBJS)
|
||||
$(EXEC)_profile: $(PCOBJS)
|
||||
$(EXEC)_debug: $(DCOBJS)
|
||||
$(EXEC)_release: $(RCOBJS)
|
||||
$(EXEC)_static: $(RCOBJS)
|
||||
|
||||
lib$(LIB)_standard.a: $(filter-out */Main.o, $(COBJS))
|
||||
lib$(LIB)_profile.a: $(filter-out */Main.op, $(PCOBJS))
|
||||
lib$(LIB)_debug.a: $(filter-out */Main.od, $(DCOBJS))
|
||||
lib$(LIB)_release.a: $(filter-out */Main.or, $(RCOBJS))
|
||||
|
||||
|
||||
## Build rule
|
||||
%.o %.op %.od %.or: %.cc
|
||||
@echo Compiling: $(subst $(MROOT)/,,$@)
|
||||
@$(CXX) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
## Linking rules (standard/profile/debug/release)
|
||||
$(EXEC) $(EXEC)_profile $(EXEC)_debug $(EXEC)_release $(EXEC)_static:
|
||||
@echo Linking: "$@ ( $(foreach f,$^,$(subst $(MROOT)/,,$f)) )"
|
||||
@$(CXX) $^ $(LFLAGS) -o $@
|
||||
|
||||
## Library rules (standard/profile/debug/release)
|
||||
lib$(LIB)_standard.a lib$(LIB)_profile.a lib$(LIB)_release.a lib$(LIB)_debug.a:
|
||||
@echo Making library: "$@ ( $(foreach f,$^,$(subst $(MROOT)/,,$f)) )"
|
||||
@$(AR) -rcsv $@ $^
|
||||
|
||||
## Library Soft Link rule:
|
||||
libs libp libd libr:
|
||||
@echo "Making Soft Link: $^ -> lib$(LIB).a"
|
||||
@ln -sf $^ lib$(LIB).a
|
||||
|
||||
## Clean rule
|
||||
clean:
|
||||
@rm -f $(EXEC) $(EXEC)_profile $(EXEC)_debug $(EXEC)_release $(EXEC)_static \
|
||||
$(COBJS) $(PCOBJS) $(DCOBJS) $(RCOBJS) *.core depend.mk
|
||||
|
||||
## Make dependencies
|
||||
depend.mk: $(CSRCS) $(CHDRS)
|
||||
@echo Making dependencies
|
||||
@$(CXX) $(CFLAGS) -I$(MROOT) \
|
||||
$(CSRCS) -MM | sed 's|\(.*\):|$(PWD)/\1 $(PWD)/\1r $(PWD)/\1d $(PWD)/\1p:|' > depend.mk
|
||||
@for dir in $(DEPDIR); do \
|
||||
if [ -r $(MROOT)/$${dir}/depend.mk ]; then \
|
||||
echo Depends on: $${dir}; \
|
||||
cat $(MROOT)/$${dir}/depend.mk >> depend.mk; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
-include $(MROOT)/mtl/config.mk
|
||||
-include depend.mk
|
|
@ -0,0 +1,251 @@
|
|||
/*****************************************************************************************[Main.cc]
|
||||
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
|
||||
Copyright (c) 2007, Niklas Sorensson
|
||||
|
||||
Chanseok Oh's MiniSat Patch Series -- Copyright (c) 2015, Chanseok Oh
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <zlib.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "utils/System.h"
|
||||
#include "utils/ParseUtils.h"
|
||||
#include "utils/Options.h"
|
||||
#include "core/Dimacs.h"
|
||||
#include "simp/SimpSolver.h"
|
||||
|
||||
using namespace Minisat;
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
|
||||
void printStats(Solver& solver)
|
||||
{
|
||||
double cpu_time = cpuTime();
|
||||
// double mem_used = memUsedPeak();
|
||||
// printf("c restarts : %"PRIu64"\n", solver.starts);
|
||||
// printf("c conflicts : %-12"PRIu64" (%.0f /sec)\n", solver.conflicts , solver.conflicts /cpu_time);
|
||||
// printf("c decisions : %-12"PRIu64" (%4.2f %% random) (%.0f /sec)\n", solver.decisions, (float)solver.rnd_decisions*100 / (float)solver.decisions, solver.decisions /cpu_time);
|
||||
// printf("c propagations : %-12"PRIu64" (%.0f /sec)\n", solver.propagations, solver.propagations/cpu_time);
|
||||
// printf("c conflict literals : %-12"PRIu64" (%4.2f %% deleted)\n", solver.tot_literals, (solver.max_literals - solver.tot_literals)*100 / (double)solver.max_literals);
|
||||
// if (mem_used != 0) printf("c Memory used : %.2f MB\n", mem_used);
|
||||
printf("c CPU time : %g s\n", cpu_time);
|
||||
}
|
||||
|
||||
|
||||
static Solver* solver;
|
||||
// Terminate by notifying the solver and back out gracefully. This is mainly to have a test-case
|
||||
// for this feature of the Solver as it may take longer than an immediate call to '_exit()'.
|
||||
static void SIGINT_interrupt(int signum) { solver->interrupt(); }
|
||||
|
||||
// Note that '_exit()' rather than 'exit()' has to be used. The reason is that 'exit()' calls
|
||||
// destructors and may cause deadlocks if a malloc/free function happens to be running (these
|
||||
// functions are guarded by locks for multithreaded use).
|
||||
static void SIGINT_exit(int signum) {
|
||||
printf("\n"); printf("c *** INTERRUPTED ***\n");
|
||||
if (solver->verbosity > 0){
|
||||
printStats(*solver);
|
||||
printf("\n"); printf("c *** INTERRUPTED ***\n"); }
|
||||
_exit(1); }
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
// Main:
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
try {
|
||||
setUsageHelp("USAGE: %s [options] <input-file> <result-output-file>\n\n where input may be either in plain or gzipped DIMACS.\n");
|
||||
printf("c This is COMiniSatPS.\n");
|
||||
|
||||
#if defined(__linux__)
|
||||
fpu_control_t oldcw, newcw;
|
||||
_FPU_GETCW(oldcw); newcw = (oldcw & ~_FPU_EXTENDED) | _FPU_DOUBLE; _FPU_SETCW(newcw);
|
||||
printf("c WARNING: for repeatability, setting FPU to use double precision\n");
|
||||
#endif
|
||||
// Extra options:
|
||||
//
|
||||
IntOption verb ("MAIN", "verb", "Verbosity level (0=silent, 1=some, 2=more).", 1, IntRange(0, 2));
|
||||
BoolOption pre ("MAIN", "pre", "Completely turn on/off any preprocessing.", true);
|
||||
StringOption dimacs ("MAIN", "dimacs", "If given, stop after preprocessing and write the result to this file.");
|
||||
IntOption cpu_lim("MAIN", "cpu-lim","Limit on CPU time allowed in seconds.\n", INT32_MAX, IntRange(0, INT32_MAX));
|
||||
IntOption mem_lim("MAIN", "mem-lim","Limit on memory usage in megabytes.\n", INT32_MAX, IntRange(0, INT32_MAX));
|
||||
BoolOption drup ("MAIN", "drup", "Generate DRUP UNSAT proof.", false);
|
||||
StringOption drup_file("MAIN", "drup-file", "DRUP UNSAT proof ouput file.", "");
|
||||
|
||||
parseOptions(argc, argv, true);
|
||||
|
||||
SimpSolver S;
|
||||
double initial_time = cpuTime();
|
||||
|
||||
if (!pre) S.eliminate(true);
|
||||
|
||||
S.parsing = true;
|
||||
S.verbosity = verb;
|
||||
if (drup || strlen(drup_file)){
|
||||
S.drup_file = strlen(drup_file) ? fopen(drup_file, "wb") : stdout;
|
||||
if (S.drup_file == NULL){
|
||||
S.drup_file = stdout;
|
||||
printf("c Error opening %s for write.\n", (const char*) drup_file); }
|
||||
printf("c DRUP proof generation: %s\n", S.drup_file == stdout ? "stdout" : drup_file);
|
||||
}
|
||||
|
||||
solver = &S;
|
||||
// Use signal handlers that forcibly quit until the solver will be able to respond to
|
||||
// interrupts:
|
||||
signal(SIGINT, SIGINT_exit);
|
||||
signal(SIGXCPU,SIGINT_exit);
|
||||
|
||||
// Set limit on CPU-time:
|
||||
if (cpu_lim != INT32_MAX){
|
||||
rlimit rl;
|
||||
getrlimit(RLIMIT_CPU, &rl);
|
||||
if (rl.rlim_max == RLIM_INFINITY || (rlim_t)cpu_lim < rl.rlim_max){
|
||||
rl.rlim_cur = cpu_lim;
|
||||
if (setrlimit(RLIMIT_CPU, &rl) == -1)
|
||||
printf("c WARNING! Could not set resource limit: CPU-time.\n");
|
||||
} }
|
||||
|
||||
// Set limit on virtual memory:
|
||||
if (mem_lim != INT32_MAX){
|
||||
rlim_t new_mem_lim = (rlim_t)mem_lim * 1024*1024;
|
||||
rlimit rl;
|
||||
getrlimit(RLIMIT_AS, &rl);
|
||||
if (rl.rlim_max == RLIM_INFINITY || new_mem_lim < rl.rlim_max){
|
||||
rl.rlim_cur = new_mem_lim;
|
||||
if (setrlimit(RLIMIT_AS, &rl) == -1)
|
||||
printf("c WARNING! Could not set resource limit: Virtual memory.\n");
|
||||
} }
|
||||
|
||||
if (argc == 1)
|
||||
printf("c Reading from standard input... Use '--help' for help.\n");
|
||||
|
||||
gzFile in = (argc == 1) ? gzdopen(0, "rb") : gzopen(argv[1], "rb");
|
||||
if (in == NULL)
|
||||
printf("c ERROR! Could not open file: %s\n", argc == 1 ? "<stdin>" : argv[1]), exit(1);
|
||||
|
||||
if (S.verbosity > 0){
|
||||
printf("c ============================[ Problem Statistics ]=============================\n");
|
||||
printf("c | |\n"); }
|
||||
|
||||
parse_DIMACS(in, S);
|
||||
gzclose(in);
|
||||
FILE* res = (argc >= 3) ? fopen(argv[2], "wb") : NULL;
|
||||
|
||||
if (S.verbosity > 0){
|
||||
printf("c | Number of variables: %12d |\n", S.nVars());
|
||||
printf("c | Number of clauses: %12d |\n", S.nClauses()); }
|
||||
|
||||
double parsed_time = cpuTime();
|
||||
if (S.verbosity > 0)
|
||||
printf("c | Parse time: %12.2f s |\n", parsed_time - initial_time);
|
||||
|
||||
// Change to signal-handlers that will only notify the solver and allow it to terminate
|
||||
// voluntarily:
|
||||
// signal(SIGINT, SIGINT_interrupt);
|
||||
// signal(SIGXCPU,SIGINT_interrupt);
|
||||
|
||||
S.parsing = false;
|
||||
S.eliminate(true);
|
||||
double simplified_time = cpuTime();
|
||||
if (S.verbosity > 0){
|
||||
printf("c | Simplification time: %12.2f s |\n", simplified_time - parsed_time);
|
||||
printf("c | |\n"); }
|
||||
|
||||
if (!S.okay()){
|
||||
if (res != NULL) fprintf(res, "UNSAT\n"), fclose(res);
|
||||
if (S.verbosity > 0){
|
||||
printf("c ===============================================================================\n");
|
||||
printf("c Solved by simplification\n");
|
||||
printStats(S);
|
||||
printf("\n"); }
|
||||
printf("s UNSATISFIABLE\n");
|
||||
if (S.drup_file){
|
||||
#ifdef BIN_DRUP
|
||||
fputc('a', S.drup_file); fputc(0, S.drup_file);
|
||||
#else
|
||||
fprintf(S.drup_file, "0\n");
|
||||
#endif
|
||||
}
|
||||
if (S.drup_file && S.drup_file != stdout) fclose(S.drup_file);
|
||||
exit(20);
|
||||
}
|
||||
|
||||
if (dimacs){
|
||||
if (S.verbosity > 0)
|
||||
printf("c ==============================[ Writing DIMACS ]===============================\n");
|
||||
S.toDimacs((const char*)dimacs);
|
||||
if (S.verbosity > 0)
|
||||
printStats(S);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
vec<Lit> dummy;
|
||||
lbool ret = S.solveLimited(dummy);
|
||||
|
||||
if (S.verbosity > 0){
|
||||
printStats(S);
|
||||
printf("\n"); }
|
||||
printf(ret == l_True ? "s SATISFIABLE\n" : ret == l_False ? "s UNSATISFIABLE\n" : "s UNKNOWN\n");
|
||||
// Do not flush stdout
|
||||
// if (ret == l_True){
|
||||
// printf("v ");
|
||||
// for (int i = 0; i < S.nVars(); i++)
|
||||
// if (S.model[i] != l_Undef)
|
||||
// printf("%s%s%d", (i==0)?"":" ", (S.model[i]==l_True)?"":"-", i+1);
|
||||
// printf(" 0\n");
|
||||
// }
|
||||
|
||||
if (S.drup_file && ret == l_False){
|
||||
#ifdef BIN_DRUP
|
||||
fputc('a', S.drup_file); fputc(0, S.drup_file);
|
||||
#else
|
||||
fprintf(S.drup_file, "0\n");
|
||||
#endif
|
||||
}
|
||||
if (S.drup_file && S.drup_file != stdout) fclose(S.drup_file);
|
||||
|
||||
if (res != NULL){
|
||||
if (ret == l_True){
|
||||
fprintf(res, "SAT\n");
|
||||
for (int i = 0; i < S.nVars(); i++)
|
||||
if (S.model[i] != l_Undef)
|
||||
fprintf(res, "%s%s%d", (i==0)?"":" ", (S.model[i]==l_True)?"":"-", i+1);
|
||||
fprintf(res, " 0\n");
|
||||
}else if (ret == l_False)
|
||||
fprintf(res, "UNSAT\n");
|
||||
else
|
||||
fprintf(res, "INDET\n");
|
||||
fclose(res);
|
||||
}
|
||||
|
||||
#ifdef NDEBUG
|
||||
exit(ret == l_True ? 10 : ret == l_False ? 20 : 0); // (faster than "return", which will invoke the destructor for 'Solver')
|
||||
#else
|
||||
return (ret == l_True ? 10 : ret == l_False ? 20 : 0);
|
||||
#endif
|
||||
} catch (OutOfMemoryException&){
|
||||
printf("c ===============================================================================\n");
|
||||
printf("c Out of memory\n");
|
||||
printf("s UNKNOWN\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
EXEC = minisat
|
||||
DEPDIR = mtl utils core
|
||||
|
||||
include $(MROOT)/mtl/template.mk
|
|
@ -0,0 +1,825 @@
|
|||
/***********************************************************************************[SimpSolver.cc]
|
||||
MiniSat -- Copyright (c) 2006, Niklas Een, Niklas Sorensson
|
||||
Copyright (c) 2007-2010, Niklas Sorensson
|
||||
|
||||
Chanseok Oh's MiniSat Patch Series -- Copyright (c) 2015, Chanseok Oh
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#include "mtl/Sort.h"
|
||||
#include "simp/SimpSolver.h"
|
||||
#include "utils/System.h"
|
||||
|
||||
using namespace Minisat;
|
||||
|
||||
//=================================================================================================
|
||||
// Options:
|
||||
|
||||
|
||||
static const char* _cat = "SIMP";
|
||||
|
||||
static BoolOption opt_use_asymm (_cat, "asymm", "Shrink clauses by asymmetric branching.", false);
|
||||
static BoolOption opt_use_rcheck (_cat, "rcheck", "Check if a clause is already implied. (costly)", false);
|
||||
static BoolOption opt_use_elim (_cat, "elim", "Perform variable elimination.", true);
|
||||
static IntOption opt_grow (_cat, "grow", "Allow a variable elimination step to grow by a number of clauses.", 0);
|
||||
static IntOption opt_clause_lim (_cat, "cl-lim", "Variables are not eliminated if it produces a resolvent with a length above this limit. -1 means no limit", 20, IntRange(-1, INT32_MAX));
|
||||
static IntOption opt_subsumption_lim (_cat, "sub-lim", "Do not check if subsumption against a clause larger than this. -1 means no limit.", 1000, IntRange(-1, INT32_MAX));
|
||||
static DoubleOption opt_simp_garbage_frac(_cat, "simp-gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered during simplification.", 0.5, DoubleRange(0, false, HUGE_VAL, false));
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
// Constructor/Destructor:
|
||||
|
||||
|
||||
SimpSolver::SimpSolver() :
|
||||
parsing (false)
|
||||
, grow (opt_grow)
|
||||
, clause_lim (opt_clause_lim)
|
||||
, subsumption_lim (opt_subsumption_lim)
|
||||
, simp_garbage_frac (opt_simp_garbage_frac)
|
||||
, use_asymm (opt_use_asymm)
|
||||
, use_rcheck (opt_use_rcheck)
|
||||
, use_elim (opt_use_elim)
|
||||
, merges (0)
|
||||
, asymm_lits (0)
|
||||
, eliminated_vars (0)
|
||||
, elimorder (1)
|
||||
, use_simplification (true)
|
||||
, occurs (ClauseDeleted(ca))
|
||||
, elim_heap (ElimLt(n_occ))
|
||||
, bwdsub_assigns (0)
|
||||
, n_touched (0)
|
||||
{
|
||||
vec<Lit> dummy(1,lit_Undef);
|
||||
ca.extra_clause_field = true; // NOTE: must happen before allocating the dummy clause below.
|
||||
bwdsub_tmpunit = ca.alloc(dummy);
|
||||
remove_satisfied = false;
|
||||
}
|
||||
|
||||
|
||||
SimpSolver::~SimpSolver()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Var SimpSolver::newVar(bool sign, bool dvar) {
|
||||
Var v = Solver::newVar(sign, dvar);
|
||||
|
||||
frozen .push((char)false);
|
||||
eliminated.push((char)false);
|
||||
|
||||
if (use_simplification){
|
||||
n_occ .push(0);
|
||||
n_occ .push(0);
|
||||
occurs .init(v);
|
||||
touched .push(0);
|
||||
elim_heap .insert(v);
|
||||
}
|
||||
return v; }
|
||||
|
||||
|
||||
|
||||
lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp)
|
||||
{
|
||||
vec<Var> extra_frozen;
|
||||
lbool result = l_True;
|
||||
|
||||
do_simp &= use_simplification;
|
||||
|
||||
if (do_simp){
|
||||
// Assumptions must be temporarily frozen to run variable elimination:
|
||||
for (int i = 0; i < assumptions.size(); i++){
|
||||
Var v = var(assumptions[i]);
|
||||
|
||||
// If an assumption has been eliminated, remember it.
|
||||
assert(!isEliminated(v));
|
||||
|
||||
if (!frozen[v]){
|
||||
// Freeze and store.
|
||||
setFrozen(v, true);
|
||||
extra_frozen.push(v);
|
||||
} }
|
||||
|
||||
result = lbool(eliminate(turn_off_simp));
|
||||
}
|
||||
|
||||
if (result == l_True)
|
||||
result = Solver::solve_();
|
||||
else if (verbosity >= 1)
|
||||
printf("c ===============================================================================\n");
|
||||
|
||||
if (result == l_True)
|
||||
extendModel();
|
||||
|
||||
if (do_simp)
|
||||
// Unfreeze the assumptions that were frozen:
|
||||
for (int i = 0; i < extra_frozen.size(); i++)
|
||||
setFrozen(extra_frozen[i], false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool SimpSolver::addClause_(vec<Lit>& ps)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
for (int i = 0; i < ps.size(); i++)
|
||||
assert(!isEliminated(var(ps[i])));
|
||||
#endif
|
||||
|
||||
int nclauses = clauses.size();
|
||||
|
||||
if (use_rcheck && implied(ps))
|
||||
return true;
|
||||
|
||||
if (!Solver::addClause_(ps))
|
||||
return false;
|
||||
|
||||
if (!parsing && drup_file) {
|
||||
#ifdef BIN_DRUP
|
||||
binDRUP('a', ps, drup_file);
|
||||
#else
|
||||
for (int i = 0; i < ps.size(); i++)
|
||||
fprintf(drup_file, "%i ", (var(ps[i]) + 1) * (-2 * sign(ps[i]) + 1));
|
||||
fprintf(drup_file, "0\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (use_simplification && clauses.size() == nclauses + 1){
|
||||
CRef cr = clauses.last();
|
||||
const Clause& c = ca[cr];
|
||||
|
||||
// NOTE: the clause is added to the queue immediately and then
|
||||
// again during 'gatherTouchedClauses()'. If nothing happens
|
||||
// in between, it will only be checked once. Otherwise, it may
|
||||
// be checked twice unnecessarily. This is an unfortunate
|
||||
// consequence of how backward subsumption is used to mimic
|
||||
// forward subsumption.
|
||||
subsumption_queue.insert(cr);
|
||||
for (int i = 0; i < c.size(); i++){
|
||||
occurs[var(c[i])].push(cr);
|
||||
n_occ[toInt(c[i])]++;
|
||||
touched[var(c[i])] = 1;
|
||||
n_touched++;
|
||||
if (elim_heap.inHeap(var(c[i])))
|
||||
elim_heap.increase(var(c[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SimpSolver::removeClause(CRef cr)
|
||||
{
|
||||
const Clause& c = ca[cr];
|
||||
|
||||
if (use_simplification)
|
||||
for (int i = 0; i < c.size(); i++){
|
||||
n_occ[toInt(c[i])]--;
|
||||
updateElimHeap(var(c[i]));
|
||||
occurs.smudge(var(c[i]));
|
||||
}
|
||||
|
||||
Solver::removeClause(cr);
|
||||
}
|
||||
|
||||
|
||||
bool SimpSolver::strengthenClause(CRef cr, Lit l)
|
||||
{
|
||||
Clause& c = ca[cr];
|
||||
assert(decisionLevel() == 0);
|
||||
assert(use_simplification);
|
||||
|
||||
// FIX: this is too inefficient but would be nice to have (properly implemented)
|
||||
// if (!find(subsumption_queue, &c))
|
||||
subsumption_queue.insert(cr);
|
||||
|
||||
if (drup_file){
|
||||
#ifdef BIN_DRUP
|
||||
binDRUP_strengthen(c, l, drup_file);
|
||||
#else
|
||||
for (int i = 0; i < c.size(); i++)
|
||||
if (c[i] != l) fprintf(drup_file, "%i ", (var(c[i]) + 1) * (-2 * sign(c[i]) + 1));
|
||||
fprintf(drup_file, "0\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (c.size() == 2){
|
||||
removeClause(cr);
|
||||
c.strengthen(l);
|
||||
}else{
|
||||
if (drup_file){
|
||||
#ifdef BIN_DRUP
|
||||
binDRUP('d', c, drup_file);
|
||||
#else
|
||||
fprintf(drup_file, "d ");
|
||||
for (int i = 0; i < c.size(); i++)
|
||||
fprintf(drup_file, "%i ", (var(c[i]) + 1) * (-2 * sign(c[i]) + 1));
|
||||
fprintf(drup_file, "0\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
detachClause(cr, true);
|
||||
c.strengthen(l);
|
||||
attachClause(cr);
|
||||
remove(occurs[var(l)], cr);
|
||||
n_occ[toInt(l)]--;
|
||||
updateElimHeap(var(l));
|
||||
}
|
||||
|
||||
return c.size() == 1 ? enqueue(c[0]) && propagate() == CRef_Undef : true;
|
||||
}
|
||||
|
||||
|
||||
// Returns FALSE if clause is always satisfied ('out_clause' should not be used).
|
||||
bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause)
|
||||
{
|
||||
merges++;
|
||||
out_clause.clear();
|
||||
|
||||
bool ps_smallest = _ps.size() < _qs.size();
|
||||
const Clause& ps = ps_smallest ? _qs : _ps;
|
||||
const Clause& qs = ps_smallest ? _ps : _qs;
|
||||
|
||||
for (int i = 0; i < qs.size(); i++){
|
||||
if (var(qs[i]) != v){
|
||||
for (int j = 0; j < ps.size(); j++)
|
||||
if (var(ps[j]) == var(qs[i]))
|
||||
if (ps[j] == ~qs[i])
|
||||
return false;
|
||||
else
|
||||
goto next;
|
||||
out_clause.push(qs[i]);
|
||||
}
|
||||
next:;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ps.size(); i++)
|
||||
if (var(ps[i]) != v)
|
||||
out_clause.push(ps[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Returns FALSE if clause is always satisfied.
|
||||
bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, int& size)
|
||||
{
|
||||
merges++;
|
||||
|
||||
bool ps_smallest = _ps.size() < _qs.size();
|
||||
const Clause& ps = ps_smallest ? _qs : _ps;
|
||||
const Clause& qs = ps_smallest ? _ps : _qs;
|
||||
const Lit* __ps = (const Lit*)ps;
|
||||
const Lit* __qs = (const Lit*)qs;
|
||||
|
||||
size = ps.size()-1;
|
||||
|
||||
for (int i = 0; i < qs.size(); i++){
|
||||
if (var(__qs[i]) != v){
|
||||
for (int j = 0; j < ps.size(); j++)
|
||||
if (var(__ps[j]) == var(__qs[i]))
|
||||
if (__ps[j] == ~__qs[i])
|
||||
return false;
|
||||
else
|
||||
goto next;
|
||||
size++;
|
||||
}
|
||||
next:;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SimpSolver::gatherTouchedClauses()
|
||||
{
|
||||
if (n_touched == 0) return;
|
||||
|
||||
int i,j;
|
||||
for (i = j = 0; i < subsumption_queue.size(); i++)
|
||||
if (ca[subsumption_queue[i]].mark() == 0)
|
||||
ca[subsumption_queue[i]].mark(2);
|
||||
|
||||
for (i = 0; i < touched.size(); i++)
|
||||
if (touched[i]){
|
||||
const vec<CRef>& cs = occurs.lookup(i);
|
||||
for (j = 0; j < cs.size(); j++)
|
||||
if (ca[cs[j]].mark() == 0){
|
||||
subsumption_queue.insert(cs[j]);
|
||||
ca[cs[j]].mark(2);
|
||||
}
|
||||
touched[i] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < subsumption_queue.size(); i++)
|
||||
if (ca[subsumption_queue[i]].mark() == 2)
|
||||
ca[subsumption_queue[i]].mark(0);
|
||||
|
||||
n_touched = 0;
|
||||
}
|
||||
|
||||
|
||||
bool SimpSolver::implied(const vec<Lit>& c)
|
||||
{
|
||||
assert(decisionLevel() == 0);
|
||||
|
||||
trail_lim.push(trail.size());
|
||||
for (int i = 0; i < c.size(); i++)
|
||||
if (value(c[i]) == l_True){
|
||||
cancelUntil(0);
|
||||
return true;
|
||||
}else if (value(c[i]) != l_False){
|
||||
assert(value(c[i]) == l_Undef);
|
||||
uncheckedEnqueue(~c[i]);
|
||||
}
|
||||
|
||||
bool result = propagate() != CRef_Undef;
|
||||
cancelUntil(0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Backward subsumption + backward subsumption resolution
|
||||
bool SimpSolver::backwardSubsumptionCheck(bool verbose)
|
||||
{
|
||||
int cnt = 0;
|
||||
int subsumed = 0;
|
||||
int deleted_literals = 0;
|
||||
assert(decisionLevel() == 0);
|
||||
|
||||
while (subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()){
|
||||
|
||||
// Empty subsumption queue and return immediately on user-interrupt:
|
||||
if (asynch_interrupt){
|
||||
subsumption_queue.clear();
|
||||
bwdsub_assigns = trail.size();
|
||||
break; }
|
||||
|
||||
// Check top-level assignments by creating a dummy clause and placing it in the queue:
|
||||
if (subsumption_queue.size() == 0 && bwdsub_assigns < trail.size()){
|
||||
Lit l = trail[bwdsub_assigns++];
|
||||
ca[bwdsub_tmpunit][0] = l;
|
||||
ca[bwdsub_tmpunit].calcAbstraction();
|
||||
subsumption_queue.insert(bwdsub_tmpunit); }
|
||||
|
||||
CRef cr = subsumption_queue.peek(); subsumption_queue.pop();
|
||||
Clause& c = ca[cr];
|
||||
|
||||
if (c.mark()) continue;
|
||||
|
||||
if (verbose && verbosity >= 2 && cnt++ % 1000 == 0)
|
||||
printf("c subsumption left: %10d (%10d subsumed, %10d deleted literals)\r", subsumption_queue.size(), subsumed, deleted_literals);
|
||||
|
||||
assert(c.size() > 1 || value(c[0]) == l_True); // Unit-clauses should have been propagated before this point.
|
||||
|
||||
// Find best variable to scan:
|
||||
Var best = var(c[0]);
|
||||
for (int i = 1; i < c.size(); i++)
|
||||
if (occurs[var(c[i])].size() < occurs[best].size())
|
||||
best = var(c[i]);
|
||||
|
||||
// Search all candidates:
|
||||
vec<CRef>& _cs = occurs.lookup(best);
|
||||
CRef* cs = (CRef*)_cs;
|
||||
|
||||
for (int j = 0; j < _cs.size(); j++)
|
||||
if (c.mark())
|
||||
break;
|
||||
else if (!ca[cs[j]].mark() && cs[j] != cr && (subsumption_lim == -1 || ca[cs[j]].size() < subsumption_lim)){
|
||||
Lit l = c.subsumes(ca[cs[j]]);
|
||||
|
||||
if (l == lit_Undef)
|
||||
subsumed++, removeClause(cs[j]);
|
||||
else if (l != lit_Error){
|
||||
deleted_literals++;
|
||||
|
||||
if (!strengthenClause(cs[j], ~l))
|
||||
return false;
|
||||
|
||||
// Did current candidate get deleted from cs? Then check candidate at index j again:
|
||||
if (var(l) == best)
|
||||
j--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SimpSolver::asymm(Var v, CRef cr)
|
||||
{
|
||||
Clause& c = ca[cr];
|
||||
assert(decisionLevel() == 0);
|
||||
|
||||
if (c.mark() || satisfied(c)) return true;
|
||||
|
||||
trail_lim.push(trail.size());
|
||||
Lit l = lit_Undef;
|
||||
for (int i = 0; i < c.size(); i++)
|
||||
if (var(c[i]) != v){
|
||||
if (value(c[i]) != l_False)
|
||||
uncheckedEnqueue(~c[i]);
|
||||
}else
|
||||
l = c[i];
|
||||
|
||||
if (propagate() != CRef_Undef){
|
||||
cancelUntil(0);
|
||||
asymm_lits++;
|
||||
if (!strengthenClause(cr, l))
|
||||
return false;
|
||||
}else
|
||||
cancelUntil(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SimpSolver::asymmVar(Var v)
|
||||
{
|
||||
assert(use_simplification);
|
||||
|
||||
const vec<CRef>& cls = occurs.lookup(v);
|
||||
|
||||
if (value(v) != l_Undef || cls.size() == 0)
|
||||
return true;
|
||||
|
||||
for (int i = 0; i < cls.size(); i++)
|
||||
if (!asymm(v, cls[i]))
|
||||
return false;
|
||||
|
||||
return backwardSubsumptionCheck();
|
||||
}
|
||||
|
||||
|
||||
static void mkElimClause(vec<uint32_t>& elimclauses, Lit x)
|
||||
{
|
||||
elimclauses.push(toInt(x));
|
||||
elimclauses.push(1);
|
||||
}
|
||||
|
||||
|
||||
static void mkElimClause(vec<uint32_t>& elimclauses, Var v, Clause& c)
|
||||
{
|
||||
int first = elimclauses.size();
|
||||
int v_pos = -1;
|
||||
|
||||
// Copy clause to elimclauses-vector. Remember position where the
|
||||
// variable 'v' occurs:
|
||||
for (int i = 0; i < c.size(); i++){
|
||||
elimclauses.push(toInt(c[i]));
|
||||
if (var(c[i]) == v)
|
||||
v_pos = i + first;
|
||||
}
|
||||
assert(v_pos != -1);
|
||||
|
||||
// Swap the first literal with the 'v' literal, so that the literal
|
||||
// containing 'v' will occur first in the clause:
|
||||
uint32_t tmp = elimclauses[v_pos];
|
||||
elimclauses[v_pos] = elimclauses[first];
|
||||
elimclauses[first] = tmp;
|
||||
|
||||
// Store the length of the clause last:
|
||||
elimclauses.push(c.size());
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool SimpSolver::eliminateVar(Var v)
|
||||
{
|
||||
assert(!frozen[v]);
|
||||
assert(!isEliminated(v));
|
||||
assert(value(v) == l_Undef);
|
||||
|
||||
// Split the occurrences into positive and negative:
|
||||
//
|
||||
const vec<CRef>& cls = occurs.lookup(v);
|
||||
vec<CRef> pos, neg;
|
||||
for (int i = 0; i < cls.size(); i++)
|
||||
(find(ca[cls[i]], mkLit(v)) ? pos : neg).push(cls[i]);
|
||||
|
||||
// Check wether the increase in number of clauses stays within the allowed ('grow'). Moreover, no
|
||||
// clause must exceed the limit on the maximal clause size (if it is set):
|
||||
//
|
||||
int cnt = 0;
|
||||
int clause_size = 0;
|
||||
|
||||
for (int i = 0; i < pos.size(); i++)
|
||||
for (int j = 0; j < neg.size(); j++)
|
||||
if (merge(ca[pos[i]], ca[neg[j]], v, clause_size) &&
|
||||
(++cnt > cls.size() + grow || (clause_lim != -1 && clause_size > clause_lim)))
|
||||
return true;
|
||||
|
||||
// Delete and store old clauses:
|
||||
eliminated[v] = true;
|
||||
setDecisionVar(v, false);
|
||||
eliminated_vars++;
|
||||
|
||||
if (pos.size() > neg.size()){
|
||||
for (int i = 0; i < neg.size(); i++)
|
||||
mkElimClause(elimclauses, v, ca[neg[i]]);
|
||||
mkElimClause(elimclauses, mkLit(v));
|
||||
}else{
|
||||
for (int i = 0; i < pos.size(); i++)
|
||||
mkElimClause(elimclauses, v, ca[pos[i]]);
|
||||
mkElimClause(elimclauses, ~mkLit(v));
|
||||
}
|
||||
|
||||
// Produce clauses in cross product:
|
||||
vec<Lit>& resolvent = add_tmp;
|
||||
for (int i = 0; i < pos.size(); i++)
|
||||
for (int j = 0; j < neg.size(); j++)
|
||||
if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) && !addClause_(resolvent))
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < cls.size(); i++)
|
||||
removeClause(cls[i]);
|
||||
|
||||
// Free occurs list for this variable:
|
||||
occurs[v].clear(true);
|
||||
|
||||
// Free watchers lists for this variable, if possible:
|
||||
watches_bin[ mkLit(v)].clear(true);
|
||||
watches_bin[~mkLit(v)].clear(true);
|
||||
watches[ mkLit(v)].clear(true);
|
||||
watches[~mkLit(v)].clear(true);
|
||||
|
||||
return backwardSubsumptionCheck();
|
||||
}
|
||||
|
||||
|
||||
bool SimpSolver::substitute(Var v, Lit x)
|
||||
{
|
||||
assert(!frozen[v]);
|
||||
assert(!isEliminated(v));
|
||||
assert(value(v) == l_Undef);
|
||||
|
||||
if (!ok) return false;
|
||||
|
||||
eliminated[v] = true;
|
||||
setDecisionVar(v, false);
|
||||
const vec<CRef>& cls = occurs.lookup(v);
|
||||
|
||||
vec<Lit>& subst_clause = add_tmp;
|
||||
for (int i = 0; i < cls.size(); i++){
|
||||
Clause& c = ca[cls[i]];
|
||||
|
||||
subst_clause.clear();
|
||||
for (int j = 0; j < c.size(); j++){
|
||||
Lit p = c[j];
|
||||
subst_clause.push(var(p) == v ? x ^ sign(p) : p);
|
||||
}
|
||||
|
||||
if (!addClause_(subst_clause))
|
||||
return ok = false;
|
||||
|
||||
removeClause(cls[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SimpSolver::extendModel()
|
||||
{
|
||||
int i, j;
|
||||
Lit x;
|
||||
|
||||
for (i = elimclauses.size()-1; i > 0; i -= j){
|
||||
for (j = elimclauses[i--]; j > 1; j--, i--)
|
||||
if (modelValue(toLit(elimclauses[i])) != l_False)
|
||||
goto next;
|
||||
|
||||
x = toLit(elimclauses[i]);
|
||||
model[var(x)] = lbool(!sign(x));
|
||||
next:;
|
||||
}
|
||||
}
|
||||
|
||||
// Almost duplicate of Solver::removeSatisfied. Didn't want to make the base method 'virtual'.
|
||||
void SimpSolver::removeSatisfied()
|
||||
{
|
||||
int i, j;
|
||||
for (i = j = 0; i < clauses.size(); i++){
|
||||
const Clause& c = ca[clauses[i]];
|
||||
if (c.mark() == 0)
|
||||
if (satisfied(c))
|
||||
removeClause(clauses[i]);
|
||||
else
|
||||
clauses[j++] = clauses[i];
|
||||
}
|
||||
clauses.shrink(i - j);
|
||||
}
|
||||
|
||||
// The technique and code are by the courtesy of the GlueMiniSat team. Thank you!
|
||||
// It helps solving certain types of huge problems tremendously.
|
||||
bool SimpSolver::eliminate(bool turn_off_elim)
|
||||
{
|
||||
bool res = true;
|
||||
int iter = 0;
|
||||
int n_cls, n_cls_init, n_vars;
|
||||
|
||||
if (nVars() == 0) goto cleanup; // User disabling preprocessing.
|
||||
|
||||
// Get an initial number of clauses (more accurately).
|
||||
if (trail.size() != 0) removeSatisfied();
|
||||
n_cls_init = nClauses();
|
||||
|
||||
res = eliminate_(); // The first, usual variable elimination of MiniSat.
|
||||
if (!res) goto cleanup;
|
||||
|
||||
n_cls = nClauses();
|
||||
n_vars = nFreeVars();
|
||||
|
||||
printf("c Reduced to %d vars, %d cls (grow=%d)\n", n_vars, n_cls, grow);
|
||||
|
||||
if ((double)n_cls / n_vars >= 5 || n_vars < 10000){
|
||||
printf("c No iterative elimination performed. (vars=%d, c/v ratio=%.1f)\n", n_vars, (double)n_cls / n_vars);
|
||||
goto cleanup; }
|
||||
|
||||
grow = grow ? grow * 2 : 8;
|
||||
for (; grow < 10000; grow *= 2){
|
||||
// Rebuild elimination variable heap.
|
||||
for (int i = 0; i < clauses.size(); i++){
|
||||
const Clause& c = ca[clauses[i]];
|
||||
for (int j = 0; j < c.size(); j++)
|
||||
if (!elim_heap.inHeap(var(c[j])))
|
||||
elim_heap.insert(var(c[j]));
|
||||
else
|
||||
elim_heap.update(var(c[j])); }
|
||||
|
||||
int n_cls_last = nClauses();
|
||||
int n_vars_last = nFreeVars();
|
||||
|
||||
res = eliminate_();
|
||||
if (!res || n_vars_last == nFreeVars()) break;
|
||||
iter++;
|
||||
|
||||
int n_cls_now = nClauses();
|
||||
int n_vars_now = nFreeVars();
|
||||
|
||||
double cl_inc_rate = (double)n_cls_now / n_cls_last;
|
||||
double var_dec_rate = (double)n_vars_last / n_vars_now;
|
||||
|
||||
printf("c Reduced to %d vars, %d cls (grow=%d)\n", n_vars_now, n_cls_now, grow);
|
||||
printf("c cl_inc_rate=%.3f, var_dec_rate=%.3f\n", cl_inc_rate, var_dec_rate);
|
||||
|
||||
if (n_cls_now > n_cls_init || cl_inc_rate > var_dec_rate) break;
|
||||
}
|
||||
printf("c No. effective iterative eliminations: %d\n", iter);
|
||||
|
||||
cleanup:
|
||||
touched .clear(true);
|
||||
occurs .clear(true);
|
||||
n_occ .clear(true);
|
||||
elim_heap.clear(true);
|
||||
subsumption_queue.clear(true);
|
||||
|
||||
use_simplification = false;
|
||||
remove_satisfied = true;
|
||||
ca.extra_clause_field = false;
|
||||
|
||||
// Force full cleanup (this is safe and desirable since it only happens once):
|
||||
rebuildOrderHeap();
|
||||
garbageCollect();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
bool SimpSolver::eliminate_()
|
||||
{
|
||||
if (!simplify())
|
||||
return false;
|
||||
else if (!use_simplification)
|
||||
return true;
|
||||
|
||||
int trail_size_last = trail.size();
|
||||
|
||||
// Main simplification loop:
|
||||
//
|
||||
while (n_touched > 0 || bwdsub_assigns < trail.size() || elim_heap.size() > 0){
|
||||
|
||||
gatherTouchedClauses();
|
||||
// printf(" ## (time = %6.2f s) BWD-SUB: queue = %d, trail = %d\n", cpuTime(), subsumption_queue.size(), trail.size() - bwdsub_assigns);
|
||||
if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()) &&
|
||||
!backwardSubsumptionCheck(true)){
|
||||
ok = false; goto cleanup; }
|
||||
|
||||
// Empty elim_heap and return immediately on user-interrupt:
|
||||
if (asynch_interrupt){
|
||||
assert(bwdsub_assigns == trail.size());
|
||||
assert(subsumption_queue.size() == 0);
|
||||
assert(n_touched == 0);
|
||||
elim_heap.clear();
|
||||
goto cleanup; }
|
||||
|
||||
// printf(" ## (time = %6.2f s) ELIM: vars = %d\n", cpuTime(), elim_heap.size());
|
||||
for (int cnt = 0; !elim_heap.empty(); cnt++){
|
||||
Var elim = elim_heap.removeMin();
|
||||
|
||||
if (asynch_interrupt) break;
|
||||
|
||||
if (isEliminated(elim) || value(elim) != l_Undef) continue;
|
||||
|
||||
if (verbosity >= 2 && cnt % 100 == 0)
|
||||
printf("c elimination left: %10d\r", elim_heap.size());
|
||||
|
||||
if (use_asymm){
|
||||
// Temporarily freeze variable. Otherwise, it would immediately end up on the queue again:
|
||||
bool was_frozen = frozen[elim];
|
||||
frozen[elim] = true;
|
||||
if (!asymmVar(elim)){
|
||||
ok = false; goto cleanup; }
|
||||
frozen[elim] = was_frozen; }
|
||||
|
||||
// At this point, the variable may have been set by assymetric branching, so check it
|
||||
// again. Also, don't eliminate frozen variables:
|
||||
if (use_elim && value(elim) == l_Undef && !frozen[elim] && !eliminateVar(elim)){
|
||||
ok = false; goto cleanup; }
|
||||
|
||||
checkGarbage(simp_garbage_frac);
|
||||
}
|
||||
|
||||
assert(subsumption_queue.size() == 0);
|
||||
}
|
||||
cleanup:
|
||||
// To get an accurate number of clauses.
|
||||
if (trail_size_last != trail.size())
|
||||
removeSatisfied();
|
||||
else{
|
||||
int i,j;
|
||||
for (i = j = 0; i < clauses.size(); i++)
|
||||
if (ca[clauses[i]].mark() == 0)
|
||||
clauses[j++] = clauses[i];
|
||||
clauses.shrink(i - j);
|
||||
}
|
||||
checkGarbage();
|
||||
|
||||
if (verbosity >= 1 && elimclauses.size() > 0)
|
||||
printf("c | Eliminated clauses: %10.2f Mb |\n",
|
||||
double(elimclauses.size() * sizeof(uint32_t)) / (1024*1024));
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
// Garbage Collection methods:
|
||||
|
||||
|
||||
void SimpSolver::relocAll(ClauseAllocator& to)
|
||||
{
|
||||
if (!use_simplification) return;
|
||||
|
||||
// All occurs lists:
|
||||
//
|
||||
occurs.cleanAll();
|
||||
for (int i = 0; i < nVars(); i++){
|
||||
vec<CRef>& cs = occurs[i];
|
||||
for (int j = 0; j < cs.size(); j++)
|
||||
ca.reloc(cs[j], to);
|
||||
}
|
||||
|
||||
// Subsumption queue:
|
||||
//
|
||||
for (int i = 0; i < subsumption_queue.size(); i++)
|
||||
ca.reloc(subsumption_queue[i], to);
|
||||
|
||||
// Temporary clause:
|
||||
//
|
||||
ca.reloc(bwdsub_tmpunit, to);
|
||||
}
|
||||
|
||||
|
||||
void SimpSolver::garbageCollect()
|
||||
{
|
||||
// Initialize the next region to a size corresponding to the estimated utilization degree. This
|
||||
// is not precise but should avoid some unnecessary reallocations for the new region:
|
||||
ClauseAllocator to(ca.size() - ca.wasted());
|
||||
|
||||
to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields.
|
||||
relocAll(to);
|
||||
Solver::relocAll(to);
|
||||
if (verbosity >= 2)
|
||||
printf("c | Garbage collection: %12d bytes => %12d bytes |\n",
|
||||
ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size);
|
||||
to.moveTo(ca);
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
/************************************************************************************[SimpSolver.h]
|
||||
MiniSat -- Copyright (c) 2006, Niklas Een, Niklas Sorensson
|
||||
Copyright (c) 2007-2010, Niklas Sorensson
|
||||
|
||||
Chanseok Oh's MiniSat Patch Series -- Copyright (c) 2015, Chanseok Oh
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#ifndef Minisat_SimpSolver_h
|
||||
#define Minisat_SimpSolver_h
|
||||
|
||||
#include "mtl/Queue.h"
|
||||
#include "core/Solver.h"
|
||||
|
||||
|
||||
namespace Minisat {
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
|
||||
class SimpSolver : public Solver {
|
||||
public:
|
||||
// Constructor/Destructor:
|
||||
//
|
||||
SimpSolver();
|
||||
~SimpSolver();
|
||||
|
||||
// Problem specification:
|
||||
//
|
||||
Var newVar (bool polarity = true, bool dvar = true);
|
||||
bool addClause (const vec<Lit>& ps);
|
||||
bool addEmptyClause(); // Add the empty clause to the solver.
|
||||
bool addClause (Lit p); // Add a unit clause to the solver.
|
||||
bool addClause (Lit p, Lit q); // Add a binary clause to the solver.
|
||||
bool addClause (Lit p, Lit q, Lit r); // Add a ternary clause to the solver.
|
||||
bool addClause_( vec<Lit>& ps);
|
||||
bool substitute(Var v, Lit x); // Replace all occurences of v with x (may cause a contradiction).
|
||||
|
||||
// Variable mode:
|
||||
//
|
||||
void setFrozen (Var v, bool b); // If a variable is frozen it will not be eliminated.
|
||||
bool isEliminated(Var v) const;
|
||||
|
||||
// Solving:
|
||||
//
|
||||
bool solve (const vec<Lit>& assumps, bool do_simp = true, bool turn_off_simp = false);
|
||||
lbool solveLimited(const vec<Lit>& assumps, bool do_simp = true, bool turn_off_simp = false);
|
||||
bool solve ( bool do_simp = true, bool turn_off_simp = false);
|
||||
bool solve (Lit p , bool do_simp = true, bool turn_off_simp = false);
|
||||
bool solve (Lit p, Lit q, bool do_simp = true, bool turn_off_simp = false);
|
||||
bool solve (Lit p, Lit q, Lit r, bool do_simp = true, bool turn_off_simp = false);
|
||||
bool eliminate (bool turn_off_elim = false); // Perform variable elimination based simplification.
|
||||
bool eliminate_ ();
|
||||
void removeSatisfied();
|
||||
|
||||
// Memory managment:
|
||||
//
|
||||
virtual void garbageCollect();
|
||||
|
||||
|
||||
// Generate a (possibly simplified) DIMACS file:
|
||||
//
|
||||
#if 0
|
||||
void toDimacs (const char* file, const vec<Lit>& assumps);
|
||||
void toDimacs (const char* file);
|
||||
void toDimacs (const char* file, Lit p);
|
||||
void toDimacs (const char* file, Lit p, Lit q);
|
||||
void toDimacs (const char* file, Lit p, Lit q, Lit r);
|
||||
#endif
|
||||
|
||||
// Mode of operation:
|
||||
//
|
||||
bool parsing;
|
||||
int grow; // Allow a variable elimination step to grow by a number of clauses (default to zero).
|
||||
int clause_lim; // Variables are not eliminated if it produces a resolvent with a length above this limit.
|
||||
// -1 means no limit.
|
||||
int subsumption_lim; // Do not check if subsumption against a clause larger than this. -1 means no limit.
|
||||
double simp_garbage_frac; // A different limit for when to issue a GC during simplification (Also see 'garbage_frac').
|
||||
|
||||
bool use_asymm; // Shrink clauses by asymmetric branching.
|
||||
bool use_rcheck; // Check if a clause is already implied. Prett costly, and subsumes subsumptions :)
|
||||
bool use_elim; // Perform variable elimination.
|
||||
|
||||
// Statistics:
|
||||
//
|
||||
int merges;
|
||||
int asymm_lits;
|
||||
int eliminated_vars;
|
||||
|
||||
protected:
|
||||
|
||||
// Helper structures:
|
||||
//
|
||||
struct ElimLt {
|
||||
const vec<int>& n_occ;
|
||||
explicit ElimLt(const vec<int>& no) : n_occ(no) {}
|
||||
|
||||
// TODO: are 64-bit operations here noticably bad on 32-bit platforms? Could use a saturating
|
||||
// 32-bit implementation instead then, but this will have to do for now.
|
||||
uint64_t cost (Var x) const { return (uint64_t)n_occ[toInt(mkLit(x))] * (uint64_t)n_occ[toInt(~mkLit(x))]; }
|
||||
bool operator()(Var x, Var y) const { return cost(x) < cost(y); }
|
||||
|
||||
// TODO: investigate this order alternative more.
|
||||
// bool operator()(Var x, Var y) const {
|
||||
// int c_x = cost(x);
|
||||
// int c_y = cost(y);
|
||||
// return c_x < c_y || c_x == c_y && x < y; }
|
||||
};
|
||||
|
||||
struct ClauseDeleted {
|
||||
const ClauseAllocator& ca;
|
||||
explicit ClauseDeleted(const ClauseAllocator& _ca) : ca(_ca) {}
|
||||
bool operator()(const CRef& cr) const { return ca[cr].mark() == 1; } };
|
||||
|
||||
// Solver state:
|
||||
//
|
||||
int elimorder;
|
||||
bool use_simplification;
|
||||
vec<uint32_t> elimclauses;
|
||||
vec<char> touched;
|
||||
OccLists<Var, vec<CRef>, ClauseDeleted>
|
||||
occurs;
|
||||
vec<int> n_occ;
|
||||
Heap<ElimLt> elim_heap;
|
||||
Queue<CRef> subsumption_queue;
|
||||
vec<char> frozen;
|
||||
vec<char> eliminated;
|
||||
int bwdsub_assigns;
|
||||
int n_touched;
|
||||
|
||||
// Temporaries:
|
||||
//
|
||||
CRef bwdsub_tmpunit;
|
||||
|
||||
// Main internal methods:
|
||||
//
|
||||
lbool solve_ (bool do_simp = true, bool turn_off_simp = false);
|
||||
bool asymm (Var v, CRef cr);
|
||||
bool asymmVar (Var v);
|
||||
void updateElimHeap (Var v);
|
||||
void gatherTouchedClauses ();
|
||||
bool merge (const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause);
|
||||
bool merge (const Clause& _ps, const Clause& _qs, Var v, int& size);
|
||||
bool backwardSubsumptionCheck (bool verbose = false);
|
||||
bool eliminateVar (Var v);
|
||||
void extendModel ();
|
||||
|
||||
void removeClause (CRef cr);
|
||||
bool strengthenClause (CRef cr, Lit l);
|
||||
bool implied (const vec<Lit>& c);
|
||||
void relocAll (ClauseAllocator& to);
|
||||
};
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
// Implementation of inline methods:
|
||||
|
||||
|
||||
inline bool SimpSolver::isEliminated (Var v) const { return eliminated[v]; }
|
||||
inline void SimpSolver::updateElimHeap(Var v) {
|
||||
assert(use_simplification);
|
||||
// if (!frozen[v] && !isEliminated(v) && value(v) == l_Undef)
|
||||
if (elim_heap.inHeap(v) || (!frozen[v] && !isEliminated(v) && value(v) == l_Undef))
|
||||
elim_heap.update(v); }
|
||||
|
||||
|
||||
inline bool SimpSolver::addClause (const vec<Lit>& ps) { ps.copyTo(add_tmp); return addClause_(add_tmp); }
|
||||
inline bool SimpSolver::addEmptyClause() { add_tmp.clear(); return addClause_(add_tmp); }
|
||||
inline bool SimpSolver::addClause (Lit p) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp); }
|
||||
inline bool SimpSolver::addClause (Lit p, Lit q) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp); }
|
||||
inline bool SimpSolver::addClause (Lit p, Lit q, Lit r) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp); }
|
||||
inline void SimpSolver::setFrozen (Var v, bool b) { frozen[v] = (char)b; if (use_simplification && !b) { updateElimHeap(v); } }
|
||||
|
||||
inline bool SimpSolver::solve ( bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); return solve_(do_simp, turn_off_simp) == l_True; }
|
||||
inline bool SimpSolver::solve (Lit p , bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); assumptions.push(p); return solve_(do_simp, turn_off_simp) == l_True; }
|
||||
inline bool SimpSolver::solve (Lit p, Lit q, bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); return solve_(do_simp, turn_off_simp) == l_True; }
|
||||
inline bool SimpSolver::solve (Lit p, Lit q, Lit r, bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); assumptions.push(r); return solve_(do_simp, turn_off_simp) == l_True; }
|
||||
inline bool SimpSolver::solve (const vec<Lit>& assumps, bool do_simp, bool turn_off_simp){
|
||||
budgetOff(); assumps.copyTo(assumptions); return solve_(do_simp, turn_off_simp) == l_True; }
|
||||
|
||||
inline lbool SimpSolver::solveLimited (const vec<Lit>& assumps, bool do_simp, bool turn_off_simp){
|
||||
assumps.copyTo(assumptions); return solve_(do_simp, turn_off_simp); }
|
||||
|
||||
//=================================================================================================
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,4 @@
|
|||
EXEC = system_test
|
||||
DEPDIR = mtl
|
||||
|
||||
include $(MROOT)/mtl/template.mk
|
|
@ -0,0 +1,91 @@
|
|||
/**************************************************************************************[Options.cc]
|
||||
Copyright (c) 2008-2010, Niklas Sorensson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#include "mtl/Sort.h"
|
||||
#include "utils/Options.h"
|
||||
#include "utils/ParseUtils.h"
|
||||
|
||||
using namespace Minisat;
|
||||
|
||||
void Minisat::parseOptions(int& argc, char** argv, bool strict)
|
||||
{
|
||||
int i, j;
|
||||
for (i = j = 1; i < argc; i++){
|
||||
const char* str = argv[i];
|
||||
if (match(str, "--") && match(str, Option::getHelpPrefixString()) && match(str, "help")){
|
||||
if (*str == '\0')
|
||||
printUsageAndExit(argc, argv);
|
||||
else if (match(str, "-verb"))
|
||||
printUsageAndExit(argc, argv, true);
|
||||
} else {
|
||||
bool parsed_ok = false;
|
||||
|
||||
for (int k = 0; !parsed_ok && k < Option::getOptionList().size(); k++){
|
||||
parsed_ok = Option::getOptionList()[k]->parse(argv[i]);
|
||||
|
||||
// fprintf(stderr, "checking %d: %s against flag <%s> (%s)\n", i, argv[i], Option::getOptionList()[k]->name, parsed_ok ? "ok" : "skip");
|
||||
}
|
||||
|
||||
if (!parsed_ok)
|
||||
if (strict && match(argv[i], "-"))
|
||||
fprintf(stderr, "ERROR! Unknown flag \"%s\". Use '--%shelp' for help.\n", argv[i], Option::getHelpPrefixString()), exit(1);
|
||||
else
|
||||
argv[j++] = argv[i];
|
||||
}
|
||||
}
|
||||
|
||||
argc -= (i - j);
|
||||
}
|
||||
|
||||
|
||||
void Minisat::setUsageHelp (const char* str){ Option::getUsageString() = str; }
|
||||
void Minisat::setHelpPrefixStr (const char* str){ Option::getHelpPrefixString() = str; }
|
||||
void Minisat::printUsageAndExit (int argc, char** argv, bool verbose)
|
||||
{
|
||||
const char* usage = Option::getUsageString();
|
||||
if (usage != NULL)
|
||||
fprintf(stderr, usage, argv[0]);
|
||||
|
||||
sort(Option::getOptionList(), Option::OptionLt());
|
||||
|
||||
const char* prev_cat = NULL;
|
||||
const char* prev_type = NULL;
|
||||
|
||||
for (int i = 0; i < Option::getOptionList().size(); i++){
|
||||
const char* cat = Option::getOptionList()[i]->category;
|
||||
const char* type = Option::getOptionList()[i]->type_name;
|
||||
|
||||
if (cat != prev_cat)
|
||||
fprintf(stderr, "\n%s OPTIONS:\n\n", cat);
|
||||
else if (type != prev_type)
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
Option::getOptionList()[i]->help(verbose);
|
||||
|
||||
prev_cat = Option::getOptionList()[i]->category;
|
||||
prev_type = Option::getOptionList()[i]->type_name;
|
||||
}
|
||||
|
||||
fprintf(stderr, "\nHELP OPTIONS:\n\n");
|
||||
fprintf(stderr, " --%shelp Print help message.\n", Option::getHelpPrefixString());
|
||||
fprintf(stderr, " --%shelp-verb Print verbose help message.\n", Option::getHelpPrefixString());
|
||||
fprintf(stderr, "\n");
|
||||
exit(0);
|
||||
}
|
||||
|
|
@ -0,0 +1,386 @@
|
|||
/***************************************************************************************[Options.h]
|
||||
Copyright (c) 2008-2010, Niklas Sorensson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#ifndef Minisat_Options_h
|
||||
#define Minisat_Options_h
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mtl/IntTypes.h"
|
||||
#include "mtl/Vec.h"
|
||||
#include "utils/ParseUtils.h"
|
||||
|
||||
namespace Minisat {
|
||||
|
||||
//==================================================================================================
|
||||
// Top-level option parse/help functions:
|
||||
|
||||
|
||||
extern void parseOptions (int& argc, char** argv, bool strict = false);
|
||||
extern void printUsageAndExit(int argc, char** argv, bool verbose = false);
|
||||
extern void setUsageHelp (const char* str);
|
||||
extern void setHelpPrefixStr (const char* str);
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
// Options is an abstract class that gives the interface for all types options:
|
||||
|
||||
|
||||
class Option
|
||||
{
|
||||
protected:
|
||||
const char* name;
|
||||
const char* description;
|
||||
const char* category;
|
||||
const char* type_name;
|
||||
|
||||
static vec<Option*>& getOptionList () { static vec<Option*> options; return options; }
|
||||
static const char*& getUsageString() { static const char* usage_str; return usage_str; }
|
||||
static const char*& getHelpPrefixString() { static const char* help_prefix_str = ""; return help_prefix_str; }
|
||||
|
||||
struct OptionLt {
|
||||
bool operator()(const Option* x, const Option* y) {
|
||||
int test1 = strcmp(x->category, y->category);
|
||||
return test1 < 0 || test1 == 0 && strcmp(x->type_name, y->type_name) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
Option(const char* name_,
|
||||
const char* desc_,
|
||||
const char* cate_,
|
||||
const char* type_) :
|
||||
name (name_)
|
||||
, description(desc_)
|
||||
, category (cate_)
|
||||
, type_name (type_)
|
||||
{
|
||||
getOptionList().push(this);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~Option() {}
|
||||
|
||||
virtual bool parse (const char* str) = 0;
|
||||
virtual void help (bool verbose = false) = 0;
|
||||
|
||||
friend void parseOptions (int& argc, char** argv, bool strict);
|
||||
friend void printUsageAndExit (int argc, char** argv, bool verbose);
|
||||
friend void setUsageHelp (const char* str);
|
||||
friend void setHelpPrefixStr (const char* str);
|
||||
};
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
// Range classes with specialization for floating types:
|
||||
|
||||
|
||||
struct IntRange {
|
||||
int begin;
|
||||
int end;
|
||||
IntRange(int b, int e) : begin(b), end(e) {}
|
||||
};
|
||||
|
||||
struct Int64Range {
|
||||
int64_t begin;
|
||||
int64_t end;
|
||||
Int64Range(int64_t b, int64_t e) : begin(b), end(e) {}
|
||||
};
|
||||
|
||||
struct DoubleRange {
|
||||
double begin;
|
||||
double end;
|
||||
bool begin_inclusive;
|
||||
bool end_inclusive;
|
||||
DoubleRange(double b, bool binc, double e, bool einc) : begin(b), end(e), begin_inclusive(binc), end_inclusive(einc) {}
|
||||
};
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
// Double options:
|
||||
|
||||
|
||||
class DoubleOption : public Option
|
||||
{
|
||||
protected:
|
||||
DoubleRange range;
|
||||
double value;
|
||||
|
||||
public:
|
||||
DoubleOption(const char* c, const char* n, const char* d, double def = double(), DoubleRange r = DoubleRange(-HUGE_VAL, false, HUGE_VAL, false))
|
||||
: Option(n, d, c, "<double>"), range(r), value(def) {
|
||||
// FIXME: set LC_NUMERIC to "C" to make sure that strtof/strtod parses decimal point correctly.
|
||||
}
|
||||
|
||||
operator double (void) const { return value; }
|
||||
operator double& (void) { return value; }
|
||||
DoubleOption& operator=(double x) { value = x; return *this; }
|
||||
|
||||
virtual bool parse(const char* str){
|
||||
const char* span = str;
|
||||
|
||||
if (!match(span, "-") || !match(span, name) || !match(span, "="))
|
||||
return false;
|
||||
|
||||
char* end;
|
||||
double tmp = strtod(span, &end);
|
||||
|
||||
if (end == NULL)
|
||||
return false;
|
||||
else if (tmp >= range.end && (!range.end_inclusive || tmp != range.end)){
|
||||
fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name);
|
||||
exit(1);
|
||||
}else if (tmp <= range.begin && (!range.begin_inclusive || tmp != range.begin)){
|
||||
fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name);
|
||||
exit(1); }
|
||||
|
||||
value = tmp;
|
||||
// fprintf(stderr, "READ VALUE: %g\n", value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void help (bool verbose = false){
|
||||
fprintf(stderr, " -%-12s = %-8s %c%4.2g .. %4.2g%c (default: %g)\n",
|
||||
name, type_name,
|
||||
range.begin_inclusive ? '[' : '(',
|
||||
range.begin,
|
||||
range.end,
|
||||
range.end_inclusive ? ']' : ')',
|
||||
value);
|
||||
if (verbose){
|
||||
fprintf(stderr, "\n %s\n", description);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
// Int options:
|
||||
|
||||
|
||||
class IntOption : public Option
|
||||
{
|
||||
protected:
|
||||
IntRange range;
|
||||
int32_t value;
|
||||
|
||||
public:
|
||||
IntOption(const char* c, const char* n, const char* d, int32_t def = int32_t(), IntRange r = IntRange(INT32_MIN, INT32_MAX))
|
||||
: Option(n, d, c, "<int32>"), range(r), value(def) {}
|
||||
|
||||
operator int32_t (void) const { return value; }
|
||||
operator int32_t& (void) { return value; }
|
||||
IntOption& operator= (int32_t x) { value = x; return *this; }
|
||||
|
||||
virtual bool parse(const char* str){
|
||||
const char* span = str;
|
||||
|
||||
if (!match(span, "-") || !match(span, name) || !match(span, "="))
|
||||
return false;
|
||||
|
||||
char* end;
|
||||
int32_t tmp = strtol(span, &end, 10);
|
||||
|
||||
if (end == NULL)
|
||||
return false;
|
||||
else if (tmp > range.end){
|
||||
fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name);
|
||||
exit(1);
|
||||
}else if (tmp < range.begin){
|
||||
fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name);
|
||||
exit(1); }
|
||||
|
||||
value = tmp;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void help (bool verbose = false){
|
||||
fprintf(stderr, " -%-12s = %-8s [", name, type_name);
|
||||
if (range.begin == INT32_MIN)
|
||||
fprintf(stderr, "imin");
|
||||
else
|
||||
fprintf(stderr, "%4d", range.begin);
|
||||
|
||||
fprintf(stderr, " .. ");
|
||||
if (range.end == INT32_MAX)
|
||||
fprintf(stderr, "imax");
|
||||
else
|
||||
fprintf(stderr, "%4d", range.end);
|
||||
|
||||
fprintf(stderr, "] (default: %d)\n", value);
|
||||
if (verbose){
|
||||
fprintf(stderr, "\n %s\n", description);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Leave this out for visual C++ until Microsoft implements C99 and gets support for strtoll.
|
||||
#ifndef _MSC_VER
|
||||
|
||||
class Int64Option : public Option
|
||||
{
|
||||
protected:
|
||||
Int64Range range;
|
||||
int64_t value;
|
||||
|
||||
public:
|
||||
Int64Option(const char* c, const char* n, const char* d, int64_t def = int64_t(), Int64Range r = Int64Range(INT64_MIN, INT64_MAX))
|
||||
: Option(n, d, c, "<int64>"), range(r), value(def) {}
|
||||
|
||||
operator int64_t (void) const { return value; }
|
||||
operator int64_t& (void) { return value; }
|
||||
Int64Option& operator= (int64_t x) { value = x; return *this; }
|
||||
|
||||
virtual bool parse(const char* str){
|
||||
const char* span = str;
|
||||
|
||||
if (!match(span, "-") || !match(span, name) || !match(span, "="))
|
||||
return false;
|
||||
|
||||
char* end;
|
||||
int64_t tmp = strtoll(span, &end, 10);
|
||||
|
||||
if (end == NULL)
|
||||
return false;
|
||||
else if (tmp > range.end){
|
||||
fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name);
|
||||
exit(1);
|
||||
}else if (tmp < range.begin){
|
||||
fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name);
|
||||
exit(1); }
|
||||
|
||||
value = tmp;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void help (bool verbose = false){
|
||||
fprintf(stderr, " -%-12s = %-8s [", name, type_name);
|
||||
if (range.begin == INT64_MIN)
|
||||
fprintf(stderr, "imin");
|
||||
// else
|
||||
// fprintf(stderr, "%4"PRIi64, range.begin);
|
||||
|
||||
fprintf(stderr, " .. ");
|
||||
if (range.end == INT64_MAX)
|
||||
fprintf(stderr, "imax");
|
||||
// else
|
||||
// fprintf(stderr, "%4"PRIi64, range.end);
|
||||
|
||||
// fprintf(stderr, "] (default: %"PRIi64")\n", value);
|
||||
if (verbose){
|
||||
fprintf(stderr, "\n %s\n", description);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
//==================================================================================================
|
||||
// String option:
|
||||
|
||||
|
||||
class StringOption : public Option
|
||||
{
|
||||
const char* value;
|
||||
public:
|
||||
StringOption(const char* c, const char* n, const char* d, const char* def = NULL)
|
||||
: Option(n, d, c, "<string>"), value(def) {}
|
||||
|
||||
operator const char* (void) const { return value; }
|
||||
operator const char*& (void) { return value; }
|
||||
StringOption& operator= (const char* x) { value = x; return *this; }
|
||||
|
||||
virtual bool parse(const char* str){
|
||||
const char* span = str;
|
||||
|
||||
if (!match(span, "-") || !match(span, name) || !match(span, "="))
|
||||
return false;
|
||||
|
||||
value = span;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void help (bool verbose = false){
|
||||
fprintf(stderr, " -%-10s = %8s\n", name, type_name);
|
||||
if (verbose){
|
||||
fprintf(stderr, "\n %s\n", description);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
// Bool option:
|
||||
|
||||
|
||||
class BoolOption : public Option
|
||||
{
|
||||
bool value;
|
||||
|
||||
public:
|
||||
BoolOption(const char* c, const char* n, const char* d, bool v)
|
||||
: Option(n, d, c, "<bool>"), value(v) {}
|
||||
|
||||
operator bool (void) const { return value; }
|
||||
operator bool& (void) { return value; }
|
||||
BoolOption& operator=(bool b) { value = b; return *this; }
|
||||
|
||||
virtual bool parse(const char* str){
|
||||
const char* span = str;
|
||||
|
||||
if (match(span, "-")){
|
||||
bool b = !match(span, "no-");
|
||||
|
||||
if (strcmp(span, name) == 0){
|
||||
value = b;
|
||||
return true; }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void help (bool verbose = false){
|
||||
|
||||
fprintf(stderr, " -%s, -no-%s", name, name);
|
||||
|
||||
for (uint32_t i = 0; i < 32 - strlen(name)*2; i++)
|
||||
fprintf(stderr, " ");
|
||||
|
||||
fprintf(stderr, " ");
|
||||
fprintf(stderr, "(default: %s)\n", value ? "on" : "off");
|
||||
if (verbose){
|
||||
fprintf(stderr, "\n %s\n", description);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//=================================================================================================
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,122 @@
|
|||
/************************************************************************************[ParseUtils.h]
|
||||
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
|
||||
Copyright (c) 2007-2010, Niklas Sorensson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#ifndef Minisat_ParseUtils_h
|
||||
#define Minisat_ParseUtils_h
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
namespace Minisat {
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// A simple buffered character stream class:
|
||||
|
||||
static const int buffer_size = 1048576;
|
||||
|
||||
|
||||
class StreamBuffer {
|
||||
gzFile in;
|
||||
unsigned char buf[buffer_size];
|
||||
int pos;
|
||||
int size;
|
||||
|
||||
void assureLookahead() {
|
||||
if (pos >= size) {
|
||||
pos = 0;
|
||||
size = gzread(in, buf, sizeof(buf)); } }
|
||||
|
||||
public:
|
||||
explicit StreamBuffer(gzFile i) : in(i), pos(0), size(0) { assureLookahead(); }
|
||||
|
||||
int operator * () const { return (pos >= size) ? EOF : buf[pos]; }
|
||||
void operator ++ () { pos++; assureLookahead(); }
|
||||
int position () const { return pos; }
|
||||
};
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// End-of-file detection functions for StreamBuffer and char*:
|
||||
|
||||
|
||||
static inline bool isEof(StreamBuffer& in) { return *in == EOF; }
|
||||
static inline bool isEof(const char* in) { return *in == '\0'; }
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// Generic parse functions parametrized over the input-stream type.
|
||||
|
||||
|
||||
template<class B>
|
||||
static void skipWhitespace(B& in) {
|
||||
while ((*in >= 9 && *in <= 13) || *in == 32)
|
||||
++in; }
|
||||
|
||||
|
||||
template<class B>
|
||||
static void skipLine(B& in) {
|
||||
for (;;){
|
||||
if (isEof(in)) return;
|
||||
if (*in == '\n') { ++in; return; }
|
||||
++in; } }
|
||||
|
||||
|
||||
template<class B>
|
||||
static int parseInt(B& in) {
|
||||
int val = 0;
|
||||
bool neg = false;
|
||||
skipWhitespace(in);
|
||||
if (*in == '-') neg = true, ++in;
|
||||
else if (*in == '+') ++in;
|
||||
if (*in < '0' || *in > '9') fprintf(stderr, "PARSE ERROR! Unexpected char: %c\n", *in), exit(3);
|
||||
while (*in >= '0' && *in <= '9')
|
||||
val = val*10 + (*in - '0'),
|
||||
++in;
|
||||
return neg ? -val : val; }
|
||||
|
||||
|
||||
// String matching: in case of a match the input iterator will be advanced the corresponding
|
||||
// number of characters.
|
||||
template<class B>
|
||||
static bool match(B& in, const char* str) {
|
||||
int i;
|
||||
for (i = 0; str[i] != '\0'; i++)
|
||||
if (in[i] != str[i])
|
||||
return false;
|
||||
|
||||
in += i;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// String matching: consumes characters eagerly, but does not require random access iterator.
|
||||
template<class B>
|
||||
static bool eagerMatch(B& in, const char* str) {
|
||||
for (; *str != '\0'; ++str, ++in)
|
||||
if (*str != *in)
|
||||
return false;
|
||||
return true; }
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,92 @@
|
|||
/***************************************************************************************[System.cc]
|
||||
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
|
||||
Copyright (c) 2007-2010, Niklas Sorensson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#include "utils/System.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace Minisat;
|
||||
|
||||
// TODO: split the memory reading functions into two: one for reading high-watermark of RSS, and
|
||||
// one for reading the current virtual memory size.
|
||||
|
||||
static inline int memReadStat(int field)
|
||||
{
|
||||
char name[256];
|
||||
pid_t pid = getpid();
|
||||
int value;
|
||||
|
||||
sprintf(name, "/proc/%d/statm", pid);
|
||||
FILE* in = fopen(name, "rb");
|
||||
if (in == NULL) return 0;
|
||||
|
||||
for (; field >= 0; field--)
|
||||
if (fscanf(in, "%d", &value) != 1)
|
||||
printf("ERROR! Failed to parse memory statistics from \"/proc\".\n"), exit(1);
|
||||
fclose(in);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
static inline int memReadPeak(void)
|
||||
{
|
||||
char name[256];
|
||||
pid_t pid = getpid();
|
||||
|
||||
sprintf(name, "/proc/%d/status", pid);
|
||||
FILE* in = fopen(name, "rb");
|
||||
if (in == NULL) return 0;
|
||||
|
||||
// Find the correct line, beginning with "VmPeak:":
|
||||
int peak_kb = 0;
|
||||
while (!feof(in) && fscanf(in, "VmPeak: %d kB", &peak_kb) != 1)
|
||||
while (!feof(in) && fgetc(in) != '\n')
|
||||
;
|
||||
fclose(in);
|
||||
|
||||
return peak_kb;
|
||||
}
|
||||
|
||||
double Minisat::memUsed() { return (double)memReadStat(0) * (double)getpagesize() / (1024*1024); }
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
double Minisat::memUsed(void) {
|
||||
struct rusage ru;
|
||||
getrusage(RUSAGE_SELF, &ru);
|
||||
return (double)ru.ru_maxrss / 1024; }
|
||||
double MiniSat::memUsedPeak(void) { return memUsed(); }
|
||||
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
#include <malloc/malloc.h>
|
||||
|
||||
double Minisat::memUsed(void) {
|
||||
malloc_statistics_t t;
|
||||
malloc_zone_statistics(NULL, &t);
|
||||
return (double)t.max_size_in_use / (1024*1024); }
|
||||
|
||||
#else
|
||||
double Minisat::memUsed() {
|
||||
return 0; }
|
||||
#endif
|
|
@ -0,0 +1,60 @@
|
|||
/****************************************************************************************[System.h]
|
||||
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
|
||||
Copyright (c) 2007-2010, Niklas Sorensson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**************************************************************************************************/
|
||||
|
||||
#ifndef Minisat_System_h
|
||||
#define Minisat_System_h
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <fpu_control.h>
|
||||
#endif
|
||||
|
||||
#include "mtl/IntTypes.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
namespace Minisat {
|
||||
|
||||
static inline double cpuTime(void); // CPU-time in seconds.
|
||||
extern double memUsed(); // Memory in mega bytes (returns 0 for unsupported architectures).
|
||||
//extern double memUsedPeak(); // Peak-memory in mega bytes (returns 0 for unsupported architectures).
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// Implementation of inline functions:
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#include <time.h>
|
||||
|
||||
static inline double Minisat::cpuTime(void) { return (double)clock() / CLOCKS_PER_SEC; }
|
||||
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static inline double Minisat::cpuTime(void) {
|
||||
struct rusage ru;
|
||||
getrusage(RUSAGE_SELF, &ru);
|
||||
return (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec / 1000000; }
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,5 @@
|
|||
repo: 6ed5fe0ea387ba9808e21048f02c665b16aa8c23
|
||||
node: bdabbf66b2ad131199059736178664f44c69adaf
|
||||
branch: 1.3
|
||||
latesttag: r1.3
|
||||
latesttagdistance: 11
|
|
@ -0,0 +1,53 @@
|
|||
syntax: glob
|
||||
*.obj
|
||||
*.orig
|
||||
*.rej
|
||||
*~
|
||||
*.o
|
||||
*.log
|
||||
*.lo
|
||||
*.tar.*
|
||||
*.bak
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
config.h.in
|
||||
configure
|
||||
Makefile
|
||||
config.h
|
||||
config.log
|
||||
config.status
|
||||
libtool
|
||||
stamp-h1
|
||||
lemon/lemon.pc
|
||||
lemon/libemon.la
|
||||
lemon/stamp-h2
|
||||
doc/Doxyfile
|
||||
doc/references.dox
|
||||
cmake/version.cmake
|
||||
.dirstamp
|
||||
.libs/*
|
||||
.deps/*
|
||||
demo/*.eps
|
||||
m4/libtool.m4
|
||||
m4/ltoptions.m4
|
||||
m4/ltsugar.m4
|
||||
m4/ltversion.m4
|
||||
m4/lt~obsolete.m4
|
||||
|
||||
syntax: regexp
|
||||
(.*/)?\#[^/]*\#$
|
||||
(.*/)?\.\#[^/]*$
|
||||
^doc/html/.*
|
||||
^doc/.*\.tag
|
||||
^autom4te.cache/.*
|
||||
^build-aux/.*
|
||||
^.*objs.*/.*
|
||||
^test/[a-z_]*$
|
||||
^tools/[a-z-_]*$
|
||||
^demo/.*_demo$
|
||||
^.*build.*/.*
|
||||
^doc/gen-images/.*
|
||||
CMakeFiles
|
||||
DartTestfile.txt
|
||||
cmake_install.cmake
|
||||
CMakeCache.txt
|
|
@ -0,0 +1 @@
|
|||
57ab090b6109902536ee34b1e8d4d123474311e3 r1.3
|
|
@ -0,0 +1,26 @@
|
|||
The main developers of release series 1.x are
|
||||
|
||||
* Balazs Dezso <deba@inf.elte.hu>
|
||||
* Alpar Juttner <alpar@cs.elte.hu>
|
||||
* Peter Kovacs <kpeter@inf.elte.hu>
|
||||
* Akos Ladanyi <ladanyi@tmit.bme.hu>
|
||||
|
||||
For more complete list of contributors, please visit the history of
|
||||
the LEMON source code repository: http://lemon.cs.elte.hu/hg/lemon
|
||||
|
||||
Moreover, this version is heavily based on version 0.x of LEMON. Here
|
||||
is the list of people who contributed to those versions.
|
||||
|
||||
* Mihaly Barasz <klao@cs.elte.hu>
|
||||
* Johanna Becker <beckerjc@cs.elte.hu>
|
||||
* Attila Bernath <athos@cs.elte.hu>
|
||||
* Balazs Dezso <deba@inf.elte.hu>
|
||||
* Peter Hegyi <hegyi@tmit.bme.hu>
|
||||
* Alpar Juttner <alpar@cs.elte.hu>
|
||||
* Peter Kovacs <kpeter@inf.elte.hu>
|
||||
* Akos Ladanyi <ladanyi@tmit.bme.hu>
|
||||
* Marton Makai <marci@cs.elte.hu>
|
||||
* Jacint Szabo <jacint@cs.elte.hu>
|
||||
|
||||
Again, please visit the history of the old LEMON repository for more
|
||||
details: http://lemon.cs.elte.hu/hg/lemon-0.x
|
|
@ -0,0 +1,373 @@
|
|||
CMAKE_MINIMUM_REQUIRED(VERSION 3.1)
|
||||
|
||||
SET(PROJECT_NAME "LEMON")
|
||||
PROJECT(${PROJECT_NAME})
|
||||
|
||||
INCLUDE(FindPythonInterp)
|
||||
INCLUDE(FindWget)
|
||||
|
||||
IF(EXISTS ${PROJECT_SOURCE_DIR}/cmake/version.cmake)
|
||||
INCLUDE(${PROJECT_SOURCE_DIR}/cmake/version.cmake)
|
||||
ELSEIF(DEFINED ENV{LEMON_VERSION})
|
||||
SET(LEMON_VERSION $ENV{LEMON_VERSION} CACHE STRING "LEMON version string.")
|
||||
ELSE()
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND
|
||||
hg log -r. --template "{latesttag}"
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE HG_REVISION_TAG
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND
|
||||
hg log -r. --template "{latesttagdistance}"
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE HG_REVISION_DIST
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND
|
||||
hg log -r. --template "{node|short}"
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE HG_REVISION_ID
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
IF(HG_REVISION_TAG STREQUAL "")
|
||||
SET(HG_REVISION_ID "hg-tip")
|
||||
ELSE()
|
||||
IF(HG_REVISION_TAG STREQUAL "null")
|
||||
SET(HG_REVISION_TAG "trunk")
|
||||
ELSEIF(HG_REVISION_TAG MATCHES "^r")
|
||||
STRING(SUBSTRING ${HG_REVISION_TAG} 1 -1 HG_REVISION_TAG)
|
||||
ENDIF()
|
||||
IF(HG_REVISION_DIST STREQUAL "0")
|
||||
SET(HG_REVISION ${HG_REVISION_TAG})
|
||||
ELSE()
|
||||
SET(HG_REVISION
|
||||
"${HG_REVISION_TAG}+${HG_REVISION_DIST}-${HG_REVISION_ID}")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
SET(LEMON_VERSION ${HG_REVISION} CACHE STRING "LEMON version string.")
|
||||
ENDIF()
|
||||
|
||||
SET(PROJECT_VERSION ${LEMON_VERSION})
|
||||
|
||||
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||
|
||||
FIND_PACKAGE(Doxygen)
|
||||
FIND_PACKAGE(Ghostscript)
|
||||
|
||||
SET(LEMON_ENABLE_GLPK YES CACHE STRING "Enable GLPK solver backend.")
|
||||
SET(LEMON_ENABLE_ILOG YES CACHE STRING "Enable ILOG (CPLEX) solver backend.")
|
||||
SET(LEMON_ENABLE_COIN YES CACHE STRING "Enable COIN solver backend.")
|
||||
SET(LEMON_ENABLE_SOPLEX YES CACHE STRING "Enable SoPlex solver backend.")
|
||||
|
||||
IF(LEMON_ENABLE_GLPK)
|
||||
FIND_PACKAGE(GLPK 4.33)
|
||||
ENDIF(LEMON_ENABLE_GLPK)
|
||||
IF(LEMON_ENABLE_ILOG)
|
||||
FIND_PACKAGE(ILOG)
|
||||
ENDIF(LEMON_ENABLE_ILOG)
|
||||
IF(LEMON_ENABLE_COIN)
|
||||
FIND_PACKAGE(COIN)
|
||||
ENDIF(LEMON_ENABLE_COIN)
|
||||
IF(LEMON_ENABLE_SOPLEX)
|
||||
FIND_PACKAGE(SOPLEX)
|
||||
ENDIF(LEMON_ENABLE_SOPLEX)
|
||||
|
||||
IF(GLPK_FOUND)
|
||||
SET(LEMON_HAVE_LP TRUE)
|
||||
SET(LEMON_HAVE_MIP TRUE)
|
||||
SET(LEMON_HAVE_GLPK TRUE)
|
||||
ENDIF(GLPK_FOUND)
|
||||
IF(ILOG_FOUND)
|
||||
SET(LEMON_HAVE_LP TRUE)
|
||||
SET(LEMON_HAVE_MIP TRUE)
|
||||
SET(LEMON_HAVE_CPLEX TRUE)
|
||||
ENDIF(ILOG_FOUND)
|
||||
IF(COIN_FOUND)
|
||||
SET(LEMON_HAVE_LP TRUE)
|
||||
SET(LEMON_HAVE_MIP TRUE)
|
||||
SET(LEMON_HAVE_CLP TRUE)
|
||||
SET(LEMON_HAVE_CBC TRUE)
|
||||
ENDIF(COIN_FOUND)
|
||||
IF(SOPLEX_FOUND)
|
||||
SET(LEMON_HAVE_LP TRUE)
|
||||
SET(LEMON_HAVE_SOPLEX TRUE)
|
||||
ENDIF(SOPLEX_FOUND)
|
||||
|
||||
IF(ILOG_FOUND)
|
||||
SET(DEFAULT_LP "CPLEX")
|
||||
SET(DEFAULT_MIP "CPLEX")
|
||||
ELSEIF(COIN_FOUND)
|
||||
SET(DEFAULT_LP "CLP")
|
||||
SET(DEFAULT_MIP "CBC")
|
||||
ELSEIF(GLPK_FOUND)
|
||||
SET(DEFAULT_LP "GLPK")
|
||||
SET(DEFAULT_MIP "GLPK")
|
||||
ELSEIF(SOPLEX_FOUND)
|
||||
SET(DEFAULT_LP "SOPLEX")
|
||||
ENDIF()
|
||||
|
||||
IF(NOT LEMON_DEFAULT_LP OR
|
||||
(NOT ILOG_FOUND AND (LEMON_DEFAULT_LP STREQUAL "CPLEX")) OR
|
||||
(NOT COIN_FOUND AND (LEMON_DEFAULT_LP STREQUAL "CLP")) OR
|
||||
(NOT GLPK_FOUND AND (LEMON_DEFAULT_LP STREQUAL "GLPK")) OR
|
||||
(NOT SOPLEX_FOUND AND (LEMON_DEFAULT_LP STREQUAL "SOPLEX")))
|
||||
SET(LEMON_DEFAULT_LP ${DEFAULT_LP} CACHE STRING
|
||||
"Default LP solver backend (GLPK, CPLEX, CLP or SOPLEX)" FORCE)
|
||||
ELSE()
|
||||
SET(LEMON_DEFAULT_LP ${DEFAULT_LP} CACHE STRING
|
||||
"Default LP solver backend (GLPK, CPLEX, CLP or SOPLEX)")
|
||||
ENDIF()
|
||||
IF(NOT LEMON_DEFAULT_MIP OR
|
||||
(NOT ILOG_FOUND AND (LEMON_DEFAULT_MIP STREQUAL "CPLEX")) OR
|
||||
(NOT COIN_FOUND AND (LEMON_DEFAULT_MIP STREQUAL "CBC")) OR
|
||||
(NOT GLPK_FOUND AND (LEMON_DEFAULT_MIP STREQUAL "GLPK")))
|
||||
SET(LEMON_DEFAULT_MIP ${DEFAULT_MIP} CACHE STRING
|
||||
"Default MIP solver backend (GLPK, CPLEX or CBC)" FORCE)
|
||||
ELSE()
|
||||
SET(LEMON_DEFAULT_MIP ${DEFAULT_MIP} CACHE STRING
|
||||
"Default MIP solver backend (GLPK, CPLEX or CBC)")
|
||||
ENDIF()
|
||||
|
||||
|
||||
IF(DEFINED ENV{LEMON_CXX_WARNING})
|
||||
SET(CXX_WARNING $ENV{LEMON_CXX_WARNING})
|
||||
ELSE()
|
||||
IF(CMAKE_COMPILER_IS_GNUCXX)
|
||||
SET(CXX_WARNING "-Wall -W -Wunused -Wformat=2 -Wctor-dtor-privacy -Wnon-virtual-dtor -Wno-char-subscripts -Wwrite-strings -Wno-char-subscripts -Wreturn-type -Wcast-qual -Wcast-align -Wsign-promo -Woverloaded-virtual -fno-strict-aliasing -Wold-style-cast -Wno-unknown-pragmas")
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG CACHE STRING "-ggdb")
|
||||
SET(CMAKE_C_FLAGS_DEBUG CACHE STRING "-ggdb")
|
||||
ELSEIF(MSVC)
|
||||
# This part is unnecessary 'casue the same is set by the lemon/core.h.
|
||||
# Still keep it as an example.
|
||||
SET(CXX_WARNING "/wd4250 /wd4355 /wd4503 /wd4800 /wd4996")
|
||||
# Suppressed warnings:
|
||||
# C4250: 'class1' : inherits 'class2::member' via dominance
|
||||
# C4355: 'this' : used in base member initializer list
|
||||
# C4503: 'function' : decorated name length exceeded, name was truncated
|
||||
# C4800: 'type' : forcing value to bool 'true' or 'false'
|
||||
# (performance warning)
|
||||
# C4996: 'function': was declared deprecated
|
||||
ELSE()
|
||||
SET(CXX_WARNING "-Wall")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
SET(LEMON_CXX_WARNING_FLAGS ${CXX_WARNING} CACHE STRING "LEMON warning flags.")
|
||||
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LEMON_CXX_WARNING_FLAGS}")
|
||||
|
||||
IF(MSVC)
|
||||
SET( CMAKE_CXX_FLAGS_MAINTAINER "/WX ${CMAKE_CXX_FLAGS_DEBUG}" CACHE STRING
|
||||
"Flags used by the C++ compiler during maintainer builds."
|
||||
)
|
||||
SET( CMAKE_C_FLAGS_MAINTAINER "/WX ${CMAKE_CXX_FLAGS_DEBUG}" CACHE STRING
|
||||
"Flags used by the C compiler during maintainer builds."
|
||||
)
|
||||
SET( CMAKE_EXE_LINKER_FLAGS_MAINTAINER
|
||||
"${CMAKE_EXE_LINKER_FLAGS_DEBUG}" CACHE STRING
|
||||
"Flags used for linking binaries during maintainer builds."
|
||||
)
|
||||
SET( CMAKE_SHARED_LINKER_FLAGS_MAINTAINER
|
||||
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE STRING
|
||||
"Flags used by the shared libraries linker during maintainer builds."
|
||||
)
|
||||
ELSE()
|
||||
SET( CMAKE_CXX_FLAGS_MAINTAINER "-Werror -ggdb -O0" CACHE STRING
|
||||
"Flags used by the C++ compiler during maintainer builds."
|
||||
)
|
||||
SET( CMAKE_C_FLAGS_MAINTAINER "-Werror -O0" CACHE STRING
|
||||
"Flags used by the C compiler during maintainer builds."
|
||||
)
|
||||
SET( CMAKE_EXE_LINKER_FLAGS_MAINTAINER
|
||||
"${CMAKE_EXE_LINKER_FLAGS_DEBUG}" CACHE STRING
|
||||
"Flags used for linking binaries during maintainer builds."
|
||||
)
|
||||
SET( CMAKE_SHARED_LINKER_FLAGS_MAINTAINER
|
||||
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE STRING
|
||||
"Flags used by the shared libraries linker during maintainer builds."
|
||||
)
|
||||
ENDIF()
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
CMAKE_CXX_FLAGS_MAINTAINER
|
||||
CMAKE_C_FLAGS_MAINTAINER
|
||||
CMAKE_EXE_LINKER_FLAGS_MAINTAINER
|
||||
CMAKE_SHARED_LINKER_FLAGS_MAINTAINER )
|
||||
|
||||
IF(CMAKE_CONFIGURATION_TYPES)
|
||||
LIST(APPEND CMAKE_CONFIGURATION_TYPES Maintainer)
|
||||
LIST(REMOVE_DUPLICATES CMAKE_CONFIGURATION_TYPES)
|
||||
SET(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING
|
||||
"Add the configurations that we need"
|
||||
FORCE)
|
||||
endif()
|
||||
|
||||
IF(NOT CMAKE_BUILD_TYPE)
|
||||
SET(CMAKE_BUILD_TYPE "Release")
|
||||
ENDIF()
|
||||
|
||||
SET( CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING
|
||||
"Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel Maintainer."
|
||||
FORCE )
|
||||
|
||||
|
||||
INCLUDE(CheckTypeSize)
|
||||
CHECK_TYPE_SIZE("long long" LONG_LONG)
|
||||
SET(LEMON_HAVE_LONG_LONG ${HAVE_LONG_LONG})
|
||||
|
||||
INCLUDE(FindThreads)
|
||||
|
||||
IF(NOT LEMON_THREADING)
|
||||
IF(CMAKE_USE_PTHREADS_INIT)
|
||||
SET(LEMON_THREADING "Pthread")
|
||||
ELSEIF(CMAKE_USE_WIN32_THREADS_INIT)
|
||||
SET(LEMON_THREADING "Win32")
|
||||
ELSE()
|
||||
SET(LEMON_THREADING "None")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
SET( LEMON_THREADING "${LEMON_THREADING}" CACHE STRING
|
||||
"Choose the threading library, options are: Pthread Win32 None."
|
||||
FORCE )
|
||||
|
||||
IF(LEMON_THREADING STREQUAL "Pthread")
|
||||
SET(LEMON_USE_PTHREAD TRUE)
|
||||
ELSEIF(LEMON_THREADING STREQUAL "Win32")
|
||||
SET(LEMON_USE_WIN32_THREADS TRUE)
|
||||
ENDIF()
|
||||
|
||||
ENABLE_TESTING()
|
||||
|
||||
IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer")
|
||||
ADD_CUSTOM_TARGET(check ALL COMMAND ${CMAKE_CTEST_COMMAND})
|
||||
ELSE()
|
||||
ADD_CUSTOM_TARGET(check COMMAND ${CMAKE_CTEST_COMMAND})
|
||||
ENDIF()
|
||||
|
||||
ADD_SUBDIRECTORY(lemon)
|
||||
IF(${CMAKE_SOURCE_DIR} STREQUAL ${PROJECT_SOURCE_DIR})
|
||||
ADD_SUBDIRECTORY(contrib)
|
||||
ADD_SUBDIRECTORY(demo)
|
||||
ADD_SUBDIRECTORY(tools)
|
||||
ADD_SUBDIRECTORY(doc)
|
||||
ADD_SUBDIRECTORY(test)
|
||||
ENDIF()
|
||||
|
||||
CONFIGURE_FILE(
|
||||
${PROJECT_SOURCE_DIR}/cmake/LEMONConfig.cmake.in
|
||||
${PROJECT_BINARY_DIR}/cmake/LEMONConfig.cmake
|
||||
@ONLY
|
||||
)
|
||||
IF(UNIX)
|
||||
INSTALL(
|
||||
FILES ${PROJECT_BINARY_DIR}/cmake/LEMONConfig.cmake
|
||||
DESTINATION share/lemon/cmake
|
||||
)
|
||||
ELSEIF(WIN32)
|
||||
INSTALL(
|
||||
FILES ${PROJECT_BINARY_DIR}/cmake/LEMONConfig.cmake
|
||||
DESTINATION cmake
|
||||
)
|
||||
ENDIF()
|
||||
|
||||
CONFIGURE_FILE(
|
||||
${PROJECT_SOURCE_DIR}/cmake/version.cmake.in
|
||||
${PROJECT_BINARY_DIR}/cmake/version.cmake
|
||||
@ONLY
|
||||
)
|
||||
|
||||
SET(ARCHIVE_BASE_NAME ${CMAKE_PROJECT_NAME})
|
||||
STRING(TOLOWER ${ARCHIVE_BASE_NAME} ARCHIVE_BASE_NAME)
|
||||
SET(ARCHIVE_NAME ${ARCHIVE_BASE_NAME}-${PROJECT_VERSION})
|
||||
ADD_CUSTOM_TARGET(dist
|
||||
COMMAND cmake -E remove_directory ${ARCHIVE_NAME}
|
||||
COMMAND hg archive ${ARCHIVE_NAME}
|
||||
COMMAND cmake -E copy cmake/version.cmake ${ARCHIVE_NAME}/cmake/version.cmake
|
||||
COMMAND tar -czf ${ARCHIVE_BASE_NAME}-nodoc-${PROJECT_VERSION}.tar.gz ${ARCHIVE_NAME}
|
||||
COMMAND zip -r ${ARCHIVE_BASE_NAME}-nodoc-${PROJECT_VERSION}.zip ${ARCHIVE_NAME}
|
||||
COMMAND cmake -E copy_directory doc/html ${ARCHIVE_NAME}/doc/html
|
||||
COMMAND tar -czf ${ARCHIVE_NAME}.tar.gz ${ARCHIVE_NAME}
|
||||
COMMAND zip -r ${ARCHIVE_NAME}.zip ${ARCHIVE_NAME}
|
||||
COMMAND cmake -E copy_directory doc/html ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}
|
||||
COMMAND tar -czf ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}.tar.gz ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}
|
||||
COMMAND zip -r ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}.zip ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}
|
||||
COMMAND cmake -E remove_directory ${ARCHIVE_NAME}
|
||||
COMMAND cmake -E remove_directory ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}
|
||||
DEPENDS html
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
|
||||
|
||||
# CPACK config (Basically for NSIS)
|
||||
IF(${CMAKE_SOURCE_DIR} STREQUAL ${PROJECT_SOURCE_DIR})
|
||||
SET(CPACK_PACKAGE_NAME ${PROJECT_NAME})
|
||||
SET(CPACK_PACKAGE_VENDOR "EGRES")
|
||||
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY
|
||||
"LEMON - Library for Efficient Modeling and Optimization in Networks")
|
||||
SET(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
|
||||
|
||||
SET(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
|
||||
|
||||
SET(CPACK_PACKAGE_INSTALL_DIRECTORY
|
||||
"${PROJECT_NAME} ${PROJECT_VERSION}")
|
||||
SET(CPACK_PACKAGE_INSTALL_REGISTRY_KEY
|
||||
"${PROJECT_NAME} ${PROJECT_VERSION}")
|
||||
|
||||
SET(CPACK_COMPONENTS_ALL headers library html_documentation bin)
|
||||
|
||||
SET(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "C++ headers")
|
||||
SET(CPACK_COMPONENT_LIBRARY_DISPLAY_NAME "Dynamic-link library")
|
||||
SET(CPACK_COMPONENT_BIN_DISPLAY_NAME "Command line utilities")
|
||||
SET(CPACK_COMPONENT_HTML_DOCUMENTATION_DISPLAY_NAME "HTML documentation")
|
||||
|
||||
SET(CPACK_COMPONENT_HEADERS_DESCRIPTION
|
||||
"C++ header files")
|
||||
SET(CPACK_COMPONENT_LIBRARY_DESCRIPTION
|
||||
"DLL and import library")
|
||||
SET(CPACK_COMPONENT_BIN_DESCRIPTION
|
||||
"Command line utilities")
|
||||
SET(CPACK_COMPONENT_HTML_DOCUMENTATION_DESCRIPTION
|
||||
"Doxygen generated documentation")
|
||||
|
||||
SET(CPACK_COMPONENT_HEADERS_DEPENDS library)
|
||||
|
||||
SET(CPACK_COMPONENT_HEADERS_GROUP "Development")
|
||||
SET(CPACK_COMPONENT_LIBRARY_GROUP "Development")
|
||||
SET(CPACK_COMPONENT_HTML_DOCUMENTATION_GROUP "Documentation")
|
||||
|
||||
SET(CPACK_COMPONENT_GROUP_DEVELOPMENT_DESCRIPTION
|
||||
"Components needed to develop software using LEMON")
|
||||
SET(CPACK_COMPONENT_GROUP_DOCUMENTATION_DESCRIPTION
|
||||
"Documentation of LEMON")
|
||||
|
||||
SET(CPACK_ALL_INSTALL_TYPES Full Developer)
|
||||
|
||||
SET(CPACK_COMPONENT_HEADERS_INSTALL_TYPES Developer Full)
|
||||
SET(CPACK_COMPONENT_LIBRARY_INSTALL_TYPES Developer Full)
|
||||
SET(CPACK_COMPONENT_HTML_DOCUMENTATION_INSTALL_TYPES Full)
|
||||
|
||||
SET(CPACK_GENERATOR "NSIS")
|
||||
SET(CPACK_NSIS_MUI_ICON "${PROJECT_SOURCE_DIR}/cmake/nsis/lemon.ico")
|
||||
SET(CPACK_NSIS_MUI_UNIICON "${PROJECT_SOURCE_DIR}/cmake/nsis/uninstall.ico")
|
||||
#SET(CPACK_PACKAGE_ICON "${PROJECT_SOURCE_DIR}/cmake/nsis\\\\installer.bmp")
|
||||
SET(CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\lemon.ico")
|
||||
SET(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} ${PROJECT_NAME}")
|
||||
SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\lemon.cs.elte.hu")
|
||||
SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\lemon.cs.elte.hu")
|
||||
SET(CPACK_NSIS_CONTACT "lemon-user@lemon.cs.elte.hu")
|
||||
SET(CPACK_NSIS_CREATE_ICONS_EXTRA "
|
||||
CreateShortCut \\\"$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Documentation.lnk\\\" \\\"$INSTDIR\\\\share\\\\doc\\\\index.html\\\"
|
||||
")
|
||||
SET(CPACK_NSIS_DELETE_ICONS_EXTRA "
|
||||
!insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP
|
||||
Delete \\\"$SMPROGRAMS\\\\$MUI_TEMP\\\\Documentation.lnk\\\"
|
||||
")
|
||||
|
||||
INCLUDE(CPack)
|
||||
ENDIF()
|
|
@ -0,0 +1,167 @@
|
|||
Installation Instructions
|
||||
=========================
|
||||
|
||||
This file contains instructions for building and installing LEMON from
|
||||
source on Linux. The process on Windows is similar.
|
||||
|
||||
Note that it is not necessary to install LEMON in order to use
|
||||
it. Instead, you can easily integrate it with your own code
|
||||
directly. For instructions, see
|
||||
https://lemon.cs.elte.hu/trac/lemon/wiki/HowToCompile
|
||||
|
||||
|
||||
In order to install LEMON from the extracted source tarball you have to
|
||||
issue the following commands:
|
||||
|
||||
1. Step into the root of the source directory.
|
||||
|
||||
$ cd lemon-x.y.z
|
||||
|
||||
2. Create a build subdirectory and step into it.
|
||||
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
|
||||
3. Perform system checks and create the makefiles.
|
||||
|
||||
$ cmake ..
|
||||
|
||||
4. Build LEMON.
|
||||
|
||||
$ make
|
||||
|
||||
This command compiles the non-template part of LEMON into
|
||||
libemon.a file. It also compiles the programs in the 'tools' and
|
||||
'demo' subdirectories.
|
||||
|
||||
5. [Optional] Compile and run the self-tests.
|
||||
|
||||
$ make check
|
||||
|
||||
5. [Optional] Generate the user documentation.
|
||||
|
||||
$ make html
|
||||
|
||||
The release tarballs already include the documentation.
|
||||
|
||||
Note that for this step you need to have the following tools
|
||||
installed: Python, Doxygen, Graphviz, Ghostscript, LaTeX.
|
||||
|
||||
6. [Optional] Install LEMON
|
||||
|
||||
$ make install
|
||||
|
||||
This command installs LEMON under /usr/local (you will need root
|
||||
privileges to be able to do that). If you want to install it to
|
||||
some other location, then pass the
|
||||
-DCMAKE_INSTALL_PREFIX=DIRECTORY flag to cmake in Step 3.
|
||||
For example:
|
||||
|
||||
$ cmake -DCMAKE_INSTALL_PREFIX=/home/username/lemon'
|
||||
|
||||
Configure Options and Variables
|
||||
===============================
|
||||
|
||||
In Step 3, you can customize the build process by passing options to CMAKE.
|
||||
|
||||
$ cmake [OPTIONS] ..
|
||||
|
||||
You find a list of the most useful options below.
|
||||
|
||||
-DCMAKE_INSTALL_PREFIX=PREFIX
|
||||
|
||||
Set the installation prefix to PREFIX. By default it is /usr/local.
|
||||
|
||||
-DCMAKE_BUILD_TYPE=[Release|Debug|Maintainer|...]
|
||||
|
||||
This sets the compiler options. The choices are the following
|
||||
|
||||
'Release': A strong optimization is turned on (-O3 with gcc). This
|
||||
is the default setting and we strongly recommend using this for
|
||||
the final compilation.
|
||||
|
||||
'Debug': Optimization is turned off and debug info is added (-O0
|
||||
-ggdb with gcc). If is recommended during the development.
|
||||
|
||||
'Maintainer': The same as 'Debug' but the compiler warnings are
|
||||
converted to errors (-Werror with gcc). In addition, 'make' will
|
||||
also automatically compile and execute the test codes. It is the
|
||||
best way of ensuring that LEMON codebase is clean and safe.
|
||||
|
||||
'RelWithDebInfo': Optimized build with debug info.
|
||||
|
||||
'MinSizeRel': Size optimized build (-Os with gcc)
|
||||
|
||||
-DTEST_WITH_VALGRIND=YES
|
||||
|
||||
Using this, the test codes will be executed using valgrind. It is a
|
||||
very effective way of identifying indexing problems and memory leaks.
|
||||
|
||||
-DCMAKE_CXX_COMPILER=path-to-compiler
|
||||
|
||||
Change the compiler to be used.
|
||||
|
||||
-DBUILD_SHARED_LIBS=TRUE
|
||||
|
||||
Build shared library instead of static one. Think twice if you
|
||||
really want to use this option.
|
||||
|
||||
-DLEMON_DOC_SOURCE_BROWSER=YES
|
||||
|
||||
Include the browsable cross referenced LEMON source code into the
|
||||
doc. It makes the doc quite bloated, but may be useful for
|
||||
developing LEMON itself.
|
||||
|
||||
-DLEMON_DOC_USE_MATHJAX=YES
|
||||
|
||||
Use MathJax (http://mathjax.org) for rendering the math formulae in
|
||||
the doc. It of much higher quality compared to the default LaTeX
|
||||
generated static images and it allows copy&paste of the formulae to
|
||||
LaTeX, Open Office, MS Word etc. documents.
|
||||
|
||||
On the other hand, it needs either Internet access or a locally
|
||||
installed version of MathJax to properly render the doc.
|
||||
|
||||
-DLEMON_DOC_MATHJAX_RELPATH=DIRECTORY
|
||||
|
||||
The location of the MathJax library. It defaults to
|
||||
http://www.mathjax.org/mathjax, which necessitates Internet access
|
||||
for proper rendering. The easiest way to make it usable offline is
|
||||
to set this parameter to 'mathjax' and copy all files of the MathJax
|
||||
library into the 'doc/html/mathjax' subdirectory of the build
|
||||
location.
|
||||
|
||||
See http://docs.mathjax.org/en/latest/installation.html for more details.
|
||||
|
||||
|
||||
-DLEMON_ENABLE_GLPK=NO
|
||||
-DLEMON_ENABLE_COIN=NO
|
||||
-DLEMON_ENABLE_ILOG=NO
|
||||
|
||||
Enable optional third party libraries. They are all enabled by default.
|
||||
|
||||
-DLEMON_DEFAULT_LP=GLPK
|
||||
|
||||
Sets the default LP solver backend. The supported values are
|
||||
CPLEX, CLP and GLPK. By default, it is set to the first one which
|
||||
is enabled and succesfully discovered.
|
||||
|
||||
-DLEMON_DEFAULT_MIP=GLPK
|
||||
|
||||
Sets the default MIP solver backend. The supported values are
|
||||
CPLEX, CBC and GLPK. By default, it is set to the first one which
|
||||
is enabled and succesfully discovered.
|
||||
|
||||
-DGLPK_ROOT_DIR=DIRECTORY
|
||||
-DCOIN_ROOT_DIR=DIRECTORY
|
||||
-DILOG_ROOT_DIR=DIRECTORY
|
||||
|
||||
Root directory prefixes of optional third party libraries.
|
||||
|
||||
Makefile Variables
|
||||
==================
|
||||
|
||||
make VERBOSE=1
|
||||
|
||||
This results in a more verbose output by showing the full
|
||||
compiler and linker commands.
|
|
@ -0,0 +1,32 @@
|
|||
LEMON code without an explicit copyright notice is covered by the following
|
||||
copyright/license.
|
||||
|
||||
Copyright (C) 2003-2012 Egervary Jeno Kombinatorikus Optimalizalasi
|
||||
Kutatocsoport (Egervary Combinatorial Optimization Research Group,
|
||||
EGRES).
|
||||
|
||||
===========================================================================
|
||||
Boost Software License, Version 1.0
|
||||
===========================================================================
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,337 @@
|
|||
2014-07-07 Version 1.3.1 released
|
||||
|
||||
Bugfix release.
|
||||
|
||||
#484: Require CMAKE 2.8
|
||||
#471, #472, #480: Various clang compatibility fixes
|
||||
#481, #482: Fix shared lib build and versioning
|
||||
#476: Fix invalid map query in NearestNeighborTsp
|
||||
#478: Bugfix in debug checking and lower bound handling
|
||||
in min cost flow algorithms
|
||||
#479, #465: Bugfix in default LP/MIP backend settings
|
||||
#476: Bugfix in tsp_test
|
||||
#487: Add missing include header and std:: namespace spec.
|
||||
#474: Fix division by zero error in NetworkSimplex
|
||||
|
||||
2013-08-10 Version 1.3 released
|
||||
|
||||
This is major feature release
|
||||
|
||||
* New data structures
|
||||
|
||||
#69 : Bipartite graph concepts and implementations
|
||||
|
||||
* New algorithms
|
||||
|
||||
#177: Port Edmonds-Karp algorithm
|
||||
#380, #405: Heuristic algorithm for the max clique problem
|
||||
#386: Heuristic algorithms for symmetric TSP
|
||||
----: Nagamochi-Ibaraki algorithm [5087694945e4]
|
||||
#397, #56: Max. cardinality search
|
||||
|
||||
* Other new features
|
||||
|
||||
#223: Thread safe graph and graph map implementations
|
||||
#442: Different TimeStamp print formats
|
||||
#457: File export functionality to LpBase
|
||||
#362: Bidirectional iterator support for radixSort()
|
||||
|
||||
* Implementation improvements
|
||||
|
||||
----: Network Simplex
|
||||
#391: Better update process, pivot rule and arc mixing
|
||||
#435: Improved Altering List pivot rule
|
||||
#417: Various fine tunings in CostScaling
|
||||
#438: Optional iteration limit in HowardMmc
|
||||
#436: Ensure strongly polynomial running time for CycleCanceling
|
||||
while keeping the same performance
|
||||
----: Make the CBC interface be compatible with latest CBC releases
|
||||
[ee581a0ecfbf]
|
||||
|
||||
* CMAKE has become the default build environment (#434)
|
||||
|
||||
----: Autotool support has been dropped
|
||||
----: Improved LP/MIP configuration
|
||||
#465: Enable/disable options for LP/MIP backends
|
||||
#446: Better CPLEX discovery
|
||||
#460: Add cmake config to find SoPlex
|
||||
----: Allow CPACK configuration on all platforms
|
||||
#390: Add 'Maintainer' CMAKE build type
|
||||
#388: Add 'check' target.
|
||||
#401: Add contrib dir
|
||||
#389: Better version string setting in CMAKE
|
||||
#433: Support shared library build
|
||||
#416: Support testing with valgrind
|
||||
|
||||
* Doc improvements
|
||||
|
||||
#395: SOURCE_BROWSER Doxygen switch is configurable from CMAKE
|
||||
update-external-tags CMAKE target
|
||||
#455: Optionally use MathJax for rendering the math formulae
|
||||
#402, #437, #459, #456, #463: Various doc improvements
|
||||
|
||||
* Bugfixes (compared to release 1.2):
|
||||
|
||||
#432: Add missing doc/template.h and doc/references.bib to release
|
||||
tarball
|
||||
----: Intel C++ compatibility fixes
|
||||
#441: Fix buggy reinitialization in _solver_bits::VarIndex::clear()
|
||||
#444: Bugfix in path copy constructors and assignment operators
|
||||
#447: Bugfix in AllArcLookUp<>
|
||||
#448: Bugfix in adaptor_test.cc
|
||||
#449: Fix clang compilation warnings and errors
|
||||
#440: Fix a bug + remove redundant typedefs in dimacs-solver
|
||||
#453: Avoid GCC 4.7 compiler warnings
|
||||
#445: Fix missing initialization in CplexEnv::CplexEnv()
|
||||
#428: Add missing lemon/lemon.pc.cmake to the release tarball
|
||||
#393: Create and install lemon.pc
|
||||
#429: Fix VS warnings
|
||||
#430: Fix LpBase::Constr two-side limit bug
|
||||
#392: Bug fix in Dfs::start(s,t)
|
||||
#414: Fix wrong initialization in Preflow
|
||||
#418: Better Win CodeBlock/MinGW support
|
||||
#419: Build environment improvements
|
||||
- Build of mip_test and lp_test precede the running of the tests
|
||||
- Also search for coin libs under ${COIN_ROOT_DIR}/lib/coin
|
||||
- Do not look for COIN_VOL libraries
|
||||
#382: Allow lgf file without Arc maps
|
||||
#417: Bug fix in CostScaling
|
||||
#366: Fix Pred[Matrix]MapPath::empty()
|
||||
#371: Bug fix in (di)graphCopy()
|
||||
The target graph is cleared before adding nodes and arcs/edges.
|
||||
#364: Add missing UndirectedTags
|
||||
#368: Fix the usage of std::numeric_limits<>::min() in Network Simplex
|
||||
#372: Fix a critical bug in preflow
|
||||
#461: Bugfix in assert.h
|
||||
#470: Fix compilation issues related to various gcc versions
|
||||
#446: Fix #define indicating CPLEX availability
|
||||
#294: Add explicit namespace to
|
||||
ignore_unused_variable_warning() usages
|
||||
#420: Bugfix in IterableValueMap
|
||||
#439: Bugfix in biNodeConnected()
|
||||
|
||||
|
||||
2010-03-19 Version 1.2 released
|
||||
|
||||
This is major feature release
|
||||
|
||||
* New algorithms
|
||||
* Bellman-Ford algorithm (#51)
|
||||
* Minimum mean cycle algorithms (#179)
|
||||
* Karp, Hartman-Orlin and Howard algorithms
|
||||
* New minimum cost flow algorithms (#180)
|
||||
* Cost Scaling algorithms
|
||||
* Capacity Scaling algorithm
|
||||
* Cycle-Canceling algorithms
|
||||
* Planarity related algorithms (#62)
|
||||
* Planarity checking algorithm
|
||||
* Planar embedding algorithm
|
||||
* Schnyder's planar drawing algorithm
|
||||
* Coloring planar graphs with five or six colors
|
||||
* Fractional matching algorithms (#314)
|
||||
* New data structures
|
||||
* StaticDigraph structure (#68)
|
||||
* Several new priority queue structures (#50, #301)
|
||||
* Fibonacci, Radix, Bucket, Pairing, Binomial
|
||||
D-ary and fourary heaps (#301)
|
||||
* Iterable map structures (#73)
|
||||
* Other new tools and functionality
|
||||
* Map utility functions (#320)
|
||||
* Reserve functions are added to ListGraph and SmartGraph (#311)
|
||||
* A resize() function is added to HypercubeGraph (#311)
|
||||
* A count() function is added to CrossRefMap (#302)
|
||||
* Support for multiple targets in Suurballe using fullInit() (#181)
|
||||
* Traits class and named parameters for Suurballe (#323)
|
||||
* Separate reset() and resetParams() functions in NetworkSimplex
|
||||
to handle graph changes (#327)
|
||||
* tolerance() functions are added to HaoOrlin (#306)
|
||||
* Implementation improvements
|
||||
* Improvements in weighted matching algorithms (#314)
|
||||
* Jumpstart initialization
|
||||
* ArcIt iteration is based on out-arc lists instead of in-arc lists
|
||||
in ListDigraph (#311)
|
||||
* Faster add row operation in CbcMip (#203)
|
||||
* Better implementation for split() in ListDigraph (#311)
|
||||
* ArgParser can also throw exception instead of exit(1) (#332)
|
||||
* Miscellaneous
|
||||
* A simple interactive bootstrap script
|
||||
* Doc improvements (#62,#180,#299,#302,#303,#304,#307,#311,#331,#315,
|
||||
#316,#319)
|
||||
* BibTeX references in the doc (#184)
|
||||
* Optionally use valgrind when running tests
|
||||
* Also check ReferenceMapTag in concept checks (#312)
|
||||
* dimacs-solver uses long long type by default.
|
||||
* Several bugfixes (compared to release 1.1):
|
||||
#295: Suppress MSVC warnings using pragmas
|
||||
----: Various CMAKE related improvements
|
||||
* Remove duplications from doc/CMakeLists.txt
|
||||
* Rename documentation install folder from 'docs' to 'html'
|
||||
* Add tools/CMakeLists.txt to the tarball
|
||||
* Generate and install LEMONConfig.cmake
|
||||
* Change the label of the html project in Visual Studio
|
||||
* Fix the check for the 'long long' type
|
||||
* Put the version string into config.h
|
||||
* Minor CMake improvements
|
||||
* Set the version to 'hg-tip' if everything fails
|
||||
#311: Add missing 'explicit' keywords
|
||||
#302: Fix the implementation and doc of CrossRefMap
|
||||
#308: Remove duplicate list_graph.h entry from source list
|
||||
#307: Bugfix in Preflow and Circulation
|
||||
#305: Bugfix and extension in the rename script
|
||||
#312: Also check ReferenceMapTag in concept checks
|
||||
#250: Bugfix in pathSource() and pathTarget()
|
||||
#321: Use pathCopy(from,to) instead of copyPath(to,from)
|
||||
#322: Distribure LEMONConfig.cmake.in
|
||||
#330: Bug fix in map_extender.h
|
||||
#336: Fix the date field comment of graphToEps() output
|
||||
#323: Bug fix in Suurballe
|
||||
#335: Fix clear() function in ExtendFindEnum
|
||||
#337: Use void* as the LPX object pointer
|
||||
#317: Fix (and improve) error message in mip_test.cc
|
||||
Remove unnecessary OsiCbc dependency
|
||||
#356: Allow multiple executions of weighted matching algorithms (#356)
|
||||
|
||||
2009-05-13 Version 1.1 released
|
||||
|
||||
This is the second stable release of the 1.x series. It
|
||||
features a better coverage of the tools available in the 0.x
|
||||
series, a thoroughly reworked LP/MIP interface plus various
|
||||
improvements in the existing tools.
|
||||
|
||||
* Much improved M$ Windows support
|
||||
* Various improvements in the CMAKE build system
|
||||
* Compilation warnings are fixed/suppressed
|
||||
* Support IBM xlC compiler
|
||||
* New algorithms
|
||||
* Connectivity related algorithms (#61)
|
||||
* Euler walks (#65)
|
||||
* Preflow push-relabel max. flow algorithm (#176)
|
||||
* Circulation algorithm (push-relabel based) (#175)
|
||||
* Suurballe algorithm (#47)
|
||||
* Gomory-Hu algorithm (#66)
|
||||
* Hao-Orlin algorithm (#58)
|
||||
* Edmond's maximum cardinality and weighted matching algorithms
|
||||
in general graphs (#48,#265)
|
||||
* Minimum cost arborescence/branching (#60)
|
||||
* Network Simplex min. cost flow algorithm (#234)
|
||||
* New data structures
|
||||
* Full graph structure (#57)
|
||||
* Grid graph structure (#57)
|
||||
* Hypercube graph structure (#57)
|
||||
* Graph adaptors (#67)
|
||||
* ArcSet and EdgeSet classes (#67)
|
||||
* Elevator class (#174)
|
||||
* Other new tools
|
||||
* LP/MIP interface (#44)
|
||||
* Support for GLPK, CPLEX, Soplex, COIN-OR CLP and CBC
|
||||
* Reader for the Nauty file format (#55)
|
||||
* DIMACS readers (#167)
|
||||
* Radix sort algorithms (#72)
|
||||
* RangeIdMap and CrossRefMap (#160)
|
||||
* New command line tools
|
||||
* DIMACS to LGF converter (#182)
|
||||
* lgf-gen - a graph generator (#45)
|
||||
* DIMACS solver utility (#226)
|
||||
* Other code improvements
|
||||
* Lognormal distribution added to Random (#102)
|
||||
* Better (i.e. O(1) time) item counting in SmartGraph (#3)
|
||||
* The standard maps of graphs are guaranteed to be
|
||||
reference maps (#190)
|
||||
* Miscellaneous
|
||||
* Various doc improvements
|
||||
* Improved 0.x -> 1.x converter script
|
||||
|
||||
* Several bugfixes (compared to release 1.0):
|
||||
#170: Bugfix SmartDigraph::split()
|
||||
#171: Bugfix in SmartGraph::restoreSnapshot()
|
||||
#172: Extended test cases for graphs and digraphs
|
||||
#173: Bugfix in Random
|
||||
* operator()s always return a double now
|
||||
* the faulty real<Num>(Num) and real<Num>(Num,Num)
|
||||
have been removed
|
||||
#187: Remove DijkstraWidestPathOperationTraits
|
||||
#61: Bugfix in DfsVisit
|
||||
#193: Bugfix in GraphReader::skipSection()
|
||||
#195: Bugfix in ConEdgeIt()
|
||||
#197: Bugfix in heap unionfind
|
||||
* This bug affects Edmond's general matching algorithms
|
||||
#207: Fix 'make install' without 'make html' using CMAKE
|
||||
#208: Suppress or fix VS2008 compilation warnings
|
||||
----: Update the LEMON icon
|
||||
----: Enable the component-based installer
|
||||
(in installers made by CPACK)
|
||||
----: Set the proper version for CMAKE in the tarballs
|
||||
(made by autotools)
|
||||
----: Minor clarification in the LICENSE file
|
||||
----: Add missing unistd.h include to time_measure.h
|
||||
#204: Compilation bug fixed in graph_to_eps.h with VS2005
|
||||
#214,#215: windows.h should never be included by LEMON headers
|
||||
#230: Build systems check the availability of 'long long' type
|
||||
#229: Default implementation of Tolerance<> is used for integer types
|
||||
#211,#212: Various fixes for compiling on AIX
|
||||
----: Improvements in CMAKE config
|
||||
- docs is installed in share/doc/
|
||||
- detects newer versions of Ghostscript
|
||||
#239: Fix missing 'inline' specifier in time_measure.h
|
||||
#274,#280: Install lemon/config.h
|
||||
#275: Prefix macro names with LEMON_ in lemon/config.h
|
||||
----: Small script for making the release tarballs added
|
||||
----: Minor improvement in unify-sources.sh (a76f55d7d397)
|
||||
|
||||
2009-03-27 LEMON joins to the COIN-OR initiative
|
||||
|
||||
COIN-OR (Computational Infrastructure for Operations Research,
|
||||
http://www.coin-or.org) project is an initiative to spur the
|
||||
development of open-source software for the operations research
|
||||
community.
|
||||
|
||||
2008-10-13 Version 1.0 released
|
||||
|
||||
This is the first stable release of LEMON. Compared to the 0.x
|
||||
release series, it features a considerably smaller but more
|
||||
matured set of tools. The API has also completely revised and
|
||||
changed in several places.
|
||||
|
||||
* The major name changes compared to the 0.x series (see the
|
||||
Migration Guide in the doc for more details)
|
||||
* Graph -> Digraph, UGraph -> Graph
|
||||
* Edge -> Arc, UEdge -> Edge
|
||||
* source(UEdge)/target(UEdge) -> u(Edge)/v(Edge)
|
||||
* Other improvements
|
||||
* Better documentation
|
||||
* Reviewed and cleaned up codebase
|
||||
* CMake based build system (along with the autotools based one)
|
||||
* Contents of the library (ported from 0.x)
|
||||
* Algorithms
|
||||
* breadth-first search (bfs.h)
|
||||
* depth-first search (dfs.h)
|
||||
* Dijkstra's algorithm (dijkstra.h)
|
||||
* Kruskal's algorithm (kruskal.h)
|
||||
* Data structures
|
||||
* graph data structures (list_graph.h, smart_graph.h)
|
||||
* path data structures (path.h)
|
||||
* binary heap data structure (bin_heap.h)
|
||||
* union-find data structures (unionfind.h)
|
||||
* miscellaneous property maps (maps.h)
|
||||
* two dimensional vector and bounding box (dim2.h)
|
||||
* Concepts
|
||||
* graph structure concepts (concepts/digraph.h, concepts/graph.h,
|
||||
concepts/graph_components.h)
|
||||
* concepts for other structures (concepts/heap.h, concepts/maps.h,
|
||||
concepts/path.h)
|
||||
* Tools
|
||||
* Mersenne twister random number generator (random.h)
|
||||
* tools for measuring cpu and wall clock time (time_measure.h)
|
||||
* tools for counting steps and events (counter.h)
|
||||
* tool for parsing command line arguments (arg_parser.h)
|
||||
* tool for visualizing graphs (graph_to_eps.h)
|
||||
* tools for reading and writing data in LEMON Graph Format
|
||||
(lgf_reader.h, lgf_writer.h)
|
||||
* tools to handle the anomalies of calculations with
|
||||
floating point numbers (tolerance.h)
|
||||
* tools to manage RGB colors (color.h)
|
||||
* Infrastructure
|
||||
* extended assertion handling (assert.h)
|
||||
* exception classes and error handling (error.h)
|
||||
* concept checking (concept_check.h)
|
||||
* commonly used mathematical constants (math.h)
|
|
@ -0,0 +1,50 @@
|
|||
=====================================================================
|
||||
LEMON - a Library for Efficient Modeling and Optimization in Networks
|
||||
=====================================================================
|
||||
|
||||
LEMON is an open source library written in C++. It provides
|
||||
easy-to-use implementations of common data structures and algorithms
|
||||
in the area of optimization and helps implementing new ones. The main
|
||||
focus is on graphs and graph algorithms, thus it is especially
|
||||
suitable for solving design and optimization problems of
|
||||
telecommunication networks. To achieve wide usability its data
|
||||
structures and algorithms provide generic interfaces.
|
||||
|
||||
Contents
|
||||
========
|
||||
|
||||
LICENSE
|
||||
|
||||
Copying, distribution and modification conditions and terms.
|
||||
|
||||
NEWS
|
||||
|
||||
News and version history.
|
||||
|
||||
INSTALL
|
||||
|
||||
General building and installation instructions.
|
||||
|
||||
lemon/
|
||||
|
||||
Source code of LEMON library.
|
||||
|
||||
doc/
|
||||
|
||||
Documentation of LEMON. The starting page is doc/html/index.html.
|
||||
|
||||
demo/
|
||||
|
||||
Some example programs to make you easier to get familiar with LEMON.
|
||||
|
||||
scripts/
|
||||
|
||||
Scripts that make it easier to develop LEMON.
|
||||
|
||||
test/
|
||||
|
||||
Programs to check the integrity and correctness of LEMON.
|
||||
|
||||
tools/
|
||||
|
||||
Various utilities related to LEMON.
|
|
@ -0,0 +1,110 @@
|
|||
SET(COIN_ROOT_DIR "" CACHE PATH "COIN root directory")
|
||||
|
||||
FIND_PATH(COIN_INCLUDE_DIR coin/CoinUtilsConfig.h
|
||||
HINTS ${COIN_ROOT_DIR}/include
|
||||
)
|
||||
FIND_LIBRARY(COIN_CBC_LIBRARY
|
||||
NAMES Cbc libCbc
|
||||
HINTS ${COIN_ROOT_DIR}/lib/coin
|
||||
HINTS ${COIN_ROOT_DIR}/lib
|
||||
)
|
||||
FIND_LIBRARY(COIN_CBC_SOLVER_LIBRARY
|
||||
NAMES CbcSolver libCbcSolver
|
||||
HINTS ${COIN_ROOT_DIR}/lib/coin
|
||||
HINTS ${COIN_ROOT_DIR}/lib
|
||||
)
|
||||
FIND_LIBRARY(COIN_CGL_LIBRARY
|
||||
NAMES Cgl libCgl
|
||||
HINTS ${COIN_ROOT_DIR}/lib/coin
|
||||
HINTS ${COIN_ROOT_DIR}/lib
|
||||
)
|
||||
FIND_LIBRARY(COIN_CLP_LIBRARY
|
||||
NAMES Clp libClp
|
||||
HINTS ${COIN_ROOT_DIR}/lib/coin
|
||||
HINTS ${COIN_ROOT_DIR}/lib
|
||||
)
|
||||
FIND_LIBRARY(COIN_COIN_UTILS_LIBRARY
|
||||
NAMES CoinUtils libCoinUtils
|
||||
HINTS ${COIN_ROOT_DIR}/lib/coin
|
||||
HINTS ${COIN_ROOT_DIR}/lib
|
||||
)
|
||||
FIND_LIBRARY(COIN_OSI_LIBRARY
|
||||
NAMES Osi libOsi
|
||||
HINTS ${COIN_ROOT_DIR}/lib/coin
|
||||
HINTS ${COIN_ROOT_DIR}/lib
|
||||
)
|
||||
FIND_LIBRARY(COIN_OSI_CBC_LIBRARY
|
||||
NAMES OsiCbc libOsiCbc
|
||||
HINTS ${COIN_ROOT_DIR}/lib/coin
|
||||
HINTS ${COIN_ROOT_DIR}/lib
|
||||
)
|
||||
FIND_LIBRARY(COIN_OSI_CLP_LIBRARY
|
||||
NAMES OsiClp libOsiClp
|
||||
HINTS ${COIN_ROOT_DIR}/lib/coin
|
||||
HINTS ${COIN_ROOT_DIR}/lib
|
||||
)
|
||||
FIND_LIBRARY(COIN_OSI_VOL_LIBRARY
|
||||
NAMES OsiVol libOsiVol
|
||||
HINTS ${COIN_ROOT_DIR}/lib/coin
|
||||
HINTS ${COIN_ROOT_DIR}/lib
|
||||
)
|
||||
FIND_LIBRARY(COIN_VOL_LIBRARY
|
||||
NAMES Vol libVol
|
||||
HINTS ${COIN_ROOT_DIR}/lib/coin
|
||||
HINTS ${COIN_ROOT_DIR}/lib
|
||||
)
|
||||
|
||||
FIND_LIBRARY(COIN_ZLIB_LIBRARY
|
||||
NAMES z libz
|
||||
HINTS ${COIN_ROOT_DIR}/lib/coin
|
||||
HINTS ${COIN_ROOT_DIR}/lib
|
||||
)
|
||||
FIND_LIBRARY(COIN_BZ2_LIBRARY
|
||||
NAMES bz2 libbz2
|
||||
HINTS ${COIN_ROOT_DIR}/lib/coin
|
||||
HINTS ${COIN_ROOT_DIR}/lib
|
||||
)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(COIN DEFAULT_MSG
|
||||
COIN_INCLUDE_DIR
|
||||
COIN_CBC_LIBRARY
|
||||
COIN_CBC_SOLVER_LIBRARY
|
||||
COIN_CGL_LIBRARY
|
||||
COIN_CLP_LIBRARY
|
||||
COIN_COIN_UTILS_LIBRARY
|
||||
COIN_OSI_LIBRARY
|
||||
COIN_OSI_CBC_LIBRARY
|
||||
COIN_OSI_CLP_LIBRARY
|
||||
# COIN_OSI_VOL_LIBRARY
|
||||
# COIN_VOL_LIBRARY
|
||||
)
|
||||
|
||||
IF(COIN_FOUND)
|
||||
SET(COIN_INCLUDE_DIRS ${COIN_INCLUDE_DIR})
|
||||
SET(COIN_CLP_LIBRARIES "${COIN_CLP_LIBRARY};${COIN_COIN_UTILS_LIBRARY};${COIN_ZLIB_LIBRARY};${COIN_BZ2_LIBRARY}")
|
||||
IF(COIN_ZLIB_LIBRARY)
|
||||
SET(COIN_CLP_LIBRARIES "${COIN_CLP_LIBRARIES};${COIN_ZLIB_LIBRARY}")
|
||||
ENDIF(COIN_ZLIB_LIBRARY)
|
||||
IF(COIN_BZ2_LIBRARY)
|
||||
SET(COIN_CLP_LIBRARIES "${COIN_CLP_LIBRARIES};${COIN_BZ2_LIBRARY}")
|
||||
ENDIF(COIN_BZ2_LIBRARY)
|
||||
SET(COIN_CBC_LIBRARIES "${COIN_CBC_LIBRARY};${COIN_CBC_SOLVER_LIBRARY};${COIN_CGL_LIBRARY};${COIN_OSI_LIBRARY};${COIN_OSI_CBC_LIBRARY};${COIN_OSI_CLP_LIBRARY};${COIN_ZLIB_LIBRARY};${COIN_BZ2_LIBRARY};${COIN_CLP_LIBRARIES}")
|
||||
SET(COIN_LIBRARIES ${COIN_CBC_LIBRARIES})
|
||||
ENDIF(COIN_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
COIN_INCLUDE_DIR
|
||||
COIN_CBC_LIBRARY
|
||||
COIN_CBC_SOLVER_LIBRARY
|
||||
COIN_CGL_LIBRARY
|
||||
COIN_CLP_LIBRARY
|
||||
COIN_COIN_UTILS_LIBRARY
|
||||
COIN_OSI_LIBRARY
|
||||
COIN_OSI_CBC_LIBRARY
|
||||
COIN_OSI_CLP_LIBRARY
|
||||
COIN_OSI_VOL_LIBRARY
|
||||
COIN_VOL_LIBRARY
|
||||
COIN_ZLIB_LIBRARY
|
||||
COIN_BZ2_LIBRARY
|
||||
)
|
|
@ -0,0 +1,55 @@
|
|||
SET(GLPK_ROOT_DIR "" CACHE PATH "GLPK root directory")
|
||||
|
||||
SET(GLPK_REGKEY "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\Glpk;InstallPath]")
|
||||
GET_FILENAME_COMPONENT(GLPK_ROOT_PATH ${GLPK_REGKEY} ABSOLUTE)
|
||||
|
||||
FIND_PATH(GLPK_INCLUDE_DIR
|
||||
glpk.h
|
||||
PATHS ${GLPK_REGKEY}/include
|
||||
HINTS ${GLPK_ROOT_DIR}/include
|
||||
)
|
||||
FIND_LIBRARY(GLPK_LIBRARY
|
||||
glpk
|
||||
PATHS ${GLPK_REGKEY}/lib
|
||||
HINTS ${GLPK_ROOT_DIR}/lib
|
||||
)
|
||||
|
||||
IF(GLPK_INCLUDE_DIR AND GLPK_LIBRARY)
|
||||
FILE(READ ${GLPK_INCLUDE_DIR}/glpk.h GLPK_GLPK_H)
|
||||
|
||||
STRING(REGEX MATCH "define[ ]+GLP_MAJOR_VERSION[ ]+[0-9]+" GLPK_MAJOR_VERSION_LINE "${GLPK_GLPK_H}")
|
||||
STRING(REGEX REPLACE "define[ ]+GLP_MAJOR_VERSION[ ]+([0-9]+)" "\\1" GLPK_VERSION_MAJOR "${GLPK_MAJOR_VERSION_LINE}")
|
||||
|
||||
STRING(REGEX MATCH "define[ ]+GLP_MINOR_VERSION[ ]+[0-9]+" GLPK_MINOR_VERSION_LINE "${GLPK_GLPK_H}")
|
||||
STRING(REGEX REPLACE "define[ ]+GLP_MINOR_VERSION[ ]+([0-9]+)" "\\1" GLPK_VERSION_MINOR "${GLPK_MINOR_VERSION_LINE}")
|
||||
|
||||
SET(GLPK_VERSION_STRING "${GLPK_VERSION_MAJOR}.${GLPK_VERSION_MINOR}")
|
||||
|
||||
IF(GLPK_FIND_VERSION)
|
||||
IF(GLPK_FIND_VERSION_COUNT GREATER 2)
|
||||
MESSAGE(SEND_ERROR "unexpected version string")
|
||||
ENDIF(GLPK_FIND_VERSION_COUNT GREATER 2)
|
||||
|
||||
MATH(EXPR GLPK_REQUESTED_VERSION "${GLPK_FIND_VERSION_MAJOR}*100 + ${GLPK_FIND_VERSION_MINOR}")
|
||||
MATH(EXPR GLPK_FOUND_VERSION "${GLPK_VERSION_MAJOR}*100 + ${GLPK_VERSION_MINOR}")
|
||||
|
||||
IF(GLPK_FOUND_VERSION LESS GLPK_REQUESTED_VERSION)
|
||||
SET(GLPK_PROPER_VERSION_FOUND FALSE)
|
||||
ELSE(GLPK_FOUND_VERSION LESS GLPK_REQUESTED_VERSION)
|
||||
SET(GLPK_PROPER_VERSION_FOUND TRUE)
|
||||
ENDIF(GLPK_FOUND_VERSION LESS GLPK_REQUESTED_VERSION)
|
||||
ELSE(GLPK_FIND_VERSION)
|
||||
SET(GLPK_PROPER_VERSION_FOUND TRUE)
|
||||
ENDIF(GLPK_FIND_VERSION)
|
||||
ENDIF(GLPK_INCLUDE_DIR AND GLPK_LIBRARY)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLPK DEFAULT_MSG GLPK_LIBRARY GLPK_INCLUDE_DIR GLPK_PROPER_VERSION_FOUND)
|
||||
|
||||
IF(GLPK_FOUND)
|
||||
SET(GLPK_INCLUDE_DIRS ${GLPK_INCLUDE_DIR})
|
||||
SET(GLPK_LIBRARIES ${GLPK_LIBRARY})
|
||||
SET(GLPK_BIN_DIR ${GLPK_ROOT_PATH}/bin)
|
||||
ENDIF(GLPK_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(GLPK_LIBRARY GLPK_INCLUDE_DIR GLPK_BIN_DIR)
|
|
@ -0,0 +1,10 @@
|
|||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
|
||||
FIND_PROGRAM(GHOSTSCRIPT_EXECUTABLE
|
||||
NAMES gs gswin32c
|
||||
PATHS "$ENV{ProgramFiles}/gs"
|
||||
PATH_SUFFIXES gs8.61/bin gs8.62/bin gs8.63/bin gs8.64/bin gs8.65/bin
|
||||
DOC "Ghostscript: PostScript and PDF language interpreter and previewer."
|
||||
)
|
||||
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Ghostscript DEFAULT_MSG GHOSTSCRIPT_EXECUTABLE)
|
|
@ -0,0 +1,102 @@
|
|||
FIND_PATH(ILOG_ROOT_DIR
|
||||
NAMES cplex
|
||||
DOC "CPLEX STUDIO root directory"
|
||||
PATHS /opt/ibm/ILOG /usr/local/ibm/ILOG /usr/local/ILOG /usr/local/ilog
|
||||
PATHS "$ENV{HOME}/ILOG" "$ENV{HOME}/.local/ILOG"
|
||||
PATHS "$ENV{HOME}/ibm/ILOG" "$ENV{HOME}/.local/ibm/ILOG"
|
||||
PATHS "C:/Program Files/IBM/ILOG"
|
||||
PATH_SUFFIXES "CPLEX_Studio126" "CPLEX_Studio125"
|
||||
"CPLEX_Studio124" "CPLEX_Studio123" "CPLEX_Studio122"
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
IF(WIN32)
|
||||
IF(MSVC_VERSION STREQUAL "1400")
|
||||
SET(ILOG_WIN_COMPILER "windows_vs2005")
|
||||
ELSEIF(MSVC_VERSION STREQUAL "1500")
|
||||
SET(ILOG_WIN_COMPILER "windows_vs2008")
|
||||
ELSEIF(MSVC_VERSION STREQUAL "1600")
|
||||
SET(ILOG_WIN_COMPILER "windows_vs2010")
|
||||
ELSE()
|
||||
SET(ILOG_WIN_COMPILER "windows_vs2008")
|
||||
ENDIF()
|
||||
IF(CMAKE_CL_64)
|
||||
SET(ILOG_WIN_COMPILER "x64_${ILOG_WIN_COMPILER}")
|
||||
SET(ILOG_WIN_PLATFORM "x64_win32")
|
||||
ELSE()
|
||||
SET(ILOG_WIN_COMPILER "x86_${ILOG_WIN_COMPILER}")
|
||||
SET(ILOG_WIN_PLATFORM "x86_win32")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
FIND_PATH(ILOG_CPLEX_ROOT_DIR
|
||||
NAMES include/ilcplex
|
||||
HINTS ${ILOG_ROOT_DIR}/cplex ${ILOG_ROOT_DIR}/cplex121
|
||||
${ILOG_ROOT_DIR}/cplex122 ${ILOG_ROOT_DIR}/cplex123
|
||||
DOC "CPLEX root directory"
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
FIND_PATH(ILOG_CONCERT_ROOT_DIR
|
||||
NAMES include/ilconcert
|
||||
HINTS ${ILOG_ROOT_DIR}/concert ${ILOG_ROOT_DIR}/concert29
|
||||
DOC "CONCERT root directory"
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
FIND_PATH(ILOG_CPLEX_INCLUDE_DIR
|
||||
ilcplex/cplex.h
|
||||
HINTS ${ILOG_CPLEX_ROOT_DIR}/include
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
FIND_PATH(ILOG_CONCERT_INCLUDE_DIR
|
||||
ilconcert/ilobasic.h
|
||||
HINTS ${ILOG_CONCERT_ROOT_DIR}/include
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
FIND_LIBRARY(ILOG_CPLEX_LIBRARY
|
||||
cplex cplex121 cplex122 cplex123 cplex124
|
||||
HINTS ${ILOG_CPLEX_ROOT_DIR}/lib/x86_sles10_4.1/static_pic
|
||||
${ILOG_CPLEX_ROOT_DIR}/lib/x86-64_sles10_4.1/static_pic
|
||||
${ILOG_CPLEX_ROOT_DIR}/lib/x86_debian4.0_4.1/static_pic
|
||||
${ILOG_CPLEX_ROOT_DIR}/lib/x86-64_debian4.0_4.1/static_pic
|
||||
${ILOG_CPLEX_ROOT_DIR}/lib/${ILOG_WIN_COMPILER}/stat_mda
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
FIND_LIBRARY(ILOG_CONCERT_LIBRARY
|
||||
concert
|
||||
HINTS ${ILOG_CONCERT_ROOT_DIR}/lib/x86_sles10_4.1/static_pic
|
||||
${ILOG_CONCERT_ROOT_DIR}/lib/x86-64_sles10_4.1/static_pic
|
||||
${ILOG_CONCERT_ROOT_DIR}/lib/x86_debian4.0_4.1/static_pic
|
||||
${ILOG_CONCERT_ROOT_DIR}/lib/x86-64_debian4.0_4.1/static_pic
|
||||
${ILOG_CONCERT_ROOT_DIR}/lib/${ILOG_WIN_COMPILER}/stat_mda
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
FIND_FILE(ILOG_CPLEX_DLL
|
||||
cplex121.dll cplex122.dll cplex123.dll cplex124.dll
|
||||
HINTS ${ILOG_CPLEX_ROOT_DIR}/bin/${ILOG_WIN_PLATFORM}
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(ILOG
|
||||
DEFAULT_MSG ILOG_CPLEX_LIBRARY ILOG_CPLEX_INCLUDE_DIR
|
||||
)
|
||||
|
||||
IF(ILOG_FOUND)
|
||||
SET(ILOG_INCLUDE_DIRS ${ILOG_CPLEX_INCLUDE_DIR} ${ILOG_CONCERT_INCLUDE_DIR})
|
||||
SET(ILOG_LIBRARIES ${ILOG_CPLEX_LIBRARY} ${ILOG_CONCERT_LIBRARY})
|
||||
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
# SET(CPLEX_LIBRARIES "${CPLEX_LIBRARIES};m;pthread")
|
||||
SET(ILOG_LIBRARIES ${ILOG_LIBRARIES} "m" "pthread")
|
||||
ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
ENDIF(ILOG_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
ILOG_CPLEX_LIBRARY ILOG_CPLEX_INCLUDE_DIR ILOG_CPLEX_DLL
|
||||
ILOG_CONCERT_LIBRARY ILOG_CONCERT_INCLUDE_DIR ILOG_CONCERT_DLL
|
||||
)
|
|
@ -0,0 +1,23 @@
|
|||
SET(SOPLEX_ROOT_DIR "" CACHE PATH "SoPlex root directory")
|
||||
|
||||
FIND_PATH(SOPLEX_INCLUDE_DIR
|
||||
soplex.h
|
||||
HINTS ${SOPLEX_ROOT_DIR}/src
|
||||
)
|
||||
FIND_LIBRARY(SOPLEX_LIBRARY
|
||||
soplex
|
||||
HINTS ${SOPLEX_ROOT_DIR}/lib
|
||||
)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SOPLEX DEFAULT_MSG SOPLEX_LIBRARY SOPLEX_INCLUDE_DIR)
|
||||
|
||||
IF(SOPLEX_FOUND)
|
||||
SET(SOPLEX_INCLUDE_DIRS ${SOPLEX_INCLUDE_DIR})
|
||||
SET(SOPLEX_LIBRARIES ${SOPLEX_LIBRARY})
|
||||
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
SET(SOPLEX_LIBRARIES "${SOPLEX_LIBRARIES};z")
|
||||
ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
ENDIF(SOPLEX_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(SOPLEX_LIBRARY SOPLEX_INCLUDE_DIR)
|
|
@ -0,0 +1,13 @@
|
|||
SET(LEMON_INCLUDE_DIR "@CMAKE_INSTALL_PREFIX@/include" CACHE PATH "LEMON include directory")
|
||||
SET(LEMON_INCLUDE_DIRS "${LEMON_INCLUDE_DIR}")
|
||||
|
||||
IF(UNIX)
|
||||
SET(LEMON_LIB_NAME "libemon.a")
|
||||
ELSEIF(WIN32)
|
||||
SET(LEMON_LIB_NAME "lemon.lib")
|
||||
ENDIF(UNIX)
|
||||
|
||||
SET(LEMON_LIBRARY "@CMAKE_INSTALL_PREFIX@/lib/${LEMON_LIB_NAME}" CACHE FILEPATH "LEMON library")
|
||||
SET(LEMON_LIBRARIES "${LEMON_LIBRARY}")
|
||||
|
||||
MARK_AS_ADVANCED(LEMON_LIBRARY LEMON_INCLUDE_DIR)
|
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
|
@ -0,0 +1 @@
|
|||
SET(LEMON_VERSION "1.3.1" CACHE STRING "LEMON version string.")
|
|
@ -0,0 +1 @@
|
|||
SET(LEMON_VERSION "@LEMON_VERSION@" CACHE STRING "LEMON version string.")
|
|
@ -0,0 +1,19 @@
|
|||
INCLUDE_DIRECTORIES(
|
||||
${PROJECT_SOURCE_DIR}
|
||||
${PROJECT_BINARY_DIR}
|
||||
)
|
||||
|
||||
LINK_DIRECTORIES(
|
||||
${PROJECT_BINARY_DIR}/lemon
|
||||
)
|
||||
|
||||
# Uncomment (and adjust) the following two lines. 'myprog' is the name
|
||||
# of the final executable ('.exe' will automatically be added to the
|
||||
# name on Windows) and 'myprog-main.cc' is the source code it is
|
||||
# compiled from. You can add more source files separated by
|
||||
# whitespaces. Moreover, you can add multiple similar blocks if you
|
||||
# want to build more than one executables.
|
||||
|
||||
# ADD_EXECUTABLE(myprog myprog-main.cc)
|
||||
# TARGET_LINK_LIBRARIES(myprog lemon)
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
INCLUDE_DIRECTORIES(
|
||||
${PROJECT_SOURCE_DIR}
|
||||
${PROJECT_BINARY_DIR}
|
||||
)
|
||||
|
||||
LINK_DIRECTORIES(
|
||||
${PROJECT_BINARY_DIR}/lemon
|
||||
)
|
||||
|
||||
SET(DEMOS
|
||||
arg_parser_demo
|
||||
graph_to_eps_demo
|
||||
lgf_demo
|
||||
)
|
||||
|
||||
FOREACH(DEMO_NAME ${DEMOS})
|
||||
ADD_EXECUTABLE(${DEMO_NAME} ${DEMO_NAME}.cc)
|
||||
TARGET_LINK_LIBRARIES(${DEMO_NAME} lemon)
|
||||
ENDFOREACH()
|
|
@ -0,0 +1,112 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2010
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
///\ingroup demos
|
||||
///\file
|
||||
///\brief Argument parser demo
|
||||
///
|
||||
/// This example shows how the argument parser can be used.
|
||||
///
|
||||
/// \include arg_parser_demo.cc
|
||||
|
||||
#include <lemon/arg_parser.h>
|
||||
|
||||
using namespace lemon;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// Initialize the argument parser
|
||||
ArgParser ap(argc, argv);
|
||||
int i;
|
||||
std::string s;
|
||||
double d = 1.0;
|
||||
bool b, nh;
|
||||
bool g1, g2, g3;
|
||||
|
||||
// Add a mandatory integer option with storage reference
|
||||
ap.refOption("n", "An integer input.", i, true);
|
||||
// Add a double option with storage reference (the default value is 1.0)
|
||||
ap.refOption("val", "A double input.", d);
|
||||
// Add a double option without storage reference (the default value is 3.14)
|
||||
ap.doubleOption("val2", "A double input.", 3.14);
|
||||
// Set synonym for -val option
|
||||
ap.synonym("vals", "val");
|
||||
// Add a string option
|
||||
ap.refOption("name", "A string input.", s);
|
||||
// Add bool options
|
||||
ap.refOption("f", "A switch.", b)
|
||||
.refOption("nohelp", "", nh)
|
||||
.refOption("gra", "Choice A", g1)
|
||||
.refOption("grb", "Choice B", g2)
|
||||
.refOption("grc", "Choice C", g3);
|
||||
// Bundle -gr* options into a group
|
||||
ap.optionGroup("gr", "gra")
|
||||
.optionGroup("gr", "grb")
|
||||
.optionGroup("gr", "grc");
|
||||
// Set the group mandatory
|
||||
ap.mandatoryGroup("gr");
|
||||
// Set the options of the group exclusive (only one option can be given)
|
||||
ap.onlyOneGroup("gr");
|
||||
// Add non-parsed arguments (e.g. input files)
|
||||
ap.other("infile", "The input file.")
|
||||
.other("...");
|
||||
|
||||
// Throw an exception when problems occurs. The default behavior is to
|
||||
// exit(1) on these cases, but this makes Valgrind falsely warn
|
||||
// about memory leaks.
|
||||
ap.throwOnProblems();
|
||||
|
||||
// Perform the parsing process
|
||||
// (in case of any error it terminates the program)
|
||||
// The try {} construct is necessary only if the ap.trowOnProblems()
|
||||
// setting is in use.
|
||||
try {
|
||||
ap.parse();
|
||||
} catch (ArgParserException &) { return 1; }
|
||||
|
||||
// Check each option if it has been given and print its value
|
||||
std::cout << "Parameters of '" << ap.commandName() << "':\n";
|
||||
|
||||
std::cout << " Value of -n: " << i << std::endl;
|
||||
if(ap.given("val")) std::cout << " Value of -val: " << d << std::endl;
|
||||
if(ap.given("val2")) {
|
||||
d = ap["val2"];
|
||||
std::cout << " Value of -val2: " << d << std::endl;
|
||||
}
|
||||
if(ap.given("name")) std::cout << " Value of -name: " << s << std::endl;
|
||||
if(ap.given("f")) std::cout << " -f is given\n";
|
||||
if(ap.given("nohelp")) std::cout << " Value of -nohelp: " << nh << std::endl;
|
||||
if(ap.given("gra")) std::cout << " -gra is given\n";
|
||||
if(ap.given("grb")) std::cout << " -grb is given\n";
|
||||
if(ap.given("grc")) std::cout << " -grc is given\n";
|
||||
|
||||
switch(ap.files().size()) {
|
||||
case 0:
|
||||
std::cout << " No file argument was given.\n";
|
||||
break;
|
||||
case 1:
|
||||
std::cout << " 1 file argument was given. It is:\n";
|
||||
break;
|
||||
default:
|
||||
std::cout << " "
|
||||
<< ap.files().size() << " file arguments were given. They are:\n";
|
||||
}
|
||||
for(unsigned int i=0;i<ap.files().size();++i)
|
||||
std::cout << " '" << ap.files()[i] << "'\n";
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
@nodes
|
||||
label
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
@arcs
|
||||
label capacity
|
||||
0 1 0 16
|
||||
0 2 1 12
|
||||
0 3 2 20
|
||||
1 2 3 10
|
||||
1 4 4 10
|
||||
1 5 5 13
|
||||
2 3 6 10
|
||||
2 4 7 8
|
||||
2 6 8 8
|
||||
5 3 9 20
|
||||
3 6 10 25
|
||||
4 7 11 15
|
||||
5 7 12 15
|
||||
6 7 13 18
|
||||
@attributes
|
||||
source 0
|
||||
target 7
|
|
@ -0,0 +1,206 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2009
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
/// \ingroup demos
|
||||
/// \file
|
||||
/// \brief Demo of the graph drawing function \ref graphToEps()
|
||||
///
|
||||
/// This demo program shows examples how to use the function \ref
|
||||
/// graphToEps(). It takes no input but simply creates seven
|
||||
/// <tt>.eps</tt> files demonstrating the capability of \ref
|
||||
/// graphToEps(), and showing how to draw directed graphs,
|
||||
/// how to handle parallel egdes, how to change the properties (like
|
||||
/// color, shape, size, title etc.) of nodes and arcs individually
|
||||
/// using appropriate graph maps.
|
||||
///
|
||||
/// \include graph_to_eps_demo.cc
|
||||
|
||||
#include<lemon/list_graph.h>
|
||||
#include<lemon/graph_to_eps.h>
|
||||
#include<lemon/math.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace lemon;
|
||||
|
||||
int main()
|
||||
{
|
||||
Palette palette;
|
||||
Palette paletteW(true);
|
||||
|
||||
// Create a small digraph
|
||||
ListDigraph g;
|
||||
typedef ListDigraph::Node Node;
|
||||
typedef ListDigraph::NodeIt NodeIt;
|
||||
typedef ListDigraph::Arc Arc;
|
||||
typedef dim2::Point<int> Point;
|
||||
|
||||
Node n1=g.addNode();
|
||||
Node n2=g.addNode();
|
||||
Node n3=g.addNode();
|
||||
Node n4=g.addNode();
|
||||
Node n5=g.addNode();
|
||||
|
||||
ListDigraph::NodeMap<Point> coords(g);
|
||||
ListDigraph::NodeMap<double> sizes(g);
|
||||
ListDigraph::NodeMap<int> colors(g);
|
||||
ListDigraph::NodeMap<int> shapes(g);
|
||||
ListDigraph::ArcMap<int> acolors(g);
|
||||
ListDigraph::ArcMap<int> widths(g);
|
||||
|
||||
coords[n1]=Point(50,50); sizes[n1]=1; colors[n1]=1; shapes[n1]=0;
|
||||
coords[n2]=Point(50,70); sizes[n2]=2; colors[n2]=2; shapes[n2]=2;
|
||||
coords[n3]=Point(70,70); sizes[n3]=1; colors[n3]=3; shapes[n3]=0;
|
||||
coords[n4]=Point(70,50); sizes[n4]=2; colors[n4]=4; shapes[n4]=1;
|
||||
coords[n5]=Point(85,60); sizes[n5]=3; colors[n5]=5; shapes[n5]=2;
|
||||
|
||||
Arc a;
|
||||
|
||||
a=g.addArc(n1,n2); acolors[a]=0; widths[a]=1;
|
||||
a=g.addArc(n2,n3); acolors[a]=0; widths[a]=1;
|
||||
a=g.addArc(n3,n5); acolors[a]=0; widths[a]=3;
|
||||
a=g.addArc(n5,n4); acolors[a]=0; widths[a]=1;
|
||||
a=g.addArc(n4,n1); acolors[a]=0; widths[a]=1;
|
||||
a=g.addArc(n2,n4); acolors[a]=1; widths[a]=2;
|
||||
a=g.addArc(n3,n4); acolors[a]=2; widths[a]=1;
|
||||
|
||||
IdMap<ListDigraph,Node> id(g);
|
||||
|
||||
// Create .eps files showing the digraph with different options
|
||||
cout << "Create 'graph_to_eps_demo_out_1_pure.eps'" << endl;
|
||||
graphToEps(g,"graph_to_eps_demo_out_1_pure.eps").
|
||||
coords(coords).
|
||||
title("Sample .eps figure").
|
||||
copyright("(C) 2003-2009 LEMON Project").
|
||||
run();
|
||||
|
||||
cout << "Create 'graph_to_eps_demo_out_2.eps'" << endl;
|
||||
graphToEps(g,"graph_to_eps_demo_out_2.eps").
|
||||
coords(coords).
|
||||
title("Sample .eps figure").
|
||||
copyright("(C) 2003-2009 LEMON Project").
|
||||
absoluteNodeSizes().absoluteArcWidths().
|
||||
nodeScale(2).nodeSizes(sizes).
|
||||
nodeShapes(shapes).
|
||||
nodeColors(composeMap(palette,colors)).
|
||||
arcColors(composeMap(palette,acolors)).
|
||||
arcWidthScale(.4).arcWidths(widths).
|
||||
nodeTexts(id).nodeTextSize(3).
|
||||
run();
|
||||
|
||||
cout << "Create 'graph_to_eps_demo_out_3_arr.eps'" << endl;
|
||||
graphToEps(g,"graph_to_eps_demo_out_3_arr.eps").
|
||||
title("Sample .eps figure (with arrowheads)").
|
||||
copyright("(C) 2003-2009 LEMON Project").
|
||||
absoluteNodeSizes().absoluteArcWidths().
|
||||
nodeColors(composeMap(palette,colors)).
|
||||
coords(coords).
|
||||
nodeScale(2).nodeSizes(sizes).
|
||||
nodeShapes(shapes).
|
||||
arcColors(composeMap(palette,acolors)).
|
||||
arcWidthScale(.4).arcWidths(widths).
|
||||
nodeTexts(id).nodeTextSize(3).
|
||||
drawArrows().arrowWidth(2).arrowLength(2).
|
||||
run();
|
||||
|
||||
// Add more arcs to the digraph
|
||||
a=g.addArc(n1,n4); acolors[a]=2; widths[a]=1;
|
||||
a=g.addArc(n4,n1); acolors[a]=1; widths[a]=2;
|
||||
|
||||
a=g.addArc(n1,n2); acolors[a]=1; widths[a]=1;
|
||||
a=g.addArc(n1,n2); acolors[a]=2; widths[a]=1;
|
||||
a=g.addArc(n1,n2); acolors[a]=3; widths[a]=1;
|
||||
a=g.addArc(n1,n2); acolors[a]=4; widths[a]=1;
|
||||
a=g.addArc(n1,n2); acolors[a]=5; widths[a]=1;
|
||||
a=g.addArc(n1,n2); acolors[a]=6; widths[a]=1;
|
||||
a=g.addArc(n1,n2); acolors[a]=7; widths[a]=1;
|
||||
|
||||
cout << "Create 'graph_to_eps_demo_out_4_par.eps'" << endl;
|
||||
graphToEps(g,"graph_to_eps_demo_out_4_par.eps").
|
||||
title("Sample .eps figure (parallel arcs)").
|
||||
copyright("(C) 2003-2009 LEMON Project").
|
||||
absoluteNodeSizes().absoluteArcWidths().
|
||||
nodeShapes(shapes).
|
||||
coords(coords).
|
||||
nodeScale(2).nodeSizes(sizes).
|
||||
nodeColors(composeMap(palette,colors)).
|
||||
arcColors(composeMap(palette,acolors)).
|
||||
arcWidthScale(.4).arcWidths(widths).
|
||||
nodeTexts(id).nodeTextSize(3).
|
||||
enableParallel().parArcDist(1.5).
|
||||
run();
|
||||
|
||||
cout << "Create 'graph_to_eps_demo_out_5_par_arr.eps'" << endl;
|
||||
graphToEps(g,"graph_to_eps_demo_out_5_par_arr.eps").
|
||||
title("Sample .eps figure (parallel arcs and arrowheads)").
|
||||
copyright("(C) 2003-2009 LEMON Project").
|
||||
absoluteNodeSizes().absoluteArcWidths().
|
||||
nodeScale(2).nodeSizes(sizes).
|
||||
coords(coords).
|
||||
nodeShapes(shapes).
|
||||
nodeColors(composeMap(palette,colors)).
|
||||
arcColors(composeMap(palette,acolors)).
|
||||
arcWidthScale(.3).arcWidths(widths).
|
||||
nodeTexts(id).nodeTextSize(3).
|
||||
enableParallel().parArcDist(1).
|
||||
drawArrows().arrowWidth(1).arrowLength(1).
|
||||
run();
|
||||
|
||||
cout << "Create 'graph_to_eps_demo_out_6_par_arr_a4.eps'" << endl;
|
||||
graphToEps(g,"graph_to_eps_demo_out_6_par_arr_a4.eps").
|
||||
title("Sample .eps figure (fits to A4)").
|
||||
copyright("(C) 2003-2009 LEMON Project").
|
||||
scaleToA4().
|
||||
absoluteNodeSizes().absoluteArcWidths().
|
||||
nodeScale(2).nodeSizes(sizes).
|
||||
coords(coords).
|
||||
nodeShapes(shapes).
|
||||
nodeColors(composeMap(palette,colors)).
|
||||
arcColors(composeMap(palette,acolors)).
|
||||
arcWidthScale(.3).arcWidths(widths).
|
||||
nodeTexts(id).nodeTextSize(3).
|
||||
enableParallel().parArcDist(1).
|
||||
drawArrows().arrowWidth(1).arrowLength(1).
|
||||
run();
|
||||
|
||||
// Create an .eps file showing the colors of a default Palette
|
||||
ListDigraph h;
|
||||
ListDigraph::NodeMap<int> hcolors(h);
|
||||
ListDigraph::NodeMap<Point> hcoords(h);
|
||||
|
||||
int cols=int(std::sqrt(double(palette.size())));
|
||||
for(int i=0;i<int(paletteW.size());i++) {
|
||||
Node n=h.addNode();
|
||||
hcoords[n]=Point(1+i%cols,1+i/cols);
|
||||
hcolors[n]=i;
|
||||
}
|
||||
|
||||
cout << "Create 'graph_to_eps_demo_out_7_colors.eps'" << endl;
|
||||
graphToEps(h,"graph_to_eps_demo_out_7_colors.eps").
|
||||
scale(60).
|
||||
title("Sample .eps figure (Palette demo)").
|
||||
copyright("(C) 2003-2009 LEMON Project").
|
||||
coords(hcoords).
|
||||
absoluteNodeSizes().absoluteArcWidths().
|
||||
nodeScale(.45).
|
||||
distantColorNodeTexts().
|
||||
nodeTexts(hcolors).nodeTextSize(.6).
|
||||
nodeColors(composeMap(paletteW,hcolors)).
|
||||
run();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2009
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
///\ingroup demos
|
||||
///\file
|
||||
///\brief Demonstrating graph input and output
|
||||
///
|
||||
/// This program gives an example of how to read and write a digraph
|
||||
/// and additional maps from/to a stream or a file using the
|
||||
/// \ref lgf-format "LGF" format.
|
||||
///
|
||||
/// The \c "digraph.lgf" file:
|
||||
/// \include digraph.lgf
|
||||
///
|
||||
/// And the program which reads it and prints the digraph to the
|
||||
/// standard output:
|
||||
/// \include lgf_demo.cc
|
||||
|
||||
#include <iostream>
|
||||
#include <lemon/smart_graph.h>
|
||||
#include <lemon/lgf_reader.h>
|
||||
#include <lemon/lgf_writer.h>
|
||||
|
||||
using namespace lemon;
|
||||
|
||||
int main() {
|
||||
SmartDigraph g;
|
||||
SmartDigraph::ArcMap<int> cap(g);
|
||||
SmartDigraph::Node s, t;
|
||||
|
||||
try {
|
||||
digraphReader(g, "digraph.lgf"). // read the directed graph into g
|
||||
arcMap("capacity", cap). // read the 'capacity' arc map into cap
|
||||
node("source", s). // read 'source' node to s
|
||||
node("target", t). // read 'target' node to t
|
||||
run();
|
||||
} catch (Exception& error) { // check if there was any error
|
||||
std::cerr << "Error: " << error.what() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout << "A digraph is read from 'digraph.lgf'." << std::endl;
|
||||
std::cout << "Number of nodes: " << countNodes(g) << std::endl;
|
||||
std::cout << "Number of arcs: " << countArcs(g) << std::endl;
|
||||
|
||||
std::cout << "We can write it to the standard output:" << std::endl;
|
||||
|
||||
digraphWriter(g). // write g to the standard output
|
||||
arcMap("capacity", cap). // write cap into 'capacity'
|
||||
node("source", s). // write s to 'source'
|
||||
node("target", t). // write t to 'target'
|
||||
run();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
INCLUDE_DIRECTORIES(
|
||||
${PROJECT_SOURCE_DIR}
|
||||
${PROJECT_BINARY_DIR}
|
||||
)
|
||||
|
||||
CONFIGURE_FILE(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/config.h
|
||||
)
|
||||
|
||||
CONFIGURE_FILE(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lemon.pc.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/lemon.pc
|
||||
@ONLY
|
||||
)
|
||||
|
||||
SET(LEMON_SOURCES
|
||||
arg_parser.cc
|
||||
base.cc
|
||||
color.cc
|
||||
lp_base.cc
|
||||
lp_skeleton.cc
|
||||
random.cc
|
||||
bits/windows.cc
|
||||
)
|
||||
|
||||
IF(LEMON_HAVE_GLPK)
|
||||
SET(LEMON_SOURCES ${LEMON_SOURCES} glpk.cc)
|
||||
INCLUDE_DIRECTORIES(${GLPK_INCLUDE_DIRS})
|
||||
IF(WIN32)
|
||||
INSTALL(FILES ${GLPK_BIN_DIR}/glpk.dll DESTINATION bin)
|
||||
INSTALL(FILES ${GLPK_BIN_DIR}/libltdl3.dll DESTINATION bin)
|
||||
INSTALL(FILES ${GLPK_BIN_DIR}/zlib1.dll DESTINATION bin)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF(LEMON_HAVE_CPLEX)
|
||||
SET(LEMON_SOURCES ${LEMON_SOURCES} cplex.cc)
|
||||
INCLUDE_DIRECTORIES(${ILOG_INCLUDE_DIRS})
|
||||
ENDIF()
|
||||
|
||||
IF(LEMON_HAVE_CLP)
|
||||
SET(LEMON_SOURCES ${LEMON_SOURCES} clp.cc)
|
||||
INCLUDE_DIRECTORIES(${COIN_INCLUDE_DIRS})
|
||||
ENDIF()
|
||||
|
||||
IF(LEMON_HAVE_CBC)
|
||||
SET(LEMON_SOURCES ${LEMON_SOURCES} cbc.cc)
|
||||
INCLUDE_DIRECTORIES(${COIN_INCLUDE_DIRS})
|
||||
ENDIF()
|
||||
|
||||
IF(LEMON_HAVE_SOPLEX)
|
||||
SET(LEMON_SOURCES ${LEMON_SOURCES} soplex.cc)
|
||||
INCLUDE_DIRECTORIES(${SOPLEX_INCLUDE_DIRS})
|
||||
ENDIF()
|
||||
|
||||
ADD_LIBRARY(lemon ${LEMON_SOURCES})
|
||||
|
||||
TARGET_LINK_LIBRARIES(lemon
|
||||
${GLPK_LIBRARIES} ${COIN_LIBRARIES} ${ILOG_LIBRARIES} ${SOPLEX_LIBRARIES}
|
||||
)
|
||||
|
||||
IF(UNIX)
|
||||
SET_TARGET_PROPERTIES(lemon PROPERTIES OUTPUT_NAME emon VERSION ${LEMON_VERSION} SOVERSION ${LEMON_VERSION})
|
||||
ENDIF()
|
||||
|
||||
INSTALL(
|
||||
TARGETS lemon
|
||||
ARCHIVE DESTINATION lib
|
||||
LIBRARY DESTINATION lib
|
||||
COMPONENT library
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
DIRECTORY . bits concepts
|
||||
DESTINATION include/lemon
|
||||
COMPONENT headers
|
||||
FILES_MATCHING PATTERN "*.h"
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/config.h
|
||||
DESTINATION include/lemon
|
||||
COMPONENT headers
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/lemon.pc
|
||||
DESTINATION lib/pkgconfig
|
||||
)
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,474 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2010
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <lemon/arg_parser.h>
|
||||
|
||||
namespace lemon {
|
||||
|
||||
void ArgParser::_terminate(ArgParserException::Reason reason) const
|
||||
{
|
||||
if(_exit_on_problems)
|
||||
exit(1);
|
||||
else throw(ArgParserException(reason));
|
||||
}
|
||||
|
||||
|
||||
void ArgParser::_showHelp(void *p)
|
||||
{
|
||||
(static_cast<ArgParser*>(p))->showHelp();
|
||||
(static_cast<ArgParser*>(p))->_terminate(ArgParserException::HELP);
|
||||
}
|
||||
|
||||
ArgParser::ArgParser(int argc, const char * const *argv)
|
||||
:_argc(argc), _argv(argv), _command_name(argv[0]),
|
||||
_exit_on_problems(true) {
|
||||
funcOption("-help","Print a short help message",_showHelp,this);
|
||||
synonym("help","-help");
|
||||
synonym("h","-help");
|
||||
}
|
||||
|
||||
ArgParser::~ArgParser()
|
||||
{
|
||||
for(Opts::iterator i=_opts.begin();i!=_opts.end();++i)
|
||||
if(i->second.self_delete)
|
||||
switch(i->second.type) {
|
||||
case BOOL:
|
||||
delete i->second.bool_p;
|
||||
break;
|
||||
case STRING:
|
||||
delete i->second.string_p;
|
||||
break;
|
||||
case DOUBLE:
|
||||
delete i->second.double_p;
|
||||
break;
|
||||
case INTEGER:
|
||||
delete i->second.int_p;
|
||||
break;
|
||||
case UNKNOWN:
|
||||
break;
|
||||
case FUNC:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ArgParser &ArgParser::intOption(const std::string &name,
|
||||
const std::string &help,
|
||||
int value, bool obl)
|
||||
{
|
||||
ParData p;
|
||||
p.int_p=new int(value);
|
||||
p.self_delete=true;
|
||||
p.help=help;
|
||||
p.type=INTEGER;
|
||||
p.mandatory=obl;
|
||||
_opts[name]=p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArgParser &ArgParser::doubleOption(const std::string &name,
|
||||
const std::string &help,
|
||||
double value, bool obl)
|
||||
{
|
||||
ParData p;
|
||||
p.double_p=new double(value);
|
||||
p.self_delete=true;
|
||||
p.help=help;
|
||||
p.type=DOUBLE;
|
||||
p.mandatory=obl;
|
||||
_opts[name]=p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArgParser &ArgParser::boolOption(const std::string &name,
|
||||
const std::string &help,
|
||||
bool value, bool obl)
|
||||
{
|
||||
ParData p;
|
||||
p.bool_p=new bool(value);
|
||||
p.self_delete=true;
|
||||
p.help=help;
|
||||
p.type=BOOL;
|
||||
p.mandatory=obl;
|
||||
_opts[name]=p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArgParser &ArgParser::stringOption(const std::string &name,
|
||||
const std::string &help,
|
||||
std::string value, bool obl)
|
||||
{
|
||||
ParData p;
|
||||
p.string_p=new std::string(value);
|
||||
p.self_delete=true;
|
||||
p.help=help;
|
||||
p.type=STRING;
|
||||
p.mandatory=obl;
|
||||
_opts[name]=p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArgParser &ArgParser::refOption(const std::string &name,
|
||||
const std::string &help,
|
||||
int &ref, bool obl)
|
||||
{
|
||||
ParData p;
|
||||
p.int_p=&ref;
|
||||
p.self_delete=false;
|
||||
p.help=help;
|
||||
p.type=INTEGER;
|
||||
p.mandatory=obl;
|
||||
_opts[name]=p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArgParser &ArgParser::refOption(const std::string &name,
|
||||
const std::string &help,
|
||||
double &ref, bool obl)
|
||||
{
|
||||
ParData p;
|
||||
p.double_p=&ref;
|
||||
p.self_delete=false;
|
||||
p.help=help;
|
||||
p.type=DOUBLE;
|
||||
p.mandatory=obl;
|
||||
_opts[name]=p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArgParser &ArgParser::refOption(const std::string &name,
|
||||
const std::string &help,
|
||||
bool &ref, bool obl)
|
||||
{
|
||||
ParData p;
|
||||
p.bool_p=&ref;
|
||||
p.self_delete=false;
|
||||
p.help=help;
|
||||
p.type=BOOL;
|
||||
p.mandatory=obl;
|
||||
_opts[name]=p;
|
||||
|
||||
ref = false;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArgParser &ArgParser::refOption(const std::string &name,
|
||||
const std::string &help,
|
||||
std::string &ref, bool obl)
|
||||
{
|
||||
ParData p;
|
||||
p.string_p=&ref;
|
||||
p.self_delete=false;
|
||||
p.help=help;
|
||||
p.type=STRING;
|
||||
p.mandatory=obl;
|
||||
_opts[name]=p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArgParser &ArgParser::funcOption(const std::string &name,
|
||||
const std::string &help,
|
||||
void (*func)(void *),void *data)
|
||||
{
|
||||
ParData p;
|
||||
p.func_p.p=func;
|
||||
p.func_p.data=data;
|
||||
p.self_delete=false;
|
||||
p.help=help;
|
||||
p.type=FUNC;
|
||||
p.mandatory=false;
|
||||
_opts[name]=p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArgParser &ArgParser::optionGroup(const std::string &group,
|
||||
const std::string &opt)
|
||||
{
|
||||
Opts::iterator i = _opts.find(opt);
|
||||
LEMON_ASSERT(i!=_opts.end(), "Unknown option: '"+opt+"'");
|
||||
LEMON_ASSERT(!(i->second.ingroup),
|
||||
"Option already in option group: '"+opt+"'");
|
||||
GroupData &g=_groups[group];
|
||||
g.opts.push_back(opt);
|
||||
i->second.ingroup=true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArgParser &ArgParser::onlyOneGroup(const std::string &group)
|
||||
{
|
||||
GroupData &g=_groups[group];
|
||||
g.only_one=true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArgParser &ArgParser::synonym(const std::string &syn,
|
||||
const std::string &opt)
|
||||
{
|
||||
Opts::iterator o = _opts.find(opt);
|
||||
Opts::iterator s = _opts.find(syn);
|
||||
LEMON_ASSERT(o!=_opts.end(), "Unknown option: '"+opt+"'");
|
||||
LEMON_ASSERT(s==_opts.end(), "Option already used: '"+syn+"'");
|
||||
ParData p;
|
||||
p.help=opt;
|
||||
p.mandatory=false;
|
||||
p.syn=true;
|
||||
_opts[syn]=p;
|
||||
o->second.has_syn=true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArgParser &ArgParser::mandatoryGroup(const std::string &group)
|
||||
{
|
||||
GroupData &g=_groups[group];
|
||||
g.mandatory=true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArgParser &ArgParser::other(const std::string &name,
|
||||
const std::string &help)
|
||||
{
|
||||
_others_help.push_back(OtherArg(name,help));
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ArgParser::show(std::ostream &os,Opts::const_iterator i) const
|
||||
{
|
||||
os << "-" << i->first;
|
||||
if(i->second.has_syn)
|
||||
for(Opts::const_iterator j=_opts.begin();j!=_opts.end();++j)
|
||||
if(j->second.syn&&j->second.help==i->first)
|
||||
os << "|-" << j->first;
|
||||
switch(i->second.type) {
|
||||
case STRING:
|
||||
os << " str";
|
||||
break;
|
||||
case INTEGER:
|
||||
os << " int";
|
||||
break;
|
||||
case DOUBLE:
|
||||
os << " num";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ArgParser::show(std::ostream &os,Groups::const_iterator i) const
|
||||
{
|
||||
GroupData::Opts::const_iterator o=i->second.opts.begin();
|
||||
while(o!=i->second.opts.end()) {
|
||||
show(os,_opts.find(*o));
|
||||
++o;
|
||||
if(o!=i->second.opts.end()) os<<'|';
|
||||
}
|
||||
}
|
||||
|
||||
void ArgParser::showHelp(Opts::const_iterator i) const
|
||||
{
|
||||
if(i->second.help.size()==0||i->second.syn) return;
|
||||
std::cerr << " ";
|
||||
show(std::cerr,i);
|
||||
std::cerr << std::endl;
|
||||
std::cerr << " " << i->second.help << std::endl;
|
||||
}
|
||||
void ArgParser::showHelp(std::vector<ArgParser::OtherArg>::const_iterator i)
|
||||
const
|
||||
{
|
||||
if(i->help.size()==0) return;
|
||||
std::cerr << " " << i->name << std::endl
|
||||
<< " " << i->help << std::endl;
|
||||
}
|
||||
|
||||
void ArgParser::shortHelp() const
|
||||
{
|
||||
const unsigned int LINE_LEN=77;
|
||||
const std::string indent(" ");
|
||||
std::cerr << "Usage:\n " << _command_name;
|
||||
int pos=_command_name.size()+2;
|
||||
for(Groups::const_iterator g=_groups.begin();g!=_groups.end();++g) {
|
||||
std::ostringstream cstr;
|
||||
cstr << ' ';
|
||||
if(!g->second.mandatory) cstr << '[';
|
||||
show(cstr,g);
|
||||
if(!g->second.mandatory) cstr << ']';
|
||||
if(pos+cstr.str().size()>LINE_LEN) {
|
||||
std::cerr << std::endl << indent;
|
||||
pos=indent.size();
|
||||
}
|
||||
std::cerr << cstr.str();
|
||||
pos+=cstr.str().size();
|
||||
}
|
||||
for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i)
|
||||
if(!i->second.ingroup&&!i->second.syn) {
|
||||
std::ostringstream cstr;
|
||||
cstr << ' ';
|
||||
if(!i->second.mandatory) cstr << '[';
|
||||
show(cstr,i);
|
||||
if(!i->second.mandatory) cstr << ']';
|
||||
if(pos+cstr.str().size()>LINE_LEN) {
|
||||
std::cerr << std::endl << indent;
|
||||
pos=indent.size();
|
||||
}
|
||||
std::cerr << cstr.str();
|
||||
pos+=cstr.str().size();
|
||||
}
|
||||
for(std::vector<OtherArg>::const_iterator i=_others_help.begin();
|
||||
i!=_others_help.end();++i)
|
||||
{
|
||||
std::ostringstream cstr;
|
||||
cstr << ' ' << i->name;
|
||||
|
||||
if(pos+cstr.str().size()>LINE_LEN) {
|
||||
std::cerr << std::endl << indent;
|
||||
pos=indent.size();
|
||||
}
|
||||
std::cerr << cstr.str();
|
||||
pos+=cstr.str().size();
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
void ArgParser::showHelp() const
|
||||
{
|
||||
shortHelp();
|
||||
std::cerr << "Where:\n";
|
||||
for(std::vector<OtherArg>::const_iterator i=_others_help.begin();
|
||||
i!=_others_help.end();++i) showHelp(i);
|
||||
for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i) showHelp(i);
|
||||
_terminate(ArgParserException::HELP);
|
||||
}
|
||||
|
||||
|
||||
void ArgParser::unknownOpt(std::string arg) const
|
||||
{
|
||||
std::cerr << "\nUnknown option: " << arg << "\n";
|
||||
std::cerr << "\nType '" << _command_name <<
|
||||
" --help' to obtain a short summary on the usage.\n\n";
|
||||
_terminate(ArgParserException::UNKNOWN_OPT);
|
||||
}
|
||||
|
||||
void ArgParser::requiresValue(std::string arg, OptType t) const
|
||||
{
|
||||
std::cerr << "Argument '" << arg << "' requires a";
|
||||
switch(t) {
|
||||
case STRING:
|
||||
std::cerr << " string";
|
||||
break;
|
||||
case INTEGER:
|
||||
std::cerr << "n integer";
|
||||
break;
|
||||
case DOUBLE:
|
||||
std::cerr << " floating point";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
std::cerr << " value\n\n";
|
||||
showHelp();
|
||||
}
|
||||
|
||||
|
||||
void ArgParser::checkMandatories() const
|
||||
{
|
||||
bool ok=true;
|
||||
for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i)
|
||||
if(i->second.mandatory&&!i->second.set)
|
||||
{
|
||||
if(ok)
|
||||
std::cerr << _command_name
|
||||
<< ": The following mandatory arguments are missing.\n";
|
||||
ok=false;
|
||||
showHelp(i);
|
||||
}
|
||||
for(Groups::const_iterator i=_groups.begin();i!=_groups.end();++i)
|
||||
if(i->second.mandatory||i->second.only_one)
|
||||
{
|
||||
int set=0;
|
||||
for(GroupData::Opts::const_iterator o=i->second.opts.begin();
|
||||
o!=i->second.opts.end();++o)
|
||||
if(_opts.find(*o)->second.set) ++set;
|
||||
if(i->second.mandatory&&!set) {
|
||||
std::cerr << _command_name <<
|
||||
": At least one of the following arguments is mandatory.\n";
|
||||
ok=false;
|
||||
for(GroupData::Opts::const_iterator o=i->second.opts.begin();
|
||||
o!=i->second.opts.end();++o)
|
||||
showHelp(_opts.find(*o));
|
||||
}
|
||||
if(i->second.only_one&&set>1) {
|
||||
std::cerr << _command_name <<
|
||||
": At most one of the following arguments can be given.\n";
|
||||
ok=false;
|
||||
for(GroupData::Opts::const_iterator o=i->second.opts.begin();
|
||||
o!=i->second.opts.end();++o)
|
||||
showHelp(_opts.find(*o));
|
||||
}
|
||||
}
|
||||
if(!ok) {
|
||||
std::cerr << "\nType '" << _command_name <<
|
||||
" --help' to obtain a short summary on the usage.\n\n";
|
||||
_terminate(ArgParserException::INVALID_OPT);
|
||||
}
|
||||
}
|
||||
|
||||
ArgParser &ArgParser::parse()
|
||||
{
|
||||
for(int ar=1; ar<_argc; ++ar) {
|
||||
std::string arg(_argv[ar]);
|
||||
if (arg[0] != '-' || arg.size() == 1) {
|
||||
_file_args.push_back(arg);
|
||||
}
|
||||
else {
|
||||
Opts::iterator i = _opts.find(arg.substr(1));
|
||||
if(i==_opts.end()) unknownOpt(arg);
|
||||
else {
|
||||
if(i->second.syn) i=_opts.find(i->second.help);
|
||||
ParData &p(i->second);
|
||||
if (p.type==BOOL) *p.bool_p=true;
|
||||
else if (p.type==FUNC) p.func_p.p(p.func_p.data);
|
||||
else if(++ar==_argc) requiresValue(arg, p.type);
|
||||
else {
|
||||
std::string val(_argv[ar]);
|
||||
std::istringstream vals(val);
|
||||
switch(p.type) {
|
||||
case STRING:
|
||||
*p.string_p=val;
|
||||
break;
|
||||
case INTEGER:
|
||||
vals >> *p.int_p;
|
||||
break;
|
||||
case DOUBLE:
|
||||
vals >> *p.double_p;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(p.type!=STRING&&(!vals||!vals.eof()))
|
||||
requiresValue(arg, p.type);
|
||||
}
|
||||
p.set = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
checkMandatories();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,440 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2010
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_ARG_PARSER_H
|
||||
#define LEMON_ARG_PARSER_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <lemon/assert.h>
|
||||
|
||||
///\ingroup misc
|
||||
///\file
|
||||
///\brief A tool to parse command line arguments.
|
||||
|
||||
namespace lemon {
|
||||
|
||||
///Exception used by ArgParser
|
||||
|
||||
///Exception used by ArgParser.
|
||||
///
|
||||
class ArgParserException : public Exception {
|
||||
public:
|
||||
/// Reasons for failure
|
||||
|
||||
/// Reasons for failure.
|
||||
///
|
||||
enum Reason {
|
||||
HELP, ///< <tt>--help</tt> option was given.
|
||||
UNKNOWN_OPT, ///< Unknown option was given.
|
||||
INVALID_OPT ///< Invalid combination of options.
|
||||
};
|
||||
|
||||
private:
|
||||
Reason _reason;
|
||||
|
||||
public:
|
||||
///Constructor
|
||||
ArgParserException(Reason r) throw() : _reason(r) {}
|
||||
///Virtual destructor
|
||||
virtual ~ArgParserException() throw() {}
|
||||
///A short description of the exception
|
||||
virtual const char* what() const throw() {
|
||||
switch(_reason)
|
||||
{
|
||||
case HELP:
|
||||
return "lemon::ArgParseException: ask for help";
|
||||
break;
|
||||
case UNKNOWN_OPT:
|
||||
return "lemon::ArgParseException: unknown option";
|
||||
break;
|
||||
case INVALID_OPT:
|
||||
return "lemon::ArgParseException: invalid combination of options";
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
///Return the reason for the failure
|
||||
Reason reason() const {return _reason; }
|
||||
};
|
||||
|
||||
|
||||
///Command line arguments parser
|
||||
|
||||
///\ingroup misc
|
||||
///Command line arguments parser.
|
||||
///
|
||||
///For a complete example see the \ref arg_parser_demo.cc demo file.
|
||||
class ArgParser {
|
||||
|
||||
static void _showHelp(void *p);
|
||||
protected:
|
||||
|
||||
int _argc;
|
||||
const char * const *_argv;
|
||||
|
||||
enum OptType { UNKNOWN=0, BOOL=1, STRING=2, DOUBLE=3, INTEGER=4, FUNC=5 };
|
||||
|
||||
class ParData {
|
||||
public:
|
||||
union {
|
||||
bool *bool_p;
|
||||
int *int_p;
|
||||
double *double_p;
|
||||
std::string *string_p;
|
||||
struct {
|
||||
void (*p)(void *);
|
||||
void *data;
|
||||
} func_p;
|
||||
|
||||
};
|
||||
std::string help;
|
||||
bool mandatory;
|
||||
OptType type;
|
||||
bool set;
|
||||
bool ingroup;
|
||||
bool has_syn;
|
||||
bool syn;
|
||||
bool self_delete;
|
||||
ParData() : mandatory(false), type(UNKNOWN), set(false), ingroup(false),
|
||||
has_syn(false), syn(false), self_delete(false) {}
|
||||
};
|
||||
|
||||
typedef std::map<std::string,ParData> Opts;
|
||||
Opts _opts;
|
||||
|
||||
class GroupData
|
||||
{
|
||||
public:
|
||||
typedef std::list<std::string> Opts;
|
||||
Opts opts;
|
||||
bool only_one;
|
||||
bool mandatory;
|
||||
GroupData() :only_one(false), mandatory(false) {}
|
||||
};
|
||||
|
||||
typedef std::map<std::string,GroupData> Groups;
|
||||
Groups _groups;
|
||||
|
||||
struct OtherArg
|
||||
{
|
||||
std::string name;
|
||||
std::string help;
|
||||
OtherArg(std::string n, std::string h) :name(n), help(h) {}
|
||||
|
||||
};
|
||||
|
||||
std::vector<OtherArg> _others_help;
|
||||
std::vector<std::string> _file_args;
|
||||
std::string _command_name;
|
||||
|
||||
|
||||
private:
|
||||
//Bind a function to an option.
|
||||
|
||||
//\param name The name of the option. The leading '-' must be omitted.
|
||||
//\param help A help string.
|
||||
//\retval func The function to be called when the option is given. It
|
||||
// must be of type "void f(void *)"
|
||||
//\param data Data to be passed to \c func
|
||||
ArgParser &funcOption(const std::string &name,
|
||||
const std::string &help,
|
||||
void (*func)(void *),void *data);
|
||||
|
||||
bool _exit_on_problems;
|
||||
|
||||
void _terminate(ArgParserException::Reason reason) const;
|
||||
|
||||
public:
|
||||
|
||||
///Constructor
|
||||
ArgParser(int argc, const char * const *argv);
|
||||
|
||||
~ArgParser();
|
||||
|
||||
///\name Options
|
||||
///
|
||||
|
||||
///@{
|
||||
|
||||
///Add a new integer type option
|
||||
|
||||
///Add a new integer type option.
|
||||
///\param name The name of the option. The leading '-' must be omitted.
|
||||
///\param help A help string.
|
||||
///\param value A default value for the option.
|
||||
///\param obl Indicate if the option is mandatory.
|
||||
ArgParser &intOption(const std::string &name,
|
||||
const std::string &help,
|
||||
int value=0, bool obl=false);
|
||||
|
||||
///Add a new floating point type option
|
||||
|
||||
///Add a new floating point type option.
|
||||
///\param name The name of the option. The leading '-' must be omitted.
|
||||
///\param help A help string.
|
||||
///\param value A default value for the option.
|
||||
///\param obl Indicate if the option is mandatory.
|
||||
ArgParser &doubleOption(const std::string &name,
|
||||
const std::string &help,
|
||||
double value=0, bool obl=false);
|
||||
|
||||
///Add a new bool type option
|
||||
|
||||
///Add a new bool type option.
|
||||
///\param name The name of the option. The leading '-' must be omitted.
|
||||
///\param help A help string.
|
||||
///\param value A default value for the option.
|
||||
///\param obl Indicate if the option is mandatory.
|
||||
///\note A mandatory bool obtion is of very little use.
|
||||
ArgParser &boolOption(const std::string &name,
|
||||
const std::string &help,
|
||||
bool value=false, bool obl=false);
|
||||
|
||||
///Add a new string type option
|
||||
|
||||
///Add a new string type option.
|
||||
///\param name The name of the option. The leading '-' must be omitted.
|
||||
///\param help A help string.
|
||||
///\param value A default value for the option.
|
||||
///\param obl Indicate if the option is mandatory.
|
||||
ArgParser &stringOption(const std::string &name,
|
||||
const std::string &help,
|
||||
std::string value="", bool obl=false);
|
||||
|
||||
///Give help string for non-parsed arguments.
|
||||
|
||||
///With this function you can give help string for non-parsed arguments.
|
||||
///The parameter \c name will be printed in the short usage line, while
|
||||
///\c help gives a more detailed description.
|
||||
ArgParser &other(const std::string &name,
|
||||
const std::string &help="");
|
||||
|
||||
///@}
|
||||
|
||||
///\name Options with External Storage
|
||||
///Using this functions, the value of the option will be directly written
|
||||
///into a variable once the option appears in the command line.
|
||||
|
||||
///@{
|
||||
|
||||
///Add a new integer type option with a storage reference
|
||||
|
||||
///Add a new integer type option with a storage reference.
|
||||
///\param name The name of the option. The leading '-' must be omitted.
|
||||
///\param help A help string.
|
||||
///\param obl Indicate if the option is mandatory.
|
||||
///\retval ref The value of the argument will be written to this variable.
|
||||
ArgParser &refOption(const std::string &name,
|
||||
const std::string &help,
|
||||
int &ref, bool obl=false);
|
||||
|
||||
///Add a new floating type option with a storage reference
|
||||
|
||||
///Add a new floating type option with a storage reference.
|
||||
///\param name The name of the option. The leading '-' must be omitted.
|
||||
///\param help A help string.
|
||||
///\param obl Indicate if the option is mandatory.
|
||||
///\retval ref The value of the argument will be written to this variable.
|
||||
ArgParser &refOption(const std::string &name,
|
||||
const std::string &help,
|
||||
double &ref, bool obl=false);
|
||||
|
||||
///Add a new bool type option with a storage reference
|
||||
|
||||
///Add a new bool type option with a storage reference.
|
||||
///\param name The name of the option. The leading '-' must be omitted.
|
||||
///\param help A help string.
|
||||
///\param obl Indicate if the option is mandatory.
|
||||
///\retval ref The value of the argument will be written to this variable.
|
||||
///\note A mandatory bool obtion is of very little use.
|
||||
ArgParser &refOption(const std::string &name,
|
||||
const std::string &help,
|
||||
bool &ref, bool obl=false);
|
||||
|
||||
///Add a new string type option with a storage reference
|
||||
|
||||
///Add a new string type option with a storage reference.
|
||||
///\param name The name of the option. The leading '-' must be omitted.
|
||||
///\param help A help string.
|
||||
///\param obl Indicate if the option is mandatory.
|
||||
///\retval ref The value of the argument will be written to this variable.
|
||||
ArgParser &refOption(const std::string &name,
|
||||
const std::string &help,
|
||||
std::string &ref, bool obl=false);
|
||||
|
||||
///@}
|
||||
|
||||
///\name Option Groups and Synonyms
|
||||
///
|
||||
|
||||
///@{
|
||||
|
||||
///Bundle some options into a group
|
||||
|
||||
/// You can group some option by calling this function repeatedly for each
|
||||
/// option to be grouped with the same groupname.
|
||||
///\param group The group name.
|
||||
///\param opt The option name.
|
||||
ArgParser &optionGroup(const std::string &group,
|
||||
const std::string &opt);
|
||||
|
||||
///Make the members of a group exclusive
|
||||
|
||||
///If you call this function for a group, than at most one of them can be
|
||||
///given at the same time.
|
||||
ArgParser &onlyOneGroup(const std::string &group);
|
||||
|
||||
///Make a group mandatory
|
||||
|
||||
///Using this function, at least one of the members of \c group
|
||||
///must be given.
|
||||
ArgParser &mandatoryGroup(const std::string &group);
|
||||
|
||||
///Create synonym to an option
|
||||
|
||||
///With this function you can create a synonym \c syn of the
|
||||
///option \c opt.
|
||||
ArgParser &synonym(const std::string &syn,
|
||||
const std::string &opt);
|
||||
|
||||
///@}
|
||||
|
||||
private:
|
||||
void show(std::ostream &os,Opts::const_iterator i) const;
|
||||
void show(std::ostream &os,Groups::const_iterator i) const;
|
||||
void showHelp(Opts::const_iterator i) const;
|
||||
void showHelp(std::vector<OtherArg>::const_iterator i) const;
|
||||
|
||||
void unknownOpt(std::string arg) const;
|
||||
|
||||
void requiresValue(std::string arg, OptType t) const;
|
||||
void checkMandatories() const;
|
||||
|
||||
void shortHelp() const;
|
||||
void showHelp() const;
|
||||
public:
|
||||
|
||||
///Start the parsing process
|
||||
ArgParser &parse();
|
||||
|
||||
/// Synonym for parse()
|
||||
ArgParser &run()
|
||||
{
|
||||
return parse();
|
||||
}
|
||||
|
||||
///Give back the command name (the 0th argument)
|
||||
const std::string &commandName() const { return _command_name; }
|
||||
|
||||
///Check if an opion has been given to the command.
|
||||
bool given(std::string op) const
|
||||
{
|
||||
Opts::const_iterator i = _opts.find(op);
|
||||
return i!=_opts.end()?i->second.set:false;
|
||||
}
|
||||
|
||||
|
||||
///Magic type for operator[]
|
||||
|
||||
///This is the type of the return value of ArgParser::operator[]().
|
||||
///It automatically converts to \c int, \c double, \c bool or
|
||||
///\c std::string if the type of the option matches, which is checked
|
||||
///with an \ref LEMON_ASSERT "assertion" (i.e. it performs runtime
|
||||
///type checking).
|
||||
class RefType
|
||||
{
|
||||
const ArgParser &_parser;
|
||||
std::string _name;
|
||||
public:
|
||||
///\e
|
||||
RefType(const ArgParser &p,const std::string &n) :_parser(p),_name(n) {}
|
||||
///\e
|
||||
operator bool()
|
||||
{
|
||||
Opts::const_iterator i = _parser._opts.find(_name);
|
||||
LEMON_ASSERT(i!=_parser._opts.end(),
|
||||
std::string()+"Unkown option: '"+_name+"'");
|
||||
LEMON_ASSERT(i->second.type==ArgParser::BOOL,
|
||||
std::string()+"'"+_name+"' is a bool option");
|
||||
return *(i->second.bool_p);
|
||||
}
|
||||
///\e
|
||||
operator std::string()
|
||||
{
|
||||
Opts::const_iterator i = _parser._opts.find(_name);
|
||||
LEMON_ASSERT(i!=_parser._opts.end(),
|
||||
std::string()+"Unkown option: '"+_name+"'");
|
||||
LEMON_ASSERT(i->second.type==ArgParser::STRING,
|
||||
std::string()+"'"+_name+"' is a string option");
|
||||
return *(i->second.string_p);
|
||||
}
|
||||
///\e
|
||||
operator double()
|
||||
{
|
||||
Opts::const_iterator i = _parser._opts.find(_name);
|
||||
LEMON_ASSERT(i!=_parser._opts.end(),
|
||||
std::string()+"Unkown option: '"+_name+"'");
|
||||
LEMON_ASSERT(i->second.type==ArgParser::DOUBLE ||
|
||||
i->second.type==ArgParser::INTEGER,
|
||||
std::string()+"'"+_name+"' is a floating point option");
|
||||
return i->second.type==ArgParser::DOUBLE ?
|
||||
*(i->second.double_p) : *(i->second.int_p);
|
||||
}
|
||||
///\e
|
||||
operator int()
|
||||
{
|
||||
Opts::const_iterator i = _parser._opts.find(_name);
|
||||
LEMON_ASSERT(i!=_parser._opts.end(),
|
||||
std::string()+"Unkown option: '"+_name+"'");
|
||||
LEMON_ASSERT(i->second.type==ArgParser::INTEGER,
|
||||
std::string()+"'"+_name+"' is an integer option");
|
||||
return *(i->second.int_p);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
///Give back the value of an option
|
||||
|
||||
///Give back the value of an option.
|
||||
///\sa RefType
|
||||
RefType operator[](const std::string &n) const
|
||||
{
|
||||
return RefType(*this, n);
|
||||
}
|
||||
|
||||
///Give back the non-option type arguments.
|
||||
|
||||
///Give back a reference to a vector consisting of the program arguments
|
||||
///not starting with a '-' character.
|
||||
const std::vector<std::string> &files() const { return _file_args; }
|
||||
|
||||
///Throw instead of exit in case of problems
|
||||
void throwOnProblems()
|
||||
{
|
||||
_exit_on_problems=false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LEMON_ARG_PARSER_H
|
|
@ -0,0 +1,214 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_ASSERT_H
|
||||
#define LEMON_ASSERT_H
|
||||
|
||||
/// \ingroup exceptions
|
||||
/// \file
|
||||
/// \brief Extended assertion handling
|
||||
|
||||
#include <lemon/error.h>
|
||||
|
||||
namespace lemon {
|
||||
|
||||
inline void assert_fail_abort(const char *file, int line,
|
||||
const char *function, const char* message,
|
||||
const char *assertion)
|
||||
{
|
||||
std::cerr << file << ":" << line << ": ";
|
||||
if (function)
|
||||
std::cerr << function << ": ";
|
||||
std::cerr << message;
|
||||
if (assertion)
|
||||
std::cerr << " (assertion '" << assertion << "' failed)";
|
||||
std::cerr << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
|
||||
namespace _assert_bits {
|
||||
|
||||
|
||||
inline const char* cstringify(const std::string& str) {
|
||||
return str.c_str();
|
||||
}
|
||||
|
||||
inline const char* cstringify(const char* str) {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LEMON_ASSERT_H
|
||||
|
||||
#undef LEMON_ASSERT
|
||||
#undef LEMON_DEBUG
|
||||
|
||||
#if (defined(LEMON_ASSERT_ABORT) ? 1 : 0) + \
|
||||
(defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) > 1
|
||||
#error "LEMON assertion system is not set properly"
|
||||
#endif
|
||||
|
||||
#if ((defined(LEMON_ASSERT_ABORT) ? 1 : 0) + \
|
||||
(defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) == 1 || \
|
||||
defined(LEMON_ENABLE_ASSERTS)) && \
|
||||
(defined(LEMON_DISABLE_ASSERTS) || \
|
||||
defined(NDEBUG))
|
||||
#error "LEMON assertion system is not set properly"
|
||||
#endif
|
||||
|
||||
|
||||
#if defined LEMON_ASSERT_ABORT
|
||||
# undef LEMON_ASSERT_HANDLER
|
||||
# define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort
|
||||
#elif defined LEMON_ASSERT_CUSTOM
|
||||
# undef LEMON_ASSERT_HANDLER
|
||||
# ifndef LEMON_CUSTOM_ASSERT_HANDLER
|
||||
# error "LEMON_CUSTOM_ASSERT_HANDLER is not set"
|
||||
# endif
|
||||
# define LEMON_ASSERT_HANDLER LEMON_CUSTOM_ASSERT_HANDLER
|
||||
#elif defined LEMON_DISABLE_ASSERTS
|
||||
# undef LEMON_ASSERT_HANDLER
|
||||
#elif defined NDEBUG
|
||||
# undef LEMON_ASSERT_HANDLER
|
||||
#else
|
||||
# define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort
|
||||
#endif
|
||||
|
||||
#ifndef LEMON_FUNCTION_NAME
|
||||
# if defined __GNUC__
|
||||
# define LEMON_FUNCTION_NAME (__PRETTY_FUNCTION__)
|
||||
# elif defined _MSC_VER
|
||||
# define LEMON_FUNCTION_NAME (__FUNCSIG__)
|
||||
# elif __STDC_VERSION__ >= 199901L
|
||||
# define LEMON_FUNCTION_NAME (__func__)
|
||||
# else
|
||||
# define LEMON_FUNCTION_NAME ("<unknown>")
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef DOXYGEN
|
||||
|
||||
/// \ingroup exceptions
|
||||
///
|
||||
/// \brief Macro for assertion with customizable message
|
||||
///
|
||||
/// Macro for assertion with customizable message.
|
||||
/// \param exp An expression that must be convertible to \c bool. If it is \c
|
||||
/// false, then an assertion is raised. The concrete behaviour depends on the
|
||||
/// settings of the assertion system.
|
||||
/// \param msg A <tt>const char*</tt> parameter, which can be used to provide
|
||||
/// information about the circumstances of the failed assertion.
|
||||
///
|
||||
/// The assertions are enabled in the default behaviour.
|
||||
/// You can disable them with the following code:
|
||||
/// \code
|
||||
/// #define LEMON_DISABLE_ASSERTS
|
||||
/// \endcode
|
||||
/// or with compilation parameters:
|
||||
/// \code
|
||||
/// g++ -DLEMON_DISABLE_ASSERTS
|
||||
/// make CXXFLAGS='-DLEMON_DISABLE_ASSERTS'
|
||||
/// \endcode
|
||||
/// The checking is also disabled when the standard macro \c NDEBUG is defined.
|
||||
///
|
||||
/// As a default behaviour the failed assertion prints a short log message to
|
||||
/// the standard error and aborts the execution.
|
||||
///
|
||||
/// However, the following modes can be used in the assertion system:
|
||||
/// - \c LEMON_ASSERT_ABORT The failed assertion prints a short log message to
|
||||
/// the standard error and aborts the program. It is the default behaviour.
|
||||
/// - \c LEMON_ASSERT_CUSTOM The user can define own assertion handler
|
||||
/// function.
|
||||
/// \code
|
||||
/// void custom_assert_handler(const char* file, int line,
|
||||
/// const char* function, const char* message,
|
||||
/// const char* assertion);
|
||||
/// \endcode
|
||||
/// The name of the function should be defined as the \c
|
||||
/// LEMON_CUSTOM_ASSERT_HANDLER macro name.
|
||||
/// \code
|
||||
/// #define LEMON_CUSTOM_ASSERT_HANDLER custom_assert_handler
|
||||
/// \endcode
|
||||
/// Whenever an assertion is occured, the custom assertion
|
||||
/// handler is called with appropiate parameters.
|
||||
///
|
||||
/// The assertion mode can also be changed within one compilation unit.
|
||||
/// If the macros are redefined with other settings and the
|
||||
/// \ref lemon/assert.h "assert.h" file is reincluded, then the
|
||||
/// behaviour is changed appropiately to the new settings.
|
||||
# define LEMON_ASSERT(exp, msg) \
|
||||
(static_cast<void> (!!(exp) ? 0 : ( \
|
||||
LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \
|
||||
LEMON_FUNCTION_NAME, \
|
||||
::lemon::_assert_bits::cstringify(msg), #exp), 0)))
|
||||
|
||||
/// \ingroup exceptions
|
||||
///
|
||||
/// \brief Macro for internal assertions
|
||||
///
|
||||
/// Macro for internal assertions, it is used in the library to check
|
||||
/// the consistency of results of algorithms, several pre- and
|
||||
/// postconditions and invariants. The checking is disabled by
|
||||
/// default, but it can be turned on with the macro \c
|
||||
/// LEMON_ENABLE_DEBUG.
|
||||
/// \code
|
||||
/// #define LEMON_ENABLE_DEBUG
|
||||
/// \endcode
|
||||
/// or with compilation parameters:
|
||||
/// \code
|
||||
/// g++ -DLEMON_ENABLE_DEBUG
|
||||
/// make CXXFLAGS='-DLEMON_ENABLE_DEBUG'
|
||||
/// \endcode
|
||||
///
|
||||
/// This macro works like the \c LEMON_ASSERT macro, therefore the
|
||||
/// current behaviour depends on the settings of \c LEMON_ASSERT
|
||||
/// macro.
|
||||
///
|
||||
/// \see LEMON_ASSERT
|
||||
# define LEMON_DEBUG(exp, msg) \
|
||||
(static_cast<void> (!!(exp) ? 0 : ( \
|
||||
LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \
|
||||
LEMON_FUNCTION_NAME, \
|
||||
::lemon::_assert_bits::cstringify(msg), #exp), 0)))
|
||||
|
||||
#else
|
||||
|
||||
# ifndef LEMON_ASSERT_HANDLER
|
||||
# define LEMON_ASSERT(exp, msg) (static_cast<void>(0))
|
||||
# define LEMON_DEBUG(exp, msg) (static_cast<void>(0))
|
||||
# else
|
||||
# define LEMON_ASSERT(exp, msg) \
|
||||
(static_cast<void> (!!(exp) ? 0 : ( \
|
||||
LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \
|
||||
LEMON_FUNCTION_NAME, \
|
||||
::lemon::_assert_bits::cstringify(msg), \
|
||||
#exp), 0)))
|
||||
# if defined LEMON_ENABLE_DEBUG
|
||||
# define LEMON_DEBUG(exp, msg) \
|
||||
(static_cast<void> (!!(exp) ? 0 : ( \
|
||||
LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \
|
||||
LEMON_FUNCTION_NAME, \
|
||||
::lemon::_assert_bits::cstringify(msg), \
|
||||
#exp), 0)))
|
||||
# else
|
||||
# define LEMON_DEBUG(exp, msg) (static_cast<void>(0))
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,37 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
///\file
|
||||
///\brief Some basic non-inline functions and static global data.
|
||||
|
||||
#include<lemon/tolerance.h>
|
||||
#include<lemon/core.h>
|
||||
#include<lemon/time_measure.h>
|
||||
namespace lemon {
|
||||
|
||||
float Tolerance<float>::def_epsilon = static_cast<float>(1e-4);
|
||||
double Tolerance<double>::def_epsilon = 1e-10;
|
||||
long double Tolerance<long double>::def_epsilon = 1e-14;
|
||||
|
||||
#ifndef LEMON_ONLY_TEMPLATES
|
||||
const Invalid INVALID = Invalid();
|
||||
#endif
|
||||
|
||||
TimeStamp::Format TimeStamp::_format = TimeStamp::NORMAL;
|
||||
|
||||
} //namespace lemon
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,347 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_BIN_HEAP_H
|
||||
#define LEMON_BIN_HEAP_H
|
||||
|
||||
///\ingroup heaps
|
||||
///\file
|
||||
///\brief Binary heap implementation.
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
|
||||
namespace lemon {
|
||||
|
||||
/// \ingroup heaps
|
||||
///
|
||||
/// \brief Binary heap data structure.
|
||||
///
|
||||
/// This class implements the \e binary \e heap data structure.
|
||||
/// It fully conforms to the \ref concepts::Heap "heap concept".
|
||||
///
|
||||
/// \tparam PR Type of the priorities of the items.
|
||||
/// \tparam IM A read-writable item map with \c int values, used
|
||||
/// internally to handle the cross references.
|
||||
/// \tparam CMP A functor class for comparing the priorities.
|
||||
/// The default is \c std::less<PR>.
|
||||
#ifdef DOXYGEN
|
||||
template <typename PR, typename IM, typename CMP>
|
||||
#else
|
||||
template <typename PR, typename IM, typename CMP = std::less<PR> >
|
||||
#endif
|
||||
class BinHeap {
|
||||
public:
|
||||
|
||||
/// Type of the item-int map.
|
||||
typedef IM ItemIntMap;
|
||||
/// Type of the priorities.
|
||||
typedef PR Prio;
|
||||
/// Type of the items stored in the heap.
|
||||
typedef typename ItemIntMap::Key Item;
|
||||
/// Type of the item-priority pairs.
|
||||
typedef std::pair<Item,Prio> Pair;
|
||||
/// Functor type for comparing the priorities.
|
||||
typedef CMP Compare;
|
||||
|
||||
/// \brief Type to represent the states of the items.
|
||||
///
|
||||
/// Each item has a state associated to it. It can be "in heap",
|
||||
/// "pre-heap" or "post-heap". The latter two are indifferent from the
|
||||
/// heap's point of view, but may be useful to the user.
|
||||
///
|
||||
/// The item-int map must be initialized in such way that it assigns
|
||||
/// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
|
||||
enum State {
|
||||
IN_HEAP = 0, ///< = 0.
|
||||
PRE_HEAP = -1, ///< = -1.
|
||||
POST_HEAP = -2 ///< = -2.
|
||||
};
|
||||
|
||||
private:
|
||||
std::vector<Pair> _data;
|
||||
Compare _comp;
|
||||
ItemIntMap &_iim;
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Constructor.
|
||||
///
|
||||
/// Constructor.
|
||||
/// \param map A map that assigns \c int values to the items.
|
||||
/// It is used internally to handle the cross references.
|
||||
/// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
|
||||
explicit BinHeap(ItemIntMap &map) : _iim(map) {}
|
||||
|
||||
/// \brief Constructor.
|
||||
///
|
||||
/// Constructor.
|
||||
/// \param map A map that assigns \c int values to the items.
|
||||
/// It is used internally to handle the cross references.
|
||||
/// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
|
||||
/// \param comp The function object used for comparing the priorities.
|
||||
BinHeap(ItemIntMap &map, const Compare &comp)
|
||||
: _iim(map), _comp(comp) {}
|
||||
|
||||
|
||||
/// \brief The number of items stored in the heap.
|
||||
///
|
||||
/// This function returns the number of items stored in the heap.
|
||||
int size() const { return _data.size(); }
|
||||
|
||||
/// \brief Check if the heap is empty.
|
||||
///
|
||||
/// This function returns \c true if the heap is empty.
|
||||
bool empty() const { return _data.empty(); }
|
||||
|
||||
/// \brief Make the heap empty.
|
||||
///
|
||||
/// This functon makes the heap empty.
|
||||
/// It does not change the cross reference map. If you want to reuse
|
||||
/// a heap that is not surely empty, you should first clear it and
|
||||
/// then you should set the cross reference map to \c PRE_HEAP
|
||||
/// for each item.
|
||||
void clear() {
|
||||
_data.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
static int parent(int i) { return (i-1)/2; }
|
||||
|
||||
static int secondChild(int i) { return 2*i+2; }
|
||||
bool less(const Pair &p1, const Pair &p2) const {
|
||||
return _comp(p1.second, p2.second);
|
||||
}
|
||||
|
||||
int bubbleUp(int hole, Pair p) {
|
||||
int par = parent(hole);
|
||||
while( hole>0 && less(p,_data[par]) ) {
|
||||
move(_data[par],hole);
|
||||
hole = par;
|
||||
par = parent(hole);
|
||||
}
|
||||
move(p, hole);
|
||||
return hole;
|
||||
}
|
||||
|
||||
int bubbleDown(int hole, Pair p, int length) {
|
||||
int child = secondChild(hole);
|
||||
while(child < length) {
|
||||
if( less(_data[child-1], _data[child]) ) {
|
||||
--child;
|
||||
}
|
||||
if( !less(_data[child], p) )
|
||||
goto ok;
|
||||
move(_data[child], hole);
|
||||
hole = child;
|
||||
child = secondChild(hole);
|
||||
}
|
||||
child--;
|
||||
if( child<length && less(_data[child], p) ) {
|
||||
move(_data[child], hole);
|
||||
hole=child;
|
||||
}
|
||||
ok:
|
||||
move(p, hole);
|
||||
return hole;
|
||||
}
|
||||
|
||||
void move(const Pair &p, int i) {
|
||||
_data[i] = p;
|
||||
_iim.set(p.first, i);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Insert a pair of item and priority into the heap.
|
||||
///
|
||||
/// This function inserts \c p.first to the heap with priority
|
||||
/// \c p.second.
|
||||
/// \param p The pair to insert.
|
||||
/// \pre \c p.first must not be stored in the heap.
|
||||
void push(const Pair &p) {
|
||||
int n = _data.size();
|
||||
_data.resize(n+1);
|
||||
bubbleUp(n, p);
|
||||
}
|
||||
|
||||
/// \brief Insert an item into the heap with the given priority.
|
||||
///
|
||||
/// This function inserts the given item into the heap with the
|
||||
/// given priority.
|
||||
/// \param i The item to insert.
|
||||
/// \param p The priority of the item.
|
||||
/// \pre \e i must not be stored in the heap.
|
||||
void push(const Item &i, const Prio &p) { push(Pair(i,p)); }
|
||||
|
||||
/// \brief Return the item having minimum priority.
|
||||
///
|
||||
/// This function returns the item having minimum priority.
|
||||
/// \pre The heap must be non-empty.
|
||||
Item top() const {
|
||||
return _data[0].first;
|
||||
}
|
||||
|
||||
/// \brief The minimum priority.
|
||||
///
|
||||
/// This function returns the minimum priority.
|
||||
/// \pre The heap must be non-empty.
|
||||
Prio prio() const {
|
||||
return _data[0].second;
|
||||
}
|
||||
|
||||
/// \brief Remove the item having minimum priority.
|
||||
///
|
||||
/// This function removes the item having minimum priority.
|
||||
/// \pre The heap must be non-empty.
|
||||
void pop() {
|
||||
int n = _data.size()-1;
|
||||
_iim.set(_data[0].first, POST_HEAP);
|
||||
if (n > 0) {
|
||||
bubbleDown(0, _data[n], n);
|
||||
}
|
||||
_data.pop_back();
|
||||
}
|
||||
|
||||
/// \brief Remove the given item from the heap.
|
||||
///
|
||||
/// This function removes the given item from the heap if it is
|
||||
/// already stored.
|
||||
/// \param i The item to delete.
|
||||
/// \pre \e i must be in the heap.
|
||||
void erase(const Item &i) {
|
||||
int h = _iim[i];
|
||||
int n = _data.size()-1;
|
||||
_iim.set(_data[h].first, POST_HEAP);
|
||||
if( h < n ) {
|
||||
if ( bubbleUp(h, _data[n]) == h) {
|
||||
bubbleDown(h, _data[n], n);
|
||||
}
|
||||
}
|
||||
_data.pop_back();
|
||||
}
|
||||
|
||||
/// \brief The priority of the given item.
|
||||
///
|
||||
/// This function returns the priority of the given item.
|
||||
/// \param i The item.
|
||||
/// \pre \e i must be in the heap.
|
||||
Prio operator[](const Item &i) const {
|
||||
int idx = _iim[i];
|
||||
return _data[idx].second;
|
||||
}
|
||||
|
||||
/// \brief Set the priority of an item or insert it, if it is
|
||||
/// not stored in the heap.
|
||||
///
|
||||
/// This method sets the priority of the given item if it is
|
||||
/// already stored in the heap. Otherwise it inserts the given
|
||||
/// item into the heap with the given priority.
|
||||
/// \param i The item.
|
||||
/// \param p The priority.
|
||||
void set(const Item &i, const Prio &p) {
|
||||
int idx = _iim[i];
|
||||
if( idx < 0 ) {
|
||||
push(i,p);
|
||||
}
|
||||
else if( _comp(p, _data[idx].second) ) {
|
||||
bubbleUp(idx, Pair(i,p));
|
||||
}
|
||||
else {
|
||||
bubbleDown(idx, Pair(i,p), _data.size());
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Decrease the priority of an item to the given value.
|
||||
///
|
||||
/// This function decreases the priority of an item to the given value.
|
||||
/// \param i The item.
|
||||
/// \param p The priority.
|
||||
/// \pre \e i must be stored in the heap with priority at least \e p.
|
||||
void decrease(const Item &i, const Prio &p) {
|
||||
int idx = _iim[i];
|
||||
bubbleUp(idx, Pair(i,p));
|
||||
}
|
||||
|
||||
/// \brief Increase the priority of an item to the given value.
|
||||
///
|
||||
/// This function increases the priority of an item to the given value.
|
||||
/// \param i The item.
|
||||
/// \param p The priority.
|
||||
/// \pre \e i must be stored in the heap with priority at most \e p.
|
||||
void increase(const Item &i, const Prio &p) {
|
||||
int idx = _iim[i];
|
||||
bubbleDown(idx, Pair(i,p), _data.size());
|
||||
}
|
||||
|
||||
/// \brief Return the state of an item.
|
||||
///
|
||||
/// This method returns \c PRE_HEAP if the given item has never
|
||||
/// been in the heap, \c IN_HEAP if it is in the heap at the moment,
|
||||
/// and \c POST_HEAP otherwise.
|
||||
/// In the latter case it is possible that the item will get back
|
||||
/// to the heap again.
|
||||
/// \param i The item.
|
||||
State state(const Item &i) const {
|
||||
int s = _iim[i];
|
||||
if( s>=0 )
|
||||
s=0;
|
||||
return State(s);
|
||||
}
|
||||
|
||||
/// \brief Set the state of an item in the heap.
|
||||
///
|
||||
/// This function sets the state of the given item in the heap.
|
||||
/// It can be used to manually clear the heap when it is important
|
||||
/// to achive better time complexity.
|
||||
/// \param i The item.
|
||||
/// \param st The state. It should not be \c IN_HEAP.
|
||||
void state(const Item& i, State st) {
|
||||
switch (st) {
|
||||
case POST_HEAP:
|
||||
case PRE_HEAP:
|
||||
if (state(i) == IN_HEAP) {
|
||||
erase(i);
|
||||
}
|
||||
_iim[i] = st;
|
||||
break;
|
||||
case IN_HEAP:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Replace an item in the heap.
|
||||
///
|
||||
/// This function replaces item \c i with item \c j.
|
||||
/// Item \c i must be in the heap, while \c j must be out of the heap.
|
||||
/// After calling this method, item \c i will be out of the
|
||||
/// heap and \c j will be in the heap with the same prioriority
|
||||
/// as item \c i had before.
|
||||
void replace(const Item& i, const Item& j) {
|
||||
int idx = _iim[i];
|
||||
_iim.set(i, _iim[j]);
|
||||
_iim.set(j, idx);
|
||||
_data[idx].first = j;
|
||||
}
|
||||
|
||||
}; // class BinHeap
|
||||
|
||||
} // namespace lemon
|
||||
|
||||
#endif // LEMON_BIN_HEAP_H
|
|
@ -0,0 +1,445 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2010
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_BINOMIAL_HEAP_H
|
||||
#define LEMON_BINOMIAL_HEAP_H
|
||||
|
||||
///\file
|
||||
///\ingroup heaps
|
||||
///\brief Binomial Heap implementation.
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
#include <lemon/math.h>
|
||||
#include <lemon/counter.h>
|
||||
|
||||
namespace lemon {
|
||||
|
||||
/// \ingroup heaps
|
||||
///
|
||||
///\brief Binomial heap data structure.
|
||||
///
|
||||
/// This class implements the \e binomial \e heap data structure.
|
||||
/// It fully conforms to the \ref concepts::Heap "heap concept".
|
||||
///
|
||||
/// The methods \ref increase() and \ref erase() are not efficient
|
||||
/// in a binomial heap. In case of many calls of these operations,
|
||||
/// it is better to use other heap structure, e.g. \ref BinHeap
|
||||
/// "binary heap".
|
||||
///
|
||||
/// \tparam PR Type of the priorities of the items.
|
||||
/// \tparam IM A read-writable item map with \c int values, used
|
||||
/// internally to handle the cross references.
|
||||
/// \tparam CMP A functor class for comparing the priorities.
|
||||
/// The default is \c std::less<PR>.
|
||||
#ifdef DOXYGEN
|
||||
template <typename PR, typename IM, typename CMP>
|
||||
#else
|
||||
template <typename PR, typename IM, typename CMP = std::less<PR> >
|
||||
#endif
|
||||
class BinomialHeap {
|
||||
public:
|
||||
/// Type of the item-int map.
|
||||
typedef IM ItemIntMap;
|
||||
/// Type of the priorities.
|
||||
typedef PR Prio;
|
||||
/// Type of the items stored in the heap.
|
||||
typedef typename ItemIntMap::Key Item;
|
||||
/// Functor type for comparing the priorities.
|
||||
typedef CMP Compare;
|
||||
|
||||
/// \brief Type to represent the states of the items.
|
||||
///
|
||||
/// Each item has a state associated to it. It can be "in heap",
|
||||
/// "pre-heap" or "post-heap". The latter two are indifferent from the
|
||||
/// heap's point of view, but may be useful to the user.
|
||||
///
|
||||
/// The item-int map must be initialized in such way that it assigns
|
||||
/// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
|
||||
enum State {
|
||||
IN_HEAP = 0, ///< = 0.
|
||||
PRE_HEAP = -1, ///< = -1.
|
||||
POST_HEAP = -2 ///< = -2.
|
||||
};
|
||||
|
||||
private:
|
||||
class Store;
|
||||
|
||||
std::vector<Store> _data;
|
||||
int _min, _head;
|
||||
ItemIntMap &_iim;
|
||||
Compare _comp;
|
||||
int _num_items;
|
||||
|
||||
public:
|
||||
/// \brief Constructor.
|
||||
///
|
||||
/// Constructor.
|
||||
/// \param map A map that assigns \c int values to the items.
|
||||
/// It is used internally to handle the cross references.
|
||||
/// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
|
||||
explicit BinomialHeap(ItemIntMap &map)
|
||||
: _min(0), _head(-1), _iim(map), _num_items(0) {}
|
||||
|
||||
/// \brief Constructor.
|
||||
///
|
||||
/// Constructor.
|
||||
/// \param map A map that assigns \c int values to the items.
|
||||
/// It is used internally to handle the cross references.
|
||||
/// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
|
||||
/// \param comp The function object used for comparing the priorities.
|
||||
BinomialHeap(ItemIntMap &map, const Compare &comp)
|
||||
: _min(0), _head(-1), _iim(map), _comp(comp), _num_items(0) {}
|
||||
|
||||
/// \brief The number of items stored in the heap.
|
||||
///
|
||||
/// This function returns the number of items stored in the heap.
|
||||
int size() const { return _num_items; }
|
||||
|
||||
/// \brief Check if the heap is empty.
|
||||
///
|
||||
/// This function returns \c true if the heap is empty.
|
||||
bool empty() const { return _num_items==0; }
|
||||
|
||||
/// \brief Make the heap empty.
|
||||
///
|
||||
/// This functon makes the heap empty.
|
||||
/// It does not change the cross reference map. If you want to reuse
|
||||
/// a heap that is not surely empty, you should first clear it and
|
||||
/// then you should set the cross reference map to \c PRE_HEAP
|
||||
/// for each item.
|
||||
void clear() {
|
||||
_data.clear(); _min=0; _num_items=0; _head=-1;
|
||||
}
|
||||
|
||||
/// \brief Set the priority of an item or insert it, if it is
|
||||
/// not stored in the heap.
|
||||
///
|
||||
/// This method sets the priority of the given item if it is
|
||||
/// already stored in the heap. Otherwise it inserts the given
|
||||
/// item into the heap with the given priority.
|
||||
/// \param item The item.
|
||||
/// \param value The priority.
|
||||
void set (const Item& item, const Prio& value) {
|
||||
int i=_iim[item];
|
||||
if ( i >= 0 && _data[i].in ) {
|
||||
if ( _comp(value, _data[i].prio) ) decrease(item, value);
|
||||
if ( _comp(_data[i].prio, value) ) increase(item, value);
|
||||
} else push(item, value);
|
||||
}
|
||||
|
||||
/// \brief Insert an item into the heap with the given priority.
|
||||
///
|
||||
/// This function inserts the given item into the heap with the
|
||||
/// given priority.
|
||||
/// \param item The item to insert.
|
||||
/// \param value The priority of the item.
|
||||
/// \pre \e item must not be stored in the heap.
|
||||
void push (const Item& item, const Prio& value) {
|
||||
int i=_iim[item];
|
||||
if ( i<0 ) {
|
||||
int s=_data.size();
|
||||
_iim.set( item,s );
|
||||
Store st;
|
||||
st.name=item;
|
||||
st.prio=value;
|
||||
_data.push_back(st);
|
||||
i=s;
|
||||
}
|
||||
else {
|
||||
_data[i].parent=_data[i].right_neighbor=_data[i].child=-1;
|
||||
_data[i].degree=0;
|
||||
_data[i].in=true;
|
||||
_data[i].prio=value;
|
||||
}
|
||||
|
||||
if( 0==_num_items ) {
|
||||
_head=i;
|
||||
_min=i;
|
||||
} else {
|
||||
merge(i);
|
||||
if( _comp(_data[i].prio, _data[_min].prio) ) _min=i;
|
||||
}
|
||||
++_num_items;
|
||||
}
|
||||
|
||||
/// \brief Return the item having minimum priority.
|
||||
///
|
||||
/// This function returns the item having minimum priority.
|
||||
/// \pre The heap must be non-empty.
|
||||
Item top() const { return _data[_min].name; }
|
||||
|
||||
/// \brief The minimum priority.
|
||||
///
|
||||
/// This function returns the minimum priority.
|
||||
/// \pre The heap must be non-empty.
|
||||
Prio prio() const { return _data[_min].prio; }
|
||||
|
||||
/// \brief The priority of the given item.
|
||||
///
|
||||
/// This function returns the priority of the given item.
|
||||
/// \param item The item.
|
||||
/// \pre \e item must be in the heap.
|
||||
const Prio& operator[](const Item& item) const {
|
||||
return _data[_iim[item]].prio;
|
||||
}
|
||||
|
||||
/// \brief Remove the item having minimum priority.
|
||||
///
|
||||
/// This function removes the item having minimum priority.
|
||||
/// \pre The heap must be non-empty.
|
||||
void pop() {
|
||||
_data[_min].in=false;
|
||||
|
||||
int head_child=-1;
|
||||
if ( _data[_min].child!=-1 ) {
|
||||
int child=_data[_min].child;
|
||||
int neighb;
|
||||
while( child!=-1 ) {
|
||||
neighb=_data[child].right_neighbor;
|
||||
_data[child].parent=-1;
|
||||
_data[child].right_neighbor=head_child;
|
||||
head_child=child;
|
||||
child=neighb;
|
||||
}
|
||||
}
|
||||
|
||||
if ( _data[_head].right_neighbor==-1 ) {
|
||||
// there was only one root
|
||||
_head=head_child;
|
||||
}
|
||||
else {
|
||||
// there were more roots
|
||||
if( _head!=_min ) { unlace(_min); }
|
||||
else { _head=_data[_head].right_neighbor; }
|
||||
merge(head_child);
|
||||
}
|
||||
_min=findMin();
|
||||
--_num_items;
|
||||
}
|
||||
|
||||
/// \brief Remove the given item from the heap.
|
||||
///
|
||||
/// This function removes the given item from the heap if it is
|
||||
/// already stored.
|
||||
/// \param item The item to delete.
|
||||
/// \pre \e item must be in the heap.
|
||||
void erase (const Item& item) {
|
||||
int i=_iim[item];
|
||||
if ( i >= 0 && _data[i].in ) {
|
||||
decrease( item, _data[_min].prio-1 );
|
||||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Decrease the priority of an item to the given value.
|
||||
///
|
||||
/// This function decreases the priority of an item to the given value.
|
||||
/// \param item The item.
|
||||
/// \param value The priority.
|
||||
/// \pre \e item must be stored in the heap with priority at least \e value.
|
||||
void decrease (Item item, const Prio& value) {
|
||||
int i=_iim[item];
|
||||
int p=_data[i].parent;
|
||||
_data[i].prio=value;
|
||||
|
||||
while( p!=-1 && _comp(value, _data[p].prio) ) {
|
||||
_data[i].name=_data[p].name;
|
||||
_data[i].prio=_data[p].prio;
|
||||
_data[p].name=item;
|
||||
_data[p].prio=value;
|
||||
_iim[_data[i].name]=i;
|
||||
i=p;
|
||||
p=_data[p].parent;
|
||||
}
|
||||
_iim[item]=i;
|
||||
if ( _comp(value, _data[_min].prio) ) _min=i;
|
||||
}
|
||||
|
||||
/// \brief Increase the priority of an item to the given value.
|
||||
///
|
||||
/// This function increases the priority of an item to the given value.
|
||||
/// \param item The item.
|
||||
/// \param value The priority.
|
||||
/// \pre \e item must be stored in the heap with priority at most \e value.
|
||||
void increase (Item item, const Prio& value) {
|
||||
erase(item);
|
||||
push(item, value);
|
||||
}
|
||||
|
||||
/// \brief Return the state of an item.
|
||||
///
|
||||
/// This method returns \c PRE_HEAP if the given item has never
|
||||
/// been in the heap, \c IN_HEAP if it is in the heap at the moment,
|
||||
/// and \c POST_HEAP otherwise.
|
||||
/// In the latter case it is possible that the item will get back
|
||||
/// to the heap again.
|
||||
/// \param item The item.
|
||||
State state(const Item &item) const {
|
||||
int i=_iim[item];
|
||||
if( i>=0 ) {
|
||||
if ( _data[i].in ) i=0;
|
||||
else i=-2;
|
||||
}
|
||||
return State(i);
|
||||
}
|
||||
|
||||
/// \brief Set the state of an item in the heap.
|
||||
///
|
||||
/// This function sets the state of the given item in the heap.
|
||||
/// It can be used to manually clear the heap when it is important
|
||||
/// to achive better time complexity.
|
||||
/// \param i The item.
|
||||
/// \param st The state. It should not be \c IN_HEAP.
|
||||
void state(const Item& i, State st) {
|
||||
switch (st) {
|
||||
case POST_HEAP:
|
||||
case PRE_HEAP:
|
||||
if (state(i) == IN_HEAP) {
|
||||
erase(i);
|
||||
}
|
||||
_iim[i] = st;
|
||||
break;
|
||||
case IN_HEAP:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Find the minimum of the roots
|
||||
int findMin() {
|
||||
if( _head!=-1 ) {
|
||||
int min_loc=_head, min_val=_data[_head].prio;
|
||||
for( int x=_data[_head].right_neighbor; x!=-1;
|
||||
x=_data[x].right_neighbor ) {
|
||||
if( _comp( _data[x].prio,min_val ) ) {
|
||||
min_val=_data[x].prio;
|
||||
min_loc=x;
|
||||
}
|
||||
}
|
||||
return min_loc;
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
|
||||
// Merge the heap with another heap starting at the given position
|
||||
void merge(int a) {
|
||||
if( _head==-1 || a==-1 ) return;
|
||||
if( _data[a].right_neighbor==-1 &&
|
||||
_data[a].degree<=_data[_head].degree ) {
|
||||
_data[a].right_neighbor=_head;
|
||||
_head=a;
|
||||
} else {
|
||||
interleave(a);
|
||||
}
|
||||
if( _data[_head].right_neighbor==-1 ) return;
|
||||
|
||||
int x=_head;
|
||||
int x_prev=-1, x_next=_data[x].right_neighbor;
|
||||
while( x_next!=-1 ) {
|
||||
if( _data[x].degree!=_data[x_next].degree ||
|
||||
( _data[x_next].right_neighbor!=-1 &&
|
||||
_data[_data[x_next].right_neighbor].degree==_data[x].degree ) ) {
|
||||
x_prev=x;
|
||||
x=x_next;
|
||||
}
|
||||
else {
|
||||
if( _comp(_data[x_next].prio,_data[x].prio) ) {
|
||||
if( x_prev==-1 ) {
|
||||
_head=x_next;
|
||||
} else {
|
||||
_data[x_prev].right_neighbor=x_next;
|
||||
}
|
||||
fuse(x,x_next);
|
||||
x=x_next;
|
||||
}
|
||||
else {
|
||||
_data[x].right_neighbor=_data[x_next].right_neighbor;
|
||||
fuse(x_next,x);
|
||||
}
|
||||
}
|
||||
x_next=_data[x].right_neighbor;
|
||||
}
|
||||
}
|
||||
|
||||
// Interleave the elements of the given list into the list of the roots
|
||||
void interleave(int a) {
|
||||
int p=_head, q=a;
|
||||
int curr=_data.size();
|
||||
_data.push_back(Store());
|
||||
|
||||
while( p!=-1 || q!=-1 ) {
|
||||
if( q==-1 || ( p!=-1 && _data[p].degree<_data[q].degree ) ) {
|
||||
_data[curr].right_neighbor=p;
|
||||
curr=p;
|
||||
p=_data[p].right_neighbor;
|
||||
}
|
||||
else {
|
||||
_data[curr].right_neighbor=q;
|
||||
curr=q;
|
||||
q=_data[q].right_neighbor;
|
||||
}
|
||||
}
|
||||
|
||||
_head=_data.back().right_neighbor;
|
||||
_data.pop_back();
|
||||
}
|
||||
|
||||
// Lace node a under node b
|
||||
void fuse(int a, int b) {
|
||||
_data[a].parent=b;
|
||||
_data[a].right_neighbor=_data[b].child;
|
||||
_data[b].child=a;
|
||||
|
||||
++_data[b].degree;
|
||||
}
|
||||
|
||||
// Unlace node a (if it has siblings)
|
||||
void unlace(int a) {
|
||||
int neighb=_data[a].right_neighbor;
|
||||
int other=_head;
|
||||
|
||||
while( _data[other].right_neighbor!=a )
|
||||
other=_data[other].right_neighbor;
|
||||
_data[other].right_neighbor=neighb;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
class Store {
|
||||
friend class BinomialHeap;
|
||||
|
||||
Item name;
|
||||
int parent;
|
||||
int right_neighbor;
|
||||
int child;
|
||||
int degree;
|
||||
bool in;
|
||||
Prio prio;
|
||||
|
||||
Store() : parent(-1), right_neighbor(-1), child(-1), degree(0),
|
||||
in(true) {}
|
||||
};
|
||||
};
|
||||
|
||||
} //namespace lemon
|
||||
|
||||
#endif //LEMON_BINOMIAL_HEAP_H
|
||||
|
|
@ -0,0 +1,472 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_BITS_ALTERATION_NOTIFIER_H
|
||||
#define LEMON_BITS_ALTERATION_NOTIFIER_H
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#include <lemon/core.h>
|
||||
#include <lemon/bits/lock.h>
|
||||
|
||||
//\ingroup graphbits
|
||||
//\file
|
||||
//\brief Observer notifier for graph alteration observers.
|
||||
|
||||
namespace lemon {
|
||||
|
||||
// \ingroup graphbits
|
||||
//
|
||||
// \brief Notifier class to notify observes about alterations in
|
||||
// a container.
|
||||
//
|
||||
// The simple graphs can be refered as two containers: a node container
|
||||
// and an edge container. But they do not store values directly, they
|
||||
// are just key continars for more value containers, which are the
|
||||
// node and edge maps.
|
||||
//
|
||||
// The node and edge sets of the graphs can be changed as we add or erase
|
||||
// nodes and edges in the graph. LEMON would like to handle easily
|
||||
// that the node and edge maps should contain values for all nodes or
|
||||
// edges. If we want to check on every indicing if the map contains
|
||||
// the current indicing key that cause a drawback in the performance
|
||||
// in the library. We use another solution: we notify all maps about
|
||||
// an alteration in the graph, which cause only drawback on the
|
||||
// alteration of the graph.
|
||||
//
|
||||
// This class provides an interface to a node or edge container.
|
||||
// The first() and next() member functions make possible
|
||||
// to iterate on the keys of the container.
|
||||
// The id() function returns an integer id for each key.
|
||||
// The maxId() function gives back an upper bound of the ids.
|
||||
//
|
||||
// For the proper functonality of this class, we should notify it
|
||||
// about each alteration in the container. The alterations have four type:
|
||||
// add(), erase(), build() and clear(). The add() and
|
||||
// erase() signal that only one or few items added or erased to or
|
||||
// from the graph. If all items are erased from the graph or if a new graph
|
||||
// is built from an empty graph, then it can be signaled with the
|
||||
// clear() and build() members. Important rule that if we erase items
|
||||
// from graphs we should first signal the alteration and after that erase
|
||||
// them from the container, on the other way on item addition we should
|
||||
// first extend the container and just after that signal the alteration.
|
||||
//
|
||||
// The alteration can be observed with a class inherited from the
|
||||
// ObserverBase nested class. The signals can be handled with
|
||||
// overriding the virtual functions defined in the base class. The
|
||||
// observer base can be attached to the notifier with the
|
||||
// attach() member and can be detached with detach() function. The
|
||||
// alteration handlers should not call any function which signals
|
||||
// an other alteration in the same notifier and should not
|
||||
// detach any observer from the notifier.
|
||||
//
|
||||
// Alteration observers try to be exception safe. If an add() or
|
||||
// a clear() function throws an exception then the remaining
|
||||
// observeres will not be notified and the fulfilled additions will
|
||||
// be rolled back by calling the erase() or clear() functions.
|
||||
// Hence erase() and clear() should not throw exception.
|
||||
// Actullay, they can throw only \ref ImmediateDetach exception,
|
||||
// which detach the observer from the notifier.
|
||||
//
|
||||
// There are some cases, when the alteration observing is not completly
|
||||
// reliable. If we want to carry out the node degree in the graph
|
||||
// as in the \ref InDegMap and we use the reverseArc(), then it cause
|
||||
// unreliable functionality. Because the alteration observing signals
|
||||
// only erasing and adding but not the reversing, it will stores bad
|
||||
// degrees. Apart form that the subgraph adaptors cannot even signal
|
||||
// the alterations because just a setting in the filter map can modify
|
||||
// the graph and this cannot be watched in any way.
|
||||
//
|
||||
// \param _Container The container which is observed.
|
||||
// \param _Item The item type which is obserbved.
|
||||
|
||||
template <typename _Container, typename _Item>
|
||||
class AlterationNotifier {
|
||||
public:
|
||||
|
||||
typedef True Notifier;
|
||||
|
||||
typedef _Container Container;
|
||||
typedef _Item Item;
|
||||
|
||||
// \brief Exception which can be called from clear() and
|
||||
// erase().
|
||||
//
|
||||
// From the clear() and erase() function only this
|
||||
// exception is allowed to throw. The exception immediatly
|
||||
// detaches the current observer from the notifier. Because the
|
||||
// clear() and erase() should not throw other exceptions
|
||||
// it can be used to invalidate the observer.
|
||||
struct ImmediateDetach {};
|
||||
|
||||
// \brief ObserverBase is the base class for the observers.
|
||||
//
|
||||
// ObserverBase is the abstract base class for the observers.
|
||||
// It will be notified about an item was inserted into or
|
||||
// erased from the graph.
|
||||
//
|
||||
// The observer interface contains some pure virtual functions
|
||||
// to override. The add() and erase() functions are
|
||||
// to notify the oberver when one item is added or erased.
|
||||
//
|
||||
// The build() and clear() members are to notify the observer
|
||||
// about the container is built from an empty container or
|
||||
// is cleared to an empty container.
|
||||
class ObserverBase {
|
||||
protected:
|
||||
typedef AlterationNotifier Notifier;
|
||||
|
||||
friend class AlterationNotifier;
|
||||
|
||||
// \brief Default constructor.
|
||||
//
|
||||
// Default constructor for ObserverBase.
|
||||
ObserverBase() : _notifier(0) {}
|
||||
|
||||
// \brief Constructor which attach the observer into notifier.
|
||||
//
|
||||
// Constructor which attach the observer into notifier.
|
||||
ObserverBase(AlterationNotifier& nf) {
|
||||
attach(nf);
|
||||
}
|
||||
|
||||
// \brief Constructor which attach the obserever to the same notifier.
|
||||
//
|
||||
// Constructor which attach the obserever to the same notifier as
|
||||
// the other observer is attached to.
|
||||
ObserverBase(const ObserverBase& copy) {
|
||||
if (copy.attached()) {
|
||||
attach(*copy.notifier());
|
||||
}
|
||||
}
|
||||
|
||||
// \brief Destructor
|
||||
virtual ~ObserverBase() {
|
||||
if (attached()) {
|
||||
detach();
|
||||
}
|
||||
}
|
||||
|
||||
// \brief Attaches the observer into an AlterationNotifier.
|
||||
//
|
||||
// This member attaches the observer into an AlterationNotifier.
|
||||
void attach(AlterationNotifier& nf) {
|
||||
nf.attach(*this);
|
||||
}
|
||||
|
||||
// \brief Detaches the observer into an AlterationNotifier.
|
||||
//
|
||||
// This member detaches the observer from an AlterationNotifier.
|
||||
void detach() {
|
||||
_notifier->detach(*this);
|
||||
}
|
||||
|
||||
// \brief Gives back a pointer to the notifier which the map
|
||||
// attached into.
|
||||
//
|
||||
// This function gives back a pointer to the notifier which the map
|
||||
// attached into.
|
||||
Notifier* notifier() const { return const_cast<Notifier*>(_notifier); }
|
||||
|
||||
// Gives back true when the observer is attached into a notifier.
|
||||
bool attached() const { return _notifier != 0; }
|
||||
|
||||
private:
|
||||
|
||||
ObserverBase& operator=(const ObserverBase& copy);
|
||||
|
||||
protected:
|
||||
|
||||
Notifier* _notifier;
|
||||
typename std::list<ObserverBase*>::iterator _index;
|
||||
|
||||
// \brief The member function to notificate the observer about an
|
||||
// item is added to the container.
|
||||
//
|
||||
// The add() member function notificates the observer about an item
|
||||
// is added to the container. It have to be overrided in the
|
||||
// subclasses.
|
||||
virtual void add(const Item&) = 0;
|
||||
|
||||
// \brief The member function to notificate the observer about
|
||||
// more item is added to the container.
|
||||
//
|
||||
// The add() member function notificates the observer about more item
|
||||
// is added to the container. It have to be overrided in the
|
||||
// subclasses.
|
||||
virtual void add(const std::vector<Item>& items) = 0;
|
||||
|
||||
// \brief The member function to notificate the observer about an
|
||||
// item is erased from the container.
|
||||
//
|
||||
// The erase() member function notificates the observer about an
|
||||
// item is erased from the container. It have to be overrided in
|
||||
// the subclasses.
|
||||
virtual void erase(const Item&) = 0;
|
||||
|
||||
// \brief The member function to notificate the observer about
|
||||
// more item is erased from the container.
|
||||
//
|
||||
// The erase() member function notificates the observer about more item
|
||||
// is erased from the container. It have to be overrided in the
|
||||
// subclasses.
|
||||
virtual void erase(const std::vector<Item>& items) = 0;
|
||||
|
||||
// \brief The member function to notificate the observer about the
|
||||
// container is built.
|
||||
//
|
||||
// The build() member function notificates the observer about the
|
||||
// container is built from an empty container. It have to be
|
||||
// overrided in the subclasses.
|
||||
virtual void build() = 0;
|
||||
|
||||
// \brief The member function to notificate the observer about all
|
||||
// items are erased from the container.
|
||||
//
|
||||
// The clear() member function notificates the observer about all
|
||||
// items are erased from the container. It have to be overrided in
|
||||
// the subclasses.
|
||||
virtual void clear() = 0;
|
||||
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
const Container* container;
|
||||
|
||||
typedef std::list<ObserverBase*> Observers;
|
||||
Observers _observers;
|
||||
lemon::bits::Lock _lock;
|
||||
|
||||
public:
|
||||
|
||||
// \brief Default constructor.
|
||||
//
|
||||
// The default constructor of the AlterationNotifier.
|
||||
// It creates an empty notifier.
|
||||
AlterationNotifier()
|
||||
: container(0) {}
|
||||
|
||||
// \brief Constructor.
|
||||
//
|
||||
// Constructor with the observed container parameter.
|
||||
AlterationNotifier(const Container& _container)
|
||||
: container(&_container) {}
|
||||
|
||||
// \brief Copy Constructor of the AlterationNotifier.
|
||||
//
|
||||
// Copy constructor of the AlterationNotifier.
|
||||
// It creates only an empty notifier because the copiable
|
||||
// notifier's observers have to be registered still into that notifier.
|
||||
AlterationNotifier(const AlterationNotifier& _notifier)
|
||||
: container(_notifier.container) {}
|
||||
|
||||
// \brief Destructor.
|
||||
//
|
||||
// Destructor of the AlterationNotifier.
|
||||
~AlterationNotifier() {
|
||||
typename Observers::iterator it;
|
||||
for (it = _observers.begin(); it != _observers.end(); ++it) {
|
||||
(*it)->_notifier = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// \brief Sets the container.
|
||||
//
|
||||
// Sets the container.
|
||||
void setContainer(const Container& _container) {
|
||||
container = &_container;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
AlterationNotifier& operator=(const AlterationNotifier&);
|
||||
|
||||
public:
|
||||
|
||||
// \brief First item in the container.
|
||||
//
|
||||
// Returns the first item in the container. It is
|
||||
// for start the iteration on the container.
|
||||
void first(Item& item) const {
|
||||
container->first(item);
|
||||
}
|
||||
|
||||
// \brief Next item in the container.
|
||||
//
|
||||
// Returns the next item in the container. It is
|
||||
// for iterate on the container.
|
||||
void next(Item& item) const {
|
||||
container->next(item);
|
||||
}
|
||||
|
||||
// \brief Returns the id of the item.
|
||||
//
|
||||
// Returns the id of the item provided by the container.
|
||||
int id(const Item& item) const {
|
||||
return container->id(item);
|
||||
}
|
||||
|
||||
// \brief Returns the maximum id of the container.
|
||||
//
|
||||
// Returns the maximum id of the container.
|
||||
int maxId() const {
|
||||
return container->maxId(Item());
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void attach(ObserverBase& observer) {
|
||||
_lock.lock();
|
||||
observer._index = _observers.insert(_observers.begin(), &observer);
|
||||
observer._notifier = this;
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
void detach(ObserverBase& observer) {
|
||||
_lock.lock();
|
||||
_observers.erase(observer._index);
|
||||
observer._index = _observers.end();
|
||||
observer._notifier = 0;
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// \brief Notifies all the registed observers about an item added to
|
||||
// the container.
|
||||
//
|
||||
// It notifies all the registed observers about an item added to
|
||||
// the container.
|
||||
void add(const Item& item) {
|
||||
typename Observers::reverse_iterator it;
|
||||
try {
|
||||
for (it = _observers.rbegin(); it != _observers.rend(); ++it) {
|
||||
(*it)->add(item);
|
||||
}
|
||||
} catch (...) {
|
||||
typename Observers::iterator jt;
|
||||
for (jt = it.base(); jt != _observers.end(); ++jt) {
|
||||
(*jt)->erase(item);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// \brief Notifies all the registed observers about more item added to
|
||||
// the container.
|
||||
//
|
||||
// It notifies all the registed observers about more item added to
|
||||
// the container.
|
||||
void add(const std::vector<Item>& items) {
|
||||
typename Observers::reverse_iterator it;
|
||||
try {
|
||||
for (it = _observers.rbegin(); it != _observers.rend(); ++it) {
|
||||
(*it)->add(items);
|
||||
}
|
||||
} catch (...) {
|
||||
typename Observers::iterator jt;
|
||||
for (jt = it.base(); jt != _observers.end(); ++jt) {
|
||||
(*jt)->erase(items);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// \brief Notifies all the registed observers about an item erased from
|
||||
// the container.
|
||||
//
|
||||
// It notifies all the registed observers about an item erased from
|
||||
// the container.
|
||||
void erase(const Item& item) throw() {
|
||||
typename Observers::iterator it = _observers.begin();
|
||||
while (it != _observers.end()) {
|
||||
try {
|
||||
(*it)->erase(item);
|
||||
++it;
|
||||
} catch (const ImmediateDetach&) {
|
||||
(*it)->_index = _observers.end();
|
||||
(*it)->_notifier = 0;
|
||||
it = _observers.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// \brief Notifies all the registed observers about more item erased
|
||||
// from the container.
|
||||
//
|
||||
// It notifies all the registed observers about more item erased from
|
||||
// the container.
|
||||
void erase(const std::vector<Item>& items) {
|
||||
typename Observers::iterator it = _observers.begin();
|
||||
while (it != _observers.end()) {
|
||||
try {
|
||||
(*it)->erase(items);
|
||||
++it;
|
||||
} catch (const ImmediateDetach&) {
|
||||
(*it)->_index = _observers.end();
|
||||
(*it)->_notifier = 0;
|
||||
it = _observers.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// \brief Notifies all the registed observers about the container is
|
||||
// built.
|
||||
//
|
||||
// Notifies all the registed observers about the container is built
|
||||
// from an empty container.
|
||||
void build() {
|
||||
typename Observers::reverse_iterator it;
|
||||
try {
|
||||
for (it = _observers.rbegin(); it != _observers.rend(); ++it) {
|
||||
(*it)->build();
|
||||
}
|
||||
} catch (...) {
|
||||
typename Observers::iterator jt;
|
||||
for (jt = it.base(); jt != _observers.end(); ++jt) {
|
||||
(*jt)->clear();
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// \brief Notifies all the registed observers about all items are
|
||||
// erased.
|
||||
//
|
||||
// Notifies all the registed observers about all items are erased
|
||||
// from the container.
|
||||
void clear() {
|
||||
typename Observers::iterator it = _observers.begin();
|
||||
while (it != _observers.end()) {
|
||||
try {
|
||||
(*it)->clear();
|
||||
++it;
|
||||
} catch (const ImmediateDetach&) {
|
||||
(*it)->_index = _observers.end();
|
||||
(*it)->_notifier = 0;
|
||||
it = _observers.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,351 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_BITS_ARRAY_MAP_H
|
||||
#define LEMON_BITS_ARRAY_MAP_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <lemon/bits/traits.h>
|
||||
#include <lemon/bits/alteration_notifier.h>
|
||||
#include <lemon/concept_check.h>
|
||||
#include <lemon/concepts/maps.h>
|
||||
|
||||
// \ingroup graphbits
|
||||
// \file
|
||||
// \brief Graph map based on the array storage.
|
||||
|
||||
namespace lemon {
|
||||
|
||||
// \ingroup graphbits
|
||||
//
|
||||
// \brief Graph map based on the array storage.
|
||||
//
|
||||
// The ArrayMap template class is graph map structure that automatically
|
||||
// updates the map when a key is added to or erased from the graph.
|
||||
// This map uses the allocators to implement the container functionality.
|
||||
//
|
||||
// The template parameters are the Graph, the current Item type and
|
||||
// the Value type of the map.
|
||||
template <typename _Graph, typename _Item, typename _Value>
|
||||
class ArrayMap
|
||||
: public ItemSetTraits<_Graph, _Item>::ItemNotifier::ObserverBase {
|
||||
public:
|
||||
// The graph type.
|
||||
typedef _Graph GraphType;
|
||||
// The item type.
|
||||
typedef _Item Item;
|
||||
// The reference map tag.
|
||||
typedef True ReferenceMapTag;
|
||||
|
||||
// The key type of the map.
|
||||
typedef _Item Key;
|
||||
// The value type of the map.
|
||||
typedef _Value Value;
|
||||
|
||||
// The const reference type of the map.
|
||||
typedef const _Value& ConstReference;
|
||||
// The reference type of the map.
|
||||
typedef _Value& Reference;
|
||||
|
||||
// The map type.
|
||||
typedef ArrayMap Map;
|
||||
|
||||
// The notifier type.
|
||||
typedef typename ItemSetTraits<_Graph, _Item>::ItemNotifier Notifier;
|
||||
|
||||
private:
|
||||
|
||||
// The MapBase of the Map which imlements the core regisitry function.
|
||||
typedef typename Notifier::ObserverBase Parent;
|
||||
|
||||
typedef std::allocator<Value> Allocator;
|
||||
|
||||
public:
|
||||
|
||||
// \brief Graph initialized map constructor.
|
||||
//
|
||||
// Graph initialized map constructor.
|
||||
explicit ArrayMap(const GraphType& graph) {
|
||||
Parent::attach(graph.notifier(Item()));
|
||||
allocate_memory();
|
||||
Notifier* nf = Parent::notifier();
|
||||
Item it;
|
||||
for (nf->first(it); it != INVALID; nf->next(it)) {
|
||||
int id = nf->id(it);;
|
||||
allocator.construct(&(values[id]), Value());
|
||||
}
|
||||
}
|
||||
|
||||
// \brief Constructor to use default value to initialize the map.
|
||||
//
|
||||
// It constructs a map and initialize all of the the map.
|
||||
ArrayMap(const GraphType& graph, const Value& value) {
|
||||
Parent::attach(graph.notifier(Item()));
|
||||
allocate_memory();
|
||||
Notifier* nf = Parent::notifier();
|
||||
Item it;
|
||||
for (nf->first(it); it != INVALID; nf->next(it)) {
|
||||
int id = nf->id(it);;
|
||||
allocator.construct(&(values[id]), value);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// \brief Constructor to copy a map of the same map type.
|
||||
//
|
||||
// Constructor to copy a map of the same map type.
|
||||
ArrayMap(const ArrayMap& copy) : Parent() {
|
||||
if (copy.attached()) {
|
||||
attach(*copy.notifier());
|
||||
}
|
||||
capacity = copy.capacity;
|
||||
if (capacity == 0) return;
|
||||
values = allocator.allocate(capacity);
|
||||
Notifier* nf = Parent::notifier();
|
||||
Item it;
|
||||
for (nf->first(it); it != INVALID; nf->next(it)) {
|
||||
int id = nf->id(it);;
|
||||
allocator.construct(&(values[id]), copy.values[id]);
|
||||
}
|
||||
}
|
||||
|
||||
// \brief Assign operator.
|
||||
//
|
||||
// This operator assigns for each item in the map the
|
||||
// value mapped to the same item in the copied map.
|
||||
// The parameter map should be indiced with the same
|
||||
// itemset because this assign operator does not change
|
||||
// the container of the map.
|
||||
ArrayMap& operator=(const ArrayMap& cmap) {
|
||||
return operator=<ArrayMap>(cmap);
|
||||
}
|
||||
|
||||
|
||||
// \brief Template assign operator.
|
||||
//
|
||||
// The given parameter should conform to the ReadMap
|
||||
// concecpt and could be indiced by the current item set of
|
||||
// the NodeMap. In this case the value for each item
|
||||
// is assigned by the value of the given ReadMap.
|
||||
template <typename CMap>
|
||||
ArrayMap& operator=(const CMap& cmap) {
|
||||
checkConcept<concepts::ReadMap<Key, _Value>, CMap>();
|
||||
const typename Parent::Notifier* nf = Parent::notifier();
|
||||
Item it;
|
||||
for (nf->first(it); it != INVALID; nf->next(it)) {
|
||||
set(it, cmap[it]);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
// \brief The destructor of the map.
|
||||
//
|
||||
// The destructor of the map.
|
||||
virtual ~ArrayMap() {
|
||||
if (attached()) {
|
||||
clear();
|
||||
detach();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
using Parent::attach;
|
||||
using Parent::detach;
|
||||
using Parent::attached;
|
||||
|
||||
public:
|
||||
|
||||
// \brief The subscript operator.
|
||||
//
|
||||
// The subscript operator. The map can be subscripted by the
|
||||
// actual keys of the graph.
|
||||
Value& operator[](const Key& key) {
|
||||
int id = Parent::notifier()->id(key);
|
||||
return values[id];
|
||||
}
|
||||
|
||||
// \brief The const subscript operator.
|
||||
//
|
||||
// The const subscript operator. The map can be subscripted by the
|
||||
// actual keys of the graph.
|
||||
const Value& operator[](const Key& key) const {
|
||||
int id = Parent::notifier()->id(key);
|
||||
return values[id];
|
||||
}
|
||||
|
||||
// \brief Setter function of the map.
|
||||
//
|
||||
// Setter function of the map. Equivalent with map[key] = val.
|
||||
// This is a compatibility feature with the not dereferable maps.
|
||||
void set(const Key& key, const Value& val) {
|
||||
(*this)[key] = val;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// \brief Adds a new key to the map.
|
||||
//
|
||||
// It adds a new key to the map. It is called by the observer notifier
|
||||
// and it overrides the add() member function of the observer base.
|
||||
virtual void add(const Key& key) {
|
||||
Notifier* nf = Parent::notifier();
|
||||
int id = nf->id(key);
|
||||
if (id >= capacity) {
|
||||
int new_capacity = (capacity == 0 ? 1 : capacity);
|
||||
while (new_capacity <= id) {
|
||||
new_capacity <<= 1;
|
||||
}
|
||||
Value* new_values = allocator.allocate(new_capacity);
|
||||
Item it;
|
||||
for (nf->first(it); it != INVALID; nf->next(it)) {
|
||||
int jd = nf->id(it);;
|
||||
if (id != jd) {
|
||||
allocator.construct(&(new_values[jd]), values[jd]);
|
||||
allocator.destroy(&(values[jd]));
|
||||
}
|
||||
}
|
||||
if (capacity != 0) allocator.deallocate(values, capacity);
|
||||
values = new_values;
|
||||
capacity = new_capacity;
|
||||
}
|
||||
allocator.construct(&(values[id]), Value());
|
||||
}
|
||||
|
||||
// \brief Adds more new keys to the map.
|
||||
//
|
||||
// It adds more new keys to the map. It is called by the observer notifier
|
||||
// and it overrides the add() member function of the observer base.
|
||||
virtual void add(const std::vector<Key>& keys) {
|
||||
Notifier* nf = Parent::notifier();
|
||||
int max_id = -1;
|
||||
for (int i = 0; i < int(keys.size()); ++i) {
|
||||
int id = nf->id(keys[i]);
|
||||
if (id > max_id) {
|
||||
max_id = id;
|
||||
}
|
||||
}
|
||||
if (max_id >= capacity) {
|
||||
int new_capacity = (capacity == 0 ? 1 : capacity);
|
||||
while (new_capacity <= max_id) {
|
||||
new_capacity <<= 1;
|
||||
}
|
||||
Value* new_values = allocator.allocate(new_capacity);
|
||||
Item it;
|
||||
for (nf->first(it); it != INVALID; nf->next(it)) {
|
||||
int id = nf->id(it);
|
||||
bool found = false;
|
||||
for (int i = 0; i < int(keys.size()); ++i) {
|
||||
int jd = nf->id(keys[i]);
|
||||
if (id == jd) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) continue;
|
||||
allocator.construct(&(new_values[id]), values[id]);
|
||||
allocator.destroy(&(values[id]));
|
||||
}
|
||||
if (capacity != 0) allocator.deallocate(values, capacity);
|
||||
values = new_values;
|
||||
capacity = new_capacity;
|
||||
}
|
||||
for (int i = 0; i < int(keys.size()); ++i) {
|
||||
int id = nf->id(keys[i]);
|
||||
allocator.construct(&(values[id]), Value());
|
||||
}
|
||||
}
|
||||
|
||||
// \brief Erase a key from the map.
|
||||
//
|
||||
// Erase a key from the map. It is called by the observer notifier
|
||||
// and it overrides the erase() member function of the observer base.
|
||||
virtual void erase(const Key& key) {
|
||||
int id = Parent::notifier()->id(key);
|
||||
allocator.destroy(&(values[id]));
|
||||
}
|
||||
|
||||
// \brief Erase more keys from the map.
|
||||
//
|
||||
// Erase more keys from the map. It is called by the observer notifier
|
||||
// and it overrides the erase() member function of the observer base.
|
||||
virtual void erase(const std::vector<Key>& keys) {
|
||||
for (int i = 0; i < int(keys.size()); ++i) {
|
||||
int id = Parent::notifier()->id(keys[i]);
|
||||
allocator.destroy(&(values[id]));
|
||||
}
|
||||
}
|
||||
|
||||
// \brief Builds the map.
|
||||
//
|
||||
// It builds the map. It is called by the observer notifier
|
||||
// and it overrides the build() member function of the observer base.
|
||||
virtual void build() {
|
||||
Notifier* nf = Parent::notifier();
|
||||
allocate_memory();
|
||||
Item it;
|
||||
for (nf->first(it); it != INVALID; nf->next(it)) {
|
||||
int id = nf->id(it);;
|
||||
allocator.construct(&(values[id]), Value());
|
||||
}
|
||||
}
|
||||
|
||||
// \brief Clear the map.
|
||||
//
|
||||
// It erase all items from the map. It is called by the observer notifier
|
||||
// and it overrides the clear() member function of the observer base.
|
||||
virtual void clear() {
|
||||
Notifier* nf = Parent::notifier();
|
||||
if (capacity != 0) {
|
||||
Item it;
|
||||
for (nf->first(it); it != INVALID; nf->next(it)) {
|
||||
int id = nf->id(it);
|
||||
allocator.destroy(&(values[id]));
|
||||
}
|
||||
allocator.deallocate(values, capacity);
|
||||
capacity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void allocate_memory() {
|
||||
int max_id = Parent::notifier()->maxId();
|
||||
if (max_id == -1) {
|
||||
capacity = 0;
|
||||
values = 0;
|
||||
return;
|
||||
}
|
||||
capacity = 1;
|
||||
while (capacity <= max_id) {
|
||||
capacity <<= 1;
|
||||
}
|
||||
values = allocator.allocate(capacity);
|
||||
}
|
||||
|
||||
int capacity;
|
||||
Value* values;
|
||||
Allocator allocator;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,174 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_BEZIER_H
|
||||
#define LEMON_BEZIER_H
|
||||
|
||||
//\ingroup misc
|
||||
//\file
|
||||
//\brief Classes to compute with Bezier curves.
|
||||
//
|
||||
//Up to now this file is used internally by \ref graph_to_eps.h
|
||||
|
||||
#include<lemon/dim2.h>
|
||||
|
||||
namespace lemon {
|
||||
namespace dim2 {
|
||||
|
||||
class BezierBase {
|
||||
public:
|
||||
typedef lemon::dim2::Point<double> Point;
|
||||
protected:
|
||||
static Point conv(Point x,Point y,double t) {return (1-t)*x+t*y;}
|
||||
};
|
||||
|
||||
class Bezier1 : public BezierBase
|
||||
{
|
||||
public:
|
||||
Point p1,p2;
|
||||
|
||||
Bezier1() {}
|
||||
Bezier1(Point _p1, Point _p2) :p1(_p1), p2(_p2) {}
|
||||
|
||||
Point operator()(double t) const
|
||||
{
|
||||
// return conv(conv(p1,p2,t),conv(p2,p3,t),t);
|
||||
return conv(p1,p2,t);
|
||||
}
|
||||
Bezier1 before(double t) const
|
||||
{
|
||||
return Bezier1(p1,conv(p1,p2,t));
|
||||
}
|
||||
|
||||
Bezier1 after(double t) const
|
||||
{
|
||||
return Bezier1(conv(p1,p2,t),p2);
|
||||
}
|
||||
|
||||
Bezier1 revert() const { return Bezier1(p2,p1);}
|
||||
Bezier1 operator()(double a,double b) const { return before(b).after(a/b); }
|
||||
Point grad() const { return p2-p1; }
|
||||
Point norm() const { return rot90(p2-p1); }
|
||||
Point grad(double) const { return grad(); }
|
||||
Point norm(double t) const { return rot90(grad(t)); }
|
||||
};
|
||||
|
||||
class Bezier2 : public BezierBase
|
||||
{
|
||||
public:
|
||||
Point p1,p2,p3;
|
||||
|
||||
Bezier2() {}
|
||||
Bezier2(Point _p1, Point _p2, Point _p3) :p1(_p1), p2(_p2), p3(_p3) {}
|
||||
Bezier2(const Bezier1 &b) : p1(b.p1), p2(conv(b.p1,b.p2,.5)), p3(b.p2) {}
|
||||
Point operator()(double t) const
|
||||
{
|
||||
// return conv(conv(p1,p2,t),conv(p2,p3,t),t);
|
||||
return ((1-t)*(1-t))*p1+(2*(1-t)*t)*p2+(t*t)*p3;
|
||||
}
|
||||
Bezier2 before(double t) const
|
||||
{
|
||||
Point q(conv(p1,p2,t));
|
||||
Point r(conv(p2,p3,t));
|
||||
return Bezier2(p1,q,conv(q,r,t));
|
||||
}
|
||||
|
||||
Bezier2 after(double t) const
|
||||
{
|
||||
Point q(conv(p1,p2,t));
|
||||
Point r(conv(p2,p3,t));
|
||||
return Bezier2(conv(q,r,t),r,p3);
|
||||
}
|
||||
Bezier2 revert() const { return Bezier2(p3,p2,p1);}
|
||||
Bezier2 operator()(double a,double b) const { return before(b).after(a/b); }
|
||||
Bezier1 grad() const { return Bezier1(2.0*(p2-p1),2.0*(p3-p2)); }
|
||||
Bezier1 norm() const { return Bezier1(2.0*rot90(p2-p1),2.0*rot90(p3-p2)); }
|
||||
Point grad(double t) const { return grad()(t); }
|
||||
Point norm(double t) const { return rot90(grad(t)); }
|
||||
};
|
||||
|
||||
class Bezier3 : public BezierBase
|
||||
{
|
||||
public:
|
||||
Point p1,p2,p3,p4;
|
||||
|
||||
Bezier3() {}
|
||||
Bezier3(Point _p1, Point _p2, Point _p3, Point _p4)
|
||||
: p1(_p1), p2(_p2), p3(_p3), p4(_p4) {}
|
||||
Bezier3(const Bezier1 &b) : p1(b.p1), p2(conv(b.p1,b.p2,1.0/3.0)),
|
||||
p3(conv(b.p1,b.p2,2.0/3.0)), p4(b.p2) {}
|
||||
Bezier3(const Bezier2 &b) : p1(b.p1), p2(conv(b.p1,b.p2,2.0/3.0)),
|
||||
p3(conv(b.p2,b.p3,1.0/3.0)), p4(b.p3) {}
|
||||
|
||||
Point operator()(double t) const
|
||||
{
|
||||
// return Bezier2(conv(p1,p2,t),conv(p2,p3,t),conv(p3,p4,t))(t);
|
||||
return ((1-t)*(1-t)*(1-t))*p1+(3*t*(1-t)*(1-t))*p2+
|
||||
(3*t*t*(1-t))*p3+(t*t*t)*p4;
|
||||
}
|
||||
Bezier3 before(double t) const
|
||||
{
|
||||
Point p(conv(p1,p2,t));
|
||||
Point q(conv(p2,p3,t));
|
||||
Point r(conv(p3,p4,t));
|
||||
Point a(conv(p,q,t));
|
||||
Point b(conv(q,r,t));
|
||||
Point c(conv(a,b,t));
|
||||
return Bezier3(p1,p,a,c);
|
||||
}
|
||||
|
||||
Bezier3 after(double t) const
|
||||
{
|
||||
Point p(conv(p1,p2,t));
|
||||
Point q(conv(p2,p3,t));
|
||||
Point r(conv(p3,p4,t));
|
||||
Point a(conv(p,q,t));
|
||||
Point b(conv(q,r,t));
|
||||
Point c(conv(a,b,t));
|
||||
return Bezier3(c,b,r,p4);
|
||||
}
|
||||
Bezier3 revert() const { return Bezier3(p4,p3,p2,p1);}
|
||||
Bezier3 operator()(double a,double b) const { return before(b).after(a/b); }
|
||||
Bezier2 grad() const { return Bezier2(3.0*(p2-p1),3.0*(p3-p2),3.0*(p4-p3)); }
|
||||
Bezier2 norm() const { return Bezier2(3.0*rot90(p2-p1),
|
||||
3.0*rot90(p3-p2),
|
||||
3.0*rot90(p4-p3)); }
|
||||
Point grad(double t) const { return grad()(t); }
|
||||
Point norm(double t) const { return rot90(grad(t)); }
|
||||
|
||||
template<class R,class F,class S,class D>
|
||||
R recSplit(F &_f,const S &_s,D _d) const
|
||||
{
|
||||
const Point a=(p1+p2)/2;
|
||||
const Point b=(p2+p3)/2;
|
||||
const Point c=(p3+p4)/2;
|
||||
const Point d=(a+b)/2;
|
||||
const Point e=(b+c)/2;
|
||||
// const Point f=(d+e)/2;
|
||||
R f1=_f(Bezier3(p1,a,d,e),_d);
|
||||
R f2=_f(Bezier3(e,d,c,p4),_d);
|
||||
return _s(f1,f2);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
} //END OF NAMESPACE dim2
|
||||
} //END OF NAMESPACE lemon
|
||||
|
||||
#endif // LEMON_BEZIER_H
|
|
@ -0,0 +1,182 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_BITS_DEFAULT_MAP_H
|
||||
#define LEMON_BITS_DEFAULT_MAP_H
|
||||
|
||||
#include <lemon/config.h>
|
||||
#include <lemon/bits/array_map.h>
|
||||
#include <lemon/bits/vector_map.h>
|
||||
//#include <lemon/bits/debug_map.h>
|
||||
|
||||
//\ingroup graphbits
|
||||
//\file
|
||||
//\brief Graph maps that construct and destruct their elements dynamically.
|
||||
|
||||
namespace lemon {
|
||||
|
||||
|
||||
//#ifndef LEMON_USE_DEBUG_MAP
|
||||
|
||||
template <typename _Graph, typename _Item, typename _Value>
|
||||
struct DefaultMapSelector {
|
||||
typedef ArrayMap<_Graph, _Item, _Value> Map;
|
||||
};
|
||||
|
||||
// bool
|
||||
template <typename _Graph, typename _Item>
|
||||
struct DefaultMapSelector<_Graph, _Item, bool> {
|
||||
typedef VectorMap<_Graph, _Item, bool> Map;
|
||||
};
|
||||
|
||||
// char
|
||||
template <typename _Graph, typename _Item>
|
||||
struct DefaultMapSelector<_Graph, _Item, char> {
|
||||
typedef VectorMap<_Graph, _Item, char> Map;
|
||||
};
|
||||
|
||||
template <typename _Graph, typename _Item>
|
||||
struct DefaultMapSelector<_Graph, _Item, signed char> {
|
||||
typedef VectorMap<_Graph, _Item, signed char> Map;
|
||||
};
|
||||
|
||||
template <typename _Graph, typename _Item>
|
||||
struct DefaultMapSelector<_Graph, _Item, unsigned char> {
|
||||
typedef VectorMap<_Graph, _Item, unsigned char> Map;
|
||||
};
|
||||
|
||||
|
||||
// int
|
||||
template <typename _Graph, typename _Item>
|
||||
struct DefaultMapSelector<_Graph, _Item, signed int> {
|
||||
typedef VectorMap<_Graph, _Item, signed int> Map;
|
||||
};
|
||||
|
||||
template <typename _Graph, typename _Item>
|
||||
struct DefaultMapSelector<_Graph, _Item, unsigned int> {
|
||||
typedef VectorMap<_Graph, _Item, unsigned int> Map;
|
||||
};
|
||||
|
||||
|
||||
// short
|
||||
template <typename _Graph, typename _Item>
|
||||
struct DefaultMapSelector<_Graph, _Item, signed short> {
|
||||
typedef VectorMap<_Graph, _Item, signed short> Map;
|
||||
};
|
||||
|
||||
template <typename _Graph, typename _Item>
|
||||
struct DefaultMapSelector<_Graph, _Item, unsigned short> {
|
||||
typedef VectorMap<_Graph, _Item, unsigned short> Map;
|
||||
};
|
||||
|
||||
|
||||
// long
|
||||
template <typename _Graph, typename _Item>
|
||||
struct DefaultMapSelector<_Graph, _Item, signed long> {
|
||||
typedef VectorMap<_Graph, _Item, signed long> Map;
|
||||
};
|
||||
|
||||
template <typename _Graph, typename _Item>
|
||||
struct DefaultMapSelector<_Graph, _Item, unsigned long> {
|
||||
typedef VectorMap<_Graph, _Item, unsigned long> Map;
|
||||
};
|
||||
|
||||
|
||||
#if defined LEMON_HAVE_LONG_LONG
|
||||
|
||||
// long long
|
||||
template <typename _Graph, typename _Item>
|
||||
struct DefaultMapSelector<_Graph, _Item, signed long long> {
|
||||
typedef VectorMap<_Graph, _Item, signed long long> Map;
|
||||
};
|
||||
|
||||
template <typename _Graph, typename _Item>
|
||||
struct DefaultMapSelector<_Graph, _Item, unsigned long long> {
|
||||
typedef VectorMap<_Graph, _Item, unsigned long long> Map;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// float
|
||||
template <typename _Graph, typename _Item>
|
||||
struct DefaultMapSelector<_Graph, _Item, float> {
|
||||
typedef VectorMap<_Graph, _Item, float> Map;
|
||||
};
|
||||
|
||||
|
||||
// double
|
||||
template <typename _Graph, typename _Item>
|
||||
struct DefaultMapSelector<_Graph, _Item, double> {
|
||||
typedef VectorMap<_Graph, _Item, double> Map;
|
||||
};
|
||||
|
||||
|
||||
// long double
|
||||
template <typename _Graph, typename _Item>
|
||||
struct DefaultMapSelector<_Graph, _Item, long double> {
|
||||
typedef VectorMap<_Graph, _Item, long double> Map;
|
||||
};
|
||||
|
||||
|
||||
// pointer
|
||||
template <typename _Graph, typename _Item, typename _Ptr>
|
||||
struct DefaultMapSelector<_Graph, _Item, _Ptr*> {
|
||||
typedef VectorMap<_Graph, _Item, _Ptr*> Map;
|
||||
};
|
||||
|
||||
// #else
|
||||
|
||||
// template <typename _Graph, typename _Item, typename _Value>
|
||||
// struct DefaultMapSelector {
|
||||
// typedef DebugMap<_Graph, _Item, _Value> Map;
|
||||
// };
|
||||
|
||||
// #endif
|
||||
|
||||
// DefaultMap class
|
||||
template <typename _Graph, typename _Item, typename _Value>
|
||||
class DefaultMap
|
||||
: public DefaultMapSelector<_Graph, _Item, _Value>::Map {
|
||||
typedef typename DefaultMapSelector<_Graph, _Item, _Value>::Map Parent;
|
||||
|
||||
public:
|
||||
typedef DefaultMap<_Graph, _Item, _Value> Map;
|
||||
|
||||
typedef typename Parent::GraphType GraphType;
|
||||
typedef typename Parent::Value Value;
|
||||
|
||||
explicit DefaultMap(const GraphType& graph) : Parent(graph) {}
|
||||
DefaultMap(const GraphType& graph, const Value& value)
|
||||
: Parent(graph, value) {}
|
||||
|
||||
DefaultMap& operator=(const DefaultMap& cmap) {
|
||||
return operator=<DefaultMap>(cmap);
|
||||
}
|
||||
|
||||
template <typename CMap>
|
||||
DefaultMap& operator=(const CMap& cmap) {
|
||||
Parent::operator=(cmap);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,627 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_BITS_EDGE_SET_EXTENDER_H
|
||||
#define LEMON_BITS_EDGE_SET_EXTENDER_H
|
||||
|
||||
#include <lemon/core.h>
|
||||
#include <lemon/error.h>
|
||||
#include <lemon/bits/default_map.h>
|
||||
#include <lemon/bits/map_extender.h>
|
||||
|
||||
//\ingroup digraphbits
|
||||
//\file
|
||||
//\brief Extenders for the arc set types
|
||||
namespace lemon {
|
||||
|
||||
// \ingroup digraphbits
|
||||
//
|
||||
// \brief Extender for the ArcSets
|
||||
template <typename Base>
|
||||
class ArcSetExtender : public Base {
|
||||
typedef Base Parent;
|
||||
|
||||
public:
|
||||
|
||||
typedef ArcSetExtender Digraph;
|
||||
|
||||
// Base extensions
|
||||
|
||||
typedef typename Parent::Node Node;
|
||||
typedef typename Parent::Arc Arc;
|
||||
|
||||
int maxId(Node) const {
|
||||
return Parent::maxNodeId();
|
||||
}
|
||||
|
||||
int maxId(Arc) const {
|
||||
return Parent::maxArcId();
|
||||
}
|
||||
|
||||
Node fromId(int id, Node) const {
|
||||
return Parent::nodeFromId(id);
|
||||
}
|
||||
|
||||
Arc fromId(int id, Arc) const {
|
||||
return Parent::arcFromId(id);
|
||||
}
|
||||
|
||||
Node oppositeNode(const Node &n, const Arc &e) const {
|
||||
if (n == Parent::source(e))
|
||||
return Parent::target(e);
|
||||
else if(n==Parent::target(e))
|
||||
return Parent::source(e);
|
||||
else
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
|
||||
// Alteration notifier extensions
|
||||
|
||||
// The arc observer registry.
|
||||
typedef AlterationNotifier<ArcSetExtender, Arc> ArcNotifier;
|
||||
|
||||
protected:
|
||||
|
||||
mutable ArcNotifier arc_notifier;
|
||||
|
||||
public:
|
||||
|
||||
using Parent::notifier;
|
||||
|
||||
// Gives back the arc alteration notifier.
|
||||
ArcNotifier& notifier(Arc) const {
|
||||
return arc_notifier;
|
||||
}
|
||||
|
||||
// Iterable extensions
|
||||
|
||||
class NodeIt : public Node {
|
||||
const Digraph* digraph;
|
||||
public:
|
||||
|
||||
NodeIt() {}
|
||||
|
||||
NodeIt(Invalid i) : Node(i) { }
|
||||
|
||||
explicit NodeIt(const Digraph& _graph) : digraph(&_graph) {
|
||||
_graph.first(static_cast<Node&>(*this));
|
||||
}
|
||||
|
||||
NodeIt(const Digraph& _graph, const Node& node)
|
||||
: Node(node), digraph(&_graph) {}
|
||||
|
||||
NodeIt& operator++() {
|
||||
digraph->next(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class ArcIt : public Arc {
|
||||
const Digraph* digraph;
|
||||
public:
|
||||
|
||||
ArcIt() { }
|
||||
|
||||
ArcIt(Invalid i) : Arc(i) { }
|
||||
|
||||
explicit ArcIt(const Digraph& _graph) : digraph(&_graph) {
|
||||
_graph.first(static_cast<Arc&>(*this));
|
||||
}
|
||||
|
||||
ArcIt(const Digraph& _graph, const Arc& e) :
|
||||
Arc(e), digraph(&_graph) { }
|
||||
|
||||
ArcIt& operator++() {
|
||||
digraph->next(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class OutArcIt : public Arc {
|
||||
const Digraph* digraph;
|
||||
public:
|
||||
|
||||
OutArcIt() { }
|
||||
|
||||
OutArcIt(Invalid i) : Arc(i) { }
|
||||
|
||||
OutArcIt(const Digraph& _graph, const Node& node)
|
||||
: digraph(&_graph) {
|
||||
_graph.firstOut(*this, node);
|
||||
}
|
||||
|
||||
OutArcIt(const Digraph& _graph, const Arc& arc)
|
||||
: Arc(arc), digraph(&_graph) {}
|
||||
|
||||
OutArcIt& operator++() {
|
||||
digraph->nextOut(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class InArcIt : public Arc {
|
||||
const Digraph* digraph;
|
||||
public:
|
||||
|
||||
InArcIt() { }
|
||||
|
||||
InArcIt(Invalid i) : Arc(i) { }
|
||||
|
||||
InArcIt(const Digraph& _graph, const Node& node)
|
||||
: digraph(&_graph) {
|
||||
_graph.firstIn(*this, node);
|
||||
}
|
||||
|
||||
InArcIt(const Digraph& _graph, const Arc& arc) :
|
||||
Arc(arc), digraph(&_graph) {}
|
||||
|
||||
InArcIt& operator++() {
|
||||
digraph->nextIn(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// \brief Base node of the iterator
|
||||
//
|
||||
// Returns the base node (ie. the source in this case) of the iterator
|
||||
Node baseNode(const OutArcIt &e) const {
|
||||
return Parent::source(static_cast<const Arc&>(e));
|
||||
}
|
||||
// \brief Running node of the iterator
|
||||
//
|
||||
// Returns the running node (ie. the target in this case) of the
|
||||
// iterator
|
||||
Node runningNode(const OutArcIt &e) const {
|
||||
return Parent::target(static_cast<const Arc&>(e));
|
||||
}
|
||||
|
||||
// \brief Base node of the iterator
|
||||
//
|
||||
// Returns the base node (ie. the target in this case) of the iterator
|
||||
Node baseNode(const InArcIt &e) const {
|
||||
return Parent::target(static_cast<const Arc&>(e));
|
||||
}
|
||||
// \brief Running node of the iterator
|
||||
//
|
||||
// Returns the running node (ie. the source in this case) of the
|
||||
// iterator
|
||||
Node runningNode(const InArcIt &e) const {
|
||||
return Parent::source(static_cast<const Arc&>(e));
|
||||
}
|
||||
|
||||
using Parent::first;
|
||||
|
||||
// Mappable extension
|
||||
|
||||
template <typename _Value>
|
||||
class ArcMap
|
||||
: public MapExtender<DefaultMap<Digraph, Arc, _Value> > {
|
||||
typedef MapExtender<DefaultMap<Digraph, Arc, _Value> > Parent;
|
||||
|
||||
public:
|
||||
explicit ArcMap(const Digraph& _g)
|
||||
: Parent(_g) {}
|
||||
ArcMap(const Digraph& _g, const _Value& _v)
|
||||
: Parent(_g, _v) {}
|
||||
|
||||
ArcMap& operator=(const ArcMap& cmap) {
|
||||
return operator=<ArcMap>(cmap);
|
||||
}
|
||||
|
||||
template <typename CMap>
|
||||
ArcMap& operator=(const CMap& cmap) {
|
||||
Parent::operator=(cmap);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Alteration extension
|
||||
|
||||
Arc addArc(const Node& from, const Node& to) {
|
||||
Arc arc = Parent::addArc(from, to);
|
||||
notifier(Arc()).add(arc);
|
||||
return arc;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
notifier(Arc()).clear();
|
||||
Parent::clear();
|
||||
}
|
||||
|
||||
void erase(const Arc& arc) {
|
||||
notifier(Arc()).erase(arc);
|
||||
Parent::erase(arc);
|
||||
}
|
||||
|
||||
ArcSetExtender() {
|
||||
arc_notifier.setContainer(*this);
|
||||
}
|
||||
|
||||
~ArcSetExtender() {
|
||||
arc_notifier.clear();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
// \ingroup digraphbits
|
||||
//
|
||||
// \brief Extender for the EdgeSets
|
||||
template <typename Base>
|
||||
class EdgeSetExtender : public Base {
|
||||
typedef Base Parent;
|
||||
|
||||
public:
|
||||
|
||||
typedef EdgeSetExtender Graph;
|
||||
|
||||
typedef True UndirectedTag;
|
||||
|
||||
typedef typename Parent::Node Node;
|
||||
typedef typename Parent::Arc Arc;
|
||||
typedef typename Parent::Edge Edge;
|
||||
|
||||
int maxId(Node) const {
|
||||
return Parent::maxNodeId();
|
||||
}
|
||||
|
||||
int maxId(Arc) const {
|
||||
return Parent::maxArcId();
|
||||
}
|
||||
|
||||
int maxId(Edge) const {
|
||||
return Parent::maxEdgeId();
|
||||
}
|
||||
|
||||
Node fromId(int id, Node) const {
|
||||
return Parent::nodeFromId(id);
|
||||
}
|
||||
|
||||
Arc fromId(int id, Arc) const {
|
||||
return Parent::arcFromId(id);
|
||||
}
|
||||
|
||||
Edge fromId(int id, Edge) const {
|
||||
return Parent::edgeFromId(id);
|
||||
}
|
||||
|
||||
Node oppositeNode(const Node &n, const Edge &e) const {
|
||||
if( n == Parent::u(e))
|
||||
return Parent::v(e);
|
||||
else if( n == Parent::v(e))
|
||||
return Parent::u(e);
|
||||
else
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
Arc oppositeArc(const Arc &e) const {
|
||||
return Parent::direct(e, !Parent::direction(e));
|
||||
}
|
||||
|
||||
using Parent::direct;
|
||||
Arc direct(const Edge &e, const Node &s) const {
|
||||
return Parent::direct(e, Parent::u(e) == s);
|
||||
}
|
||||
|
||||
typedef AlterationNotifier<EdgeSetExtender, Arc> ArcNotifier;
|
||||
typedef AlterationNotifier<EdgeSetExtender, Edge> EdgeNotifier;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
mutable ArcNotifier arc_notifier;
|
||||
mutable EdgeNotifier edge_notifier;
|
||||
|
||||
public:
|
||||
|
||||
using Parent::notifier;
|
||||
|
||||
ArcNotifier& notifier(Arc) const {
|
||||
return arc_notifier;
|
||||
}
|
||||
|
||||
EdgeNotifier& notifier(Edge) const {
|
||||
return edge_notifier;
|
||||
}
|
||||
|
||||
|
||||
class NodeIt : public Node {
|
||||
const Graph* graph;
|
||||
public:
|
||||
|
||||
NodeIt() {}
|
||||
|
||||
NodeIt(Invalid i) : Node(i) { }
|
||||
|
||||
explicit NodeIt(const Graph& _graph) : graph(&_graph) {
|
||||
_graph.first(static_cast<Node&>(*this));
|
||||
}
|
||||
|
||||
NodeIt(const Graph& _graph, const Node& node)
|
||||
: Node(node), graph(&_graph) {}
|
||||
|
||||
NodeIt& operator++() {
|
||||
graph->next(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class ArcIt : public Arc {
|
||||
const Graph* graph;
|
||||
public:
|
||||
|
||||
ArcIt() { }
|
||||
|
||||
ArcIt(Invalid i) : Arc(i) { }
|
||||
|
||||
explicit ArcIt(const Graph& _graph) : graph(&_graph) {
|
||||
_graph.first(static_cast<Arc&>(*this));
|
||||
}
|
||||
|
||||
ArcIt(const Graph& _graph, const Arc& e) :
|
||||
Arc(e), graph(&_graph) { }
|
||||
|
||||
ArcIt& operator++() {
|
||||
graph->next(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class OutArcIt : public Arc {
|
||||
const Graph* graph;
|
||||
public:
|
||||
|
||||
OutArcIt() { }
|
||||
|
||||
OutArcIt(Invalid i) : Arc(i) { }
|
||||
|
||||
OutArcIt(const Graph& _graph, const Node& node)
|
||||
: graph(&_graph) {
|
||||
_graph.firstOut(*this, node);
|
||||
}
|
||||
|
||||
OutArcIt(const Graph& _graph, const Arc& arc)
|
||||
: Arc(arc), graph(&_graph) {}
|
||||
|
||||
OutArcIt& operator++() {
|
||||
graph->nextOut(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class InArcIt : public Arc {
|
||||
const Graph* graph;
|
||||
public:
|
||||
|
||||
InArcIt() { }
|
||||
|
||||
InArcIt(Invalid i) : Arc(i) { }
|
||||
|
||||
InArcIt(const Graph& _graph, const Node& node)
|
||||
: graph(&_graph) {
|
||||
_graph.firstIn(*this, node);
|
||||
}
|
||||
|
||||
InArcIt(const Graph& _graph, const Arc& arc) :
|
||||
Arc(arc), graph(&_graph) {}
|
||||
|
||||
InArcIt& operator++() {
|
||||
graph->nextIn(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class EdgeIt : public Parent::Edge {
|
||||
const Graph* graph;
|
||||
public:
|
||||
|
||||
EdgeIt() { }
|
||||
|
||||
EdgeIt(Invalid i) : Edge(i) { }
|
||||
|
||||
explicit EdgeIt(const Graph& _graph) : graph(&_graph) {
|
||||
_graph.first(static_cast<Edge&>(*this));
|
||||
}
|
||||
|
||||
EdgeIt(const Graph& _graph, const Edge& e) :
|
||||
Edge(e), graph(&_graph) { }
|
||||
|
||||
EdgeIt& operator++() {
|
||||
graph->next(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class IncEdgeIt : public Parent::Edge {
|
||||
friend class EdgeSetExtender;
|
||||
const Graph* graph;
|
||||
bool direction;
|
||||
public:
|
||||
|
||||
IncEdgeIt() { }
|
||||
|
||||
IncEdgeIt(Invalid i) : Edge(i), direction(false) { }
|
||||
|
||||
IncEdgeIt(const Graph& _graph, const Node &n) : graph(&_graph) {
|
||||
_graph.firstInc(*this, direction, n);
|
||||
}
|
||||
|
||||
IncEdgeIt(const Graph& _graph, const Edge &ue, const Node &n)
|
||||
: graph(&_graph), Edge(ue) {
|
||||
direction = (_graph.source(ue) == n);
|
||||
}
|
||||
|
||||
IncEdgeIt& operator++() {
|
||||
graph->nextInc(*this, direction);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
// \brief Base node of the iterator
|
||||
//
|
||||
// Returns the base node (ie. the source in this case) of the iterator
|
||||
Node baseNode(const OutArcIt &e) const {
|
||||
return Parent::source(static_cast<const Arc&>(e));
|
||||
}
|
||||
// \brief Running node of the iterator
|
||||
//
|
||||
// Returns the running node (ie. the target in this case) of the
|
||||
// iterator
|
||||
Node runningNode(const OutArcIt &e) const {
|
||||
return Parent::target(static_cast<const Arc&>(e));
|
||||
}
|
||||
|
||||
// \brief Base node of the iterator
|
||||
//
|
||||
// Returns the base node (ie. the target in this case) of the iterator
|
||||
Node baseNode(const InArcIt &e) const {
|
||||
return Parent::target(static_cast<const Arc&>(e));
|
||||
}
|
||||
// \brief Running node of the iterator
|
||||
//
|
||||
// Returns the running node (ie. the source in this case) of the
|
||||
// iterator
|
||||
Node runningNode(const InArcIt &e) const {
|
||||
return Parent::source(static_cast<const Arc&>(e));
|
||||
}
|
||||
|
||||
// Base node of the iterator
|
||||
//
|
||||
// Returns the base node of the iterator
|
||||
Node baseNode(const IncEdgeIt &e) const {
|
||||
return e.direction ? this->u(e) : this->v(e);
|
||||
}
|
||||
// Running node of the iterator
|
||||
//
|
||||
// Returns the running node of the iterator
|
||||
Node runningNode(const IncEdgeIt &e) const {
|
||||
return e.direction ? this->v(e) : this->u(e);
|
||||
}
|
||||
|
||||
|
||||
template <typename _Value>
|
||||
class ArcMap
|
||||
: public MapExtender<DefaultMap<Graph, Arc, _Value> > {
|
||||
typedef MapExtender<DefaultMap<Graph, Arc, _Value> > Parent;
|
||||
|
||||
public:
|
||||
explicit ArcMap(const Graph& _g)
|
||||
: Parent(_g) {}
|
||||
ArcMap(const Graph& _g, const _Value& _v)
|
||||
: Parent(_g, _v) {}
|
||||
|
||||
ArcMap& operator=(const ArcMap& cmap) {
|
||||
return operator=<ArcMap>(cmap);
|
||||
}
|
||||
|
||||
template <typename CMap>
|
||||
ArcMap& operator=(const CMap& cmap) {
|
||||
Parent::operator=(cmap);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename _Value>
|
||||
class EdgeMap
|
||||
: public MapExtender<DefaultMap<Graph, Edge, _Value> > {
|
||||
typedef MapExtender<DefaultMap<Graph, Edge, _Value> > Parent;
|
||||
|
||||
public:
|
||||
explicit EdgeMap(const Graph& _g)
|
||||
: Parent(_g) {}
|
||||
|
||||
EdgeMap(const Graph& _g, const _Value& _v)
|
||||
: Parent(_g, _v) {}
|
||||
|
||||
EdgeMap& operator=(const EdgeMap& cmap) {
|
||||
return operator=<EdgeMap>(cmap);
|
||||
}
|
||||
|
||||
template <typename CMap>
|
||||
EdgeMap& operator=(const CMap& cmap) {
|
||||
Parent::operator=(cmap);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Alteration extension
|
||||
|
||||
Edge addEdge(const Node& from, const Node& to) {
|
||||
Edge edge = Parent::addEdge(from, to);
|
||||
notifier(Edge()).add(edge);
|
||||
std::vector<Arc> arcs;
|
||||
arcs.push_back(Parent::direct(edge, true));
|
||||
arcs.push_back(Parent::direct(edge, false));
|
||||
notifier(Arc()).add(arcs);
|
||||
return edge;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
notifier(Arc()).clear();
|
||||
notifier(Edge()).clear();
|
||||
Parent::clear();
|
||||
}
|
||||
|
||||
void erase(const Edge& edge) {
|
||||
std::vector<Arc> arcs;
|
||||
arcs.push_back(Parent::direct(edge, true));
|
||||
arcs.push_back(Parent::direct(edge, false));
|
||||
notifier(Arc()).erase(arcs);
|
||||
notifier(Edge()).erase(edge);
|
||||
Parent::erase(edge);
|
||||
}
|
||||
|
||||
|
||||
EdgeSetExtender() {
|
||||
arc_notifier.setContainer(*this);
|
||||
edge_notifier.setContainer(*this);
|
||||
}
|
||||
|
||||
~EdgeSetExtender() {
|
||||
edge_notifier.clear();
|
||||
arc_notifier.clear();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,131 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2009
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
// This file contains a modified version of the enable_if library from BOOST.
|
||||
// See the appropriate copyright notice below.
|
||||
|
||||
// Boost enable_if library
|
||||
|
||||
// Copyright 2003 (c) The Trustees of Indiana University.
|
||||
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Authors: Jaakko Jarvi (jajarvi at osl.iu.edu)
|
||||
// Jeremiah Willcock (jewillco at osl.iu.edu)
|
||||
// Andrew Lumsdaine (lums at osl.iu.edu)
|
||||
|
||||
|
||||
#ifndef LEMON_BITS_ENABLE_IF_H
|
||||
#define LEMON_BITS_ENABLE_IF_H
|
||||
|
||||
//\file
|
||||
//\brief Miscellaneous basic utilities
|
||||
|
||||
namespace lemon
|
||||
{
|
||||
|
||||
// Basic type for defining "tags". A "YES" condition for \c enable_if.
|
||||
|
||||
// Basic type for defining "tags". A "YES" condition for \c enable_if.
|
||||
//
|
||||
//\sa False
|
||||
struct True {
|
||||
//\e
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
// Basic type for defining "tags". A "NO" condition for \c enable_if.
|
||||
|
||||
// Basic type for defining "tags". A "NO" condition for \c enable_if.
|
||||
//
|
||||
//\sa True
|
||||
struct False {
|
||||
//\e
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct Wrap {
|
||||
const T &value;
|
||||
Wrap(const T &t) : value(t) {}
|
||||
};
|
||||
|
||||
/**************** dummy class to avoid ambiguity ****************/
|
||||
|
||||
template<int T> struct dummy { dummy(int) {} };
|
||||
|
||||
/**************** enable_if from BOOST ****************/
|
||||
|
||||
template <typename Type, typename T = void>
|
||||
struct exists {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
|
||||
template <bool B, class T = void>
|
||||
struct enable_if_c {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct enable_if_c<false, T> {};
|
||||
|
||||
template <class Cond, class T = void>
|
||||
struct enable_if : public enable_if_c<Cond::value, T> {};
|
||||
|
||||
template <bool B, class T>
|
||||
struct lazy_enable_if_c {
|
||||
typedef typename T::type type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct lazy_enable_if_c<false, T> {};
|
||||
|
||||
template <class Cond, class T>
|
||||
struct lazy_enable_if : public lazy_enable_if_c<Cond::value, T> {};
|
||||
|
||||
|
||||
template <bool B, class T = void>
|
||||
struct disable_if_c {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct disable_if_c<true, T> {};
|
||||
|
||||
template <class Cond, class T = void>
|
||||
struct disable_if : public disable_if_c<Cond::value, T> {};
|
||||
|
||||
template <bool B, class T>
|
||||
struct lazy_disable_if_c {
|
||||
typedef typename T::type type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct lazy_disable_if_c<true, T> {};
|
||||
|
||||
template <class Cond, class T>
|
||||
struct lazy_disable_if : public lazy_disable_if_c<Cond::value, T> {};
|
||||
|
||||
} // namespace lemon
|
||||
|
||||
#endif
|
401
thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/graph_adaptor_extender.h
vendored
Executable file
401
thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/bits/graph_adaptor_extender.h
vendored
Executable file
|
@ -0,0 +1,401 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_BITS_GRAPH_ADAPTOR_EXTENDER_H
|
||||
#define LEMON_BITS_GRAPH_ADAPTOR_EXTENDER_H
|
||||
|
||||
#include <lemon/core.h>
|
||||
#include <lemon/error.h>
|
||||
|
||||
namespace lemon {
|
||||
|
||||
template <typename _Digraph>
|
||||
class DigraphAdaptorExtender : public _Digraph {
|
||||
typedef _Digraph Parent;
|
||||
|
||||
public:
|
||||
|
||||
typedef _Digraph Digraph;
|
||||
typedef DigraphAdaptorExtender Adaptor;
|
||||
|
||||
// Base extensions
|
||||
|
||||
typedef typename Parent::Node Node;
|
||||
typedef typename Parent::Arc Arc;
|
||||
|
||||
int maxId(Node) const {
|
||||
return Parent::maxNodeId();
|
||||
}
|
||||
|
||||
int maxId(Arc) const {
|
||||
return Parent::maxArcId();
|
||||
}
|
||||
|
||||
Node fromId(int id, Node) const {
|
||||
return Parent::nodeFromId(id);
|
||||
}
|
||||
|
||||
Arc fromId(int id, Arc) const {
|
||||
return Parent::arcFromId(id);
|
||||
}
|
||||
|
||||
Node oppositeNode(const Node &n, const Arc &e) const {
|
||||
if (n == Parent::source(e))
|
||||
return Parent::target(e);
|
||||
else if(n==Parent::target(e))
|
||||
return Parent::source(e);
|
||||
else
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
class NodeIt : public Node {
|
||||
const Adaptor* _adaptor;
|
||||
public:
|
||||
|
||||
NodeIt() {}
|
||||
|
||||
NodeIt(Invalid i) : Node(i) { }
|
||||
|
||||
explicit NodeIt(const Adaptor& adaptor) : _adaptor(&adaptor) {
|
||||
_adaptor->first(static_cast<Node&>(*this));
|
||||
}
|
||||
|
||||
NodeIt(const Adaptor& adaptor, const Node& node)
|
||||
: Node(node), _adaptor(&adaptor) {}
|
||||
|
||||
NodeIt& operator++() {
|
||||
_adaptor->next(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class ArcIt : public Arc {
|
||||
const Adaptor* _adaptor;
|
||||
public:
|
||||
|
||||
ArcIt() { }
|
||||
|
||||
ArcIt(Invalid i) : Arc(i) { }
|
||||
|
||||
explicit ArcIt(const Adaptor& adaptor) : _adaptor(&adaptor) {
|
||||
_adaptor->first(static_cast<Arc&>(*this));
|
||||
}
|
||||
|
||||
ArcIt(const Adaptor& adaptor, const Arc& e) :
|
||||
Arc(e), _adaptor(&adaptor) { }
|
||||
|
||||
ArcIt& operator++() {
|
||||
_adaptor->next(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class OutArcIt : public Arc {
|
||||
const Adaptor* _adaptor;
|
||||
public:
|
||||
|
||||
OutArcIt() { }
|
||||
|
||||
OutArcIt(Invalid i) : Arc(i) { }
|
||||
|
||||
OutArcIt(const Adaptor& adaptor, const Node& node)
|
||||
: _adaptor(&adaptor) {
|
||||
_adaptor->firstOut(*this, node);
|
||||
}
|
||||
|
||||
OutArcIt(const Adaptor& adaptor, const Arc& arc)
|
||||
: Arc(arc), _adaptor(&adaptor) {}
|
||||
|
||||
OutArcIt& operator++() {
|
||||
_adaptor->nextOut(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class InArcIt : public Arc {
|
||||
const Adaptor* _adaptor;
|
||||
public:
|
||||
|
||||
InArcIt() { }
|
||||
|
||||
InArcIt(Invalid i) : Arc(i) { }
|
||||
|
||||
InArcIt(const Adaptor& adaptor, const Node& node)
|
||||
: _adaptor(&adaptor) {
|
||||
_adaptor->firstIn(*this, node);
|
||||
}
|
||||
|
||||
InArcIt(const Adaptor& adaptor, const Arc& arc) :
|
||||
Arc(arc), _adaptor(&adaptor) {}
|
||||
|
||||
InArcIt& operator++() {
|
||||
_adaptor->nextIn(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Node baseNode(const OutArcIt &e) const {
|
||||
return Parent::source(e);
|
||||
}
|
||||
Node runningNode(const OutArcIt &e) const {
|
||||
return Parent::target(e);
|
||||
}
|
||||
|
||||
Node baseNode(const InArcIt &e) const {
|
||||
return Parent::target(e);
|
||||
}
|
||||
Node runningNode(const InArcIt &e) const {
|
||||
return Parent::source(e);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename _Graph>
|
||||
class GraphAdaptorExtender : public _Graph {
|
||||
typedef _Graph Parent;
|
||||
|
||||
public:
|
||||
|
||||
typedef _Graph Graph;
|
||||
typedef GraphAdaptorExtender Adaptor;
|
||||
|
||||
typedef True UndirectedTag;
|
||||
|
||||
typedef typename Parent::Node Node;
|
||||
typedef typename Parent::Arc Arc;
|
||||
typedef typename Parent::Edge Edge;
|
||||
|
||||
// Graph extension
|
||||
|
||||
int maxId(Node) const {
|
||||
return Parent::maxNodeId();
|
||||
}
|
||||
|
||||
int maxId(Arc) const {
|
||||
return Parent::maxArcId();
|
||||
}
|
||||
|
||||
int maxId(Edge) const {
|
||||
return Parent::maxEdgeId();
|
||||
}
|
||||
|
||||
Node fromId(int id, Node) const {
|
||||
return Parent::nodeFromId(id);
|
||||
}
|
||||
|
||||
Arc fromId(int id, Arc) const {
|
||||
return Parent::arcFromId(id);
|
||||
}
|
||||
|
||||
Edge fromId(int id, Edge) const {
|
||||
return Parent::edgeFromId(id);
|
||||
}
|
||||
|
||||
Node oppositeNode(const Node &n, const Edge &e) const {
|
||||
if( n == Parent::u(e))
|
||||
return Parent::v(e);
|
||||
else if( n == Parent::v(e))
|
||||
return Parent::u(e);
|
||||
else
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
Arc oppositeArc(const Arc &a) const {
|
||||
return Parent::direct(a, !Parent::direction(a));
|
||||
}
|
||||
|
||||
using Parent::direct;
|
||||
Arc direct(const Edge &e, const Node &s) const {
|
||||
return Parent::direct(e, Parent::u(e) == s);
|
||||
}
|
||||
|
||||
|
||||
class NodeIt : public Node {
|
||||
const Adaptor* _adaptor;
|
||||
public:
|
||||
|
||||
NodeIt() {}
|
||||
|
||||
NodeIt(Invalid i) : Node(i) { }
|
||||
|
||||
explicit NodeIt(const Adaptor& adaptor) : _adaptor(&adaptor) {
|
||||
_adaptor->first(static_cast<Node&>(*this));
|
||||
}
|
||||
|
||||
NodeIt(const Adaptor& adaptor, const Node& node)
|
||||
: Node(node), _adaptor(&adaptor) {}
|
||||
|
||||
NodeIt& operator++() {
|
||||
_adaptor->next(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class ArcIt : public Arc {
|
||||
const Adaptor* _adaptor;
|
||||
public:
|
||||
|
||||
ArcIt() { }
|
||||
|
||||
ArcIt(Invalid i) : Arc(i) { }
|
||||
|
||||
explicit ArcIt(const Adaptor& adaptor) : _adaptor(&adaptor) {
|
||||
_adaptor->first(static_cast<Arc&>(*this));
|
||||
}
|
||||
|
||||
ArcIt(const Adaptor& adaptor, const Arc& e) :
|
||||
Arc(e), _adaptor(&adaptor) { }
|
||||
|
||||
ArcIt& operator++() {
|
||||
_adaptor->next(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class OutArcIt : public Arc {
|
||||
const Adaptor* _adaptor;
|
||||
public:
|
||||
|
||||
OutArcIt() { }
|
||||
|
||||
OutArcIt(Invalid i) : Arc(i) { }
|
||||
|
||||
OutArcIt(const Adaptor& adaptor, const Node& node)
|
||||
: _adaptor(&adaptor) {
|
||||
_adaptor->firstOut(*this, node);
|
||||
}
|
||||
|
||||
OutArcIt(const Adaptor& adaptor, const Arc& arc)
|
||||
: Arc(arc), _adaptor(&adaptor) {}
|
||||
|
||||
OutArcIt& operator++() {
|
||||
_adaptor->nextOut(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class InArcIt : public Arc {
|
||||
const Adaptor* _adaptor;
|
||||
public:
|
||||
|
||||
InArcIt() { }
|
||||
|
||||
InArcIt(Invalid i) : Arc(i) { }
|
||||
|
||||
InArcIt(const Adaptor& adaptor, const Node& node)
|
||||
: _adaptor(&adaptor) {
|
||||
_adaptor->firstIn(*this, node);
|
||||
}
|
||||
|
||||
InArcIt(const Adaptor& adaptor, const Arc& arc) :
|
||||
Arc(arc), _adaptor(&adaptor) {}
|
||||
|
||||
InArcIt& operator++() {
|
||||
_adaptor->nextIn(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class EdgeIt : public Parent::Edge {
|
||||
const Adaptor* _adaptor;
|
||||
public:
|
||||
|
||||
EdgeIt() { }
|
||||
|
||||
EdgeIt(Invalid i) : Edge(i) { }
|
||||
|
||||
explicit EdgeIt(const Adaptor& adaptor) : _adaptor(&adaptor) {
|
||||
_adaptor->first(static_cast<Edge&>(*this));
|
||||
}
|
||||
|
||||
EdgeIt(const Adaptor& adaptor, const Edge& e) :
|
||||
Edge(e), _adaptor(&adaptor) { }
|
||||
|
||||
EdgeIt& operator++() {
|
||||
_adaptor->next(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class IncEdgeIt : public Edge {
|
||||
friend class GraphAdaptorExtender;
|
||||
const Adaptor* _adaptor;
|
||||
bool direction;
|
||||
public:
|
||||
|
||||
IncEdgeIt() { }
|
||||
|
||||
IncEdgeIt(Invalid i) : Edge(i), direction(false) { }
|
||||
|
||||
IncEdgeIt(const Adaptor& adaptor, const Node &n) : _adaptor(&adaptor) {
|
||||
_adaptor->firstInc(static_cast<Edge&>(*this), direction, n);
|
||||
}
|
||||
|
||||
IncEdgeIt(const Adaptor& adaptor, const Edge &e, const Node &n)
|
||||
: _adaptor(&adaptor), Edge(e) {
|
||||
direction = (_adaptor->u(e) == n);
|
||||
}
|
||||
|
||||
IncEdgeIt& operator++() {
|
||||
_adaptor->nextInc(*this, direction);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
Node baseNode(const OutArcIt &a) const {
|
||||
return Parent::source(a);
|
||||
}
|
||||
Node runningNode(const OutArcIt &a) const {
|
||||
return Parent::target(a);
|
||||
}
|
||||
|
||||
Node baseNode(const InArcIt &a) const {
|
||||
return Parent::target(a);
|
||||
}
|
||||
Node runningNode(const InArcIt &a) const {
|
||||
return Parent::source(a);
|
||||
}
|
||||
|
||||
Node baseNode(const IncEdgeIt &e) const {
|
||||
return e.direction ? Parent::u(e) : Parent::v(e);
|
||||
}
|
||||
Node runningNode(const IncEdgeIt &e) const {
|
||||
return e.direction ? Parent::v(e) : Parent::u(e);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,65 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_BITS_LOCK_H
|
||||
#define LEMON_BITS_LOCK_H
|
||||
|
||||
#include <lemon/config.h>
|
||||
#if defined(LEMON_USE_PTHREAD)
|
||||
#include <pthread.h>
|
||||
#elif defined(LEMON_USE_WIN32_THREADS)
|
||||
#include <lemon/bits/windows.h>
|
||||
#endif
|
||||
|
||||
namespace lemon {
|
||||
namespace bits {
|
||||
|
||||
#if defined(LEMON_USE_PTHREAD)
|
||||
class Lock {
|
||||
public:
|
||||
Lock() {
|
||||
pthread_mutex_init(&_lock, 0);
|
||||
}
|
||||
~Lock() {
|
||||
pthread_mutex_destroy(&_lock);
|
||||
}
|
||||
void lock() {
|
||||
pthread_mutex_lock(&_lock);
|
||||
}
|
||||
void unlock() {
|
||||
pthread_mutex_unlock(&_lock);
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_mutex_t _lock;
|
||||
};
|
||||
#elif defined(LEMON_USE_WIN32_THREADS)
|
||||
class Lock : public WinLock {};
|
||||
#else
|
||||
class Lock {
|
||||
public:
|
||||
Lock() {}
|
||||
~Lock() {}
|
||||
void lock() {}
|
||||
void unlock() {}
|
||||
};
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,332 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_BITS_MAP_EXTENDER_H
|
||||
#define LEMON_BITS_MAP_EXTENDER_H
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <lemon/bits/traits.h>
|
||||
|
||||
#include <lemon/concept_check.h>
|
||||
#include <lemon/concepts/maps.h>
|
||||
|
||||
//\file
|
||||
//\brief Extenders for iterable maps.
|
||||
|
||||
namespace lemon {
|
||||
|
||||
// \ingroup graphbits
|
||||
//
|
||||
// \brief Extender for maps
|
||||
template <typename _Map>
|
||||
class MapExtender : public _Map {
|
||||
typedef _Map Parent;
|
||||
typedef typename Parent::GraphType GraphType;
|
||||
|
||||
public:
|
||||
|
||||
typedef MapExtender Map;
|
||||
typedef typename Parent::Key Item;
|
||||
|
||||
typedef typename Parent::Key Key;
|
||||
typedef typename Parent::Value Value;
|
||||
typedef typename Parent::Reference Reference;
|
||||
typedef typename Parent::ConstReference ConstReference;
|
||||
|
||||
typedef typename Parent::ReferenceMapTag ReferenceMapTag;
|
||||
|
||||
class MapIt;
|
||||
class ConstMapIt;
|
||||
|
||||
friend class MapIt;
|
||||
friend class ConstMapIt;
|
||||
|
||||
public:
|
||||
|
||||
MapExtender(const GraphType& graph)
|
||||
: Parent(graph) {}
|
||||
|
||||
MapExtender(const GraphType& graph, const Value& value)
|
||||
: Parent(graph, value) {}
|
||||
|
||||
private:
|
||||
MapExtender& operator=(const MapExtender& cmap) {
|
||||
return operator=<MapExtender>(cmap);
|
||||
}
|
||||
|
||||
template <typename CMap>
|
||||
MapExtender& operator=(const CMap& cmap) {
|
||||
Parent::operator=(cmap);
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
class MapIt : public Item {
|
||||
typedef Item Parent;
|
||||
|
||||
public:
|
||||
|
||||
typedef typename Map::Value Value;
|
||||
|
||||
MapIt() : map(NULL) {}
|
||||
|
||||
MapIt(Invalid i) : Parent(i), map(NULL) {}
|
||||
|
||||
explicit MapIt(Map& _map) : map(&_map) {
|
||||
map->notifier()->first(*this);
|
||||
}
|
||||
|
||||
MapIt(const Map& _map, const Item& item)
|
||||
: Parent(item), map(&_map) {}
|
||||
|
||||
MapIt& operator++() {
|
||||
map->notifier()->next(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
typename MapTraits<Map>::ConstReturnValue operator*() const {
|
||||
return (*map)[*this];
|
||||
}
|
||||
|
||||
typename MapTraits<Map>::ReturnValue operator*() {
|
||||
return (*map)[*this];
|
||||
}
|
||||
|
||||
void set(const Value& value) {
|
||||
map->set(*this, value);
|
||||
}
|
||||
|
||||
protected:
|
||||
Map* map;
|
||||
|
||||
};
|
||||
|
||||
class ConstMapIt : public Item {
|
||||
typedef Item Parent;
|
||||
|
||||
public:
|
||||
|
||||
typedef typename Map::Value Value;
|
||||
|
||||
ConstMapIt() : map(NULL) {}
|
||||
|
||||
ConstMapIt(Invalid i) : Parent(i), map(NULL) {}
|
||||
|
||||
explicit ConstMapIt(Map& _map) : map(&_map) {
|
||||
map->notifier()->first(*this);
|
||||
}
|
||||
|
||||
ConstMapIt(const Map& _map, const Item& item)
|
||||
: Parent(item), map(_map) {}
|
||||
|
||||
ConstMapIt& operator++() {
|
||||
map->notifier()->next(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
typename MapTraits<Map>::ConstReturnValue operator*() const {
|
||||
return map[*this];
|
||||
}
|
||||
|
||||
protected:
|
||||
const Map* map;
|
||||
};
|
||||
|
||||
class ItemIt : public Item {
|
||||
typedef Item Parent;
|
||||
|
||||
public:
|
||||
ItemIt() : map(NULL) {}
|
||||
|
||||
|
||||
ItemIt(Invalid i) : Parent(i), map(NULL) {}
|
||||
|
||||
explicit ItemIt(Map& _map) : map(&_map) {
|
||||
map->notifier()->first(*this);
|
||||
}
|
||||
|
||||
ItemIt(const Map& _map, const Item& item)
|
||||
: Parent(item), map(&_map) {}
|
||||
|
||||
ItemIt& operator++() {
|
||||
map->notifier()->next(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
const Map* map;
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
// \ingroup graphbits
|
||||
//
|
||||
// \brief Extender for maps which use a subset of the items.
|
||||
template <typename _Graph, typename _Map>
|
||||
class SubMapExtender : public _Map {
|
||||
typedef _Map Parent;
|
||||
typedef _Graph GraphType;
|
||||
|
||||
public:
|
||||
|
||||
typedef SubMapExtender Map;
|
||||
typedef typename Parent::Key Item;
|
||||
|
||||
typedef typename Parent::Key Key;
|
||||
typedef typename Parent::Value Value;
|
||||
typedef typename Parent::Reference Reference;
|
||||
typedef typename Parent::ConstReference ConstReference;
|
||||
|
||||
typedef typename Parent::ReferenceMapTag ReferenceMapTag;
|
||||
|
||||
class MapIt;
|
||||
class ConstMapIt;
|
||||
|
||||
friend class MapIt;
|
||||
friend class ConstMapIt;
|
||||
|
||||
public:
|
||||
|
||||
SubMapExtender(const GraphType& _graph)
|
||||
: Parent(_graph), graph(_graph) {}
|
||||
|
||||
SubMapExtender(const GraphType& _graph, const Value& _value)
|
||||
: Parent(_graph, _value), graph(_graph) {}
|
||||
|
||||
private:
|
||||
SubMapExtender& operator=(const SubMapExtender& cmap) {
|
||||
return operator=<MapExtender>(cmap);
|
||||
}
|
||||
|
||||
template <typename CMap>
|
||||
SubMapExtender& operator=(const CMap& cmap) {
|
||||
checkConcept<concepts::ReadMap<Key, Value>, CMap>();
|
||||
Item it;
|
||||
for (graph.first(it); it != INVALID; graph.next(it)) {
|
||||
Parent::set(it, cmap[it]);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
class MapIt : public Item {
|
||||
typedef Item Parent;
|
||||
|
||||
public:
|
||||
typedef typename Map::Value Value;
|
||||
|
||||
MapIt() : map(NULL) {}
|
||||
|
||||
MapIt(Invalid i) : Parent(i), map(NULL) { }
|
||||
|
||||
explicit MapIt(Map& _map) : map(&_map) {
|
||||
map->graph.first(*this);
|
||||
}
|
||||
|
||||
MapIt(const Map& _map, const Item& item)
|
||||
: Parent(item), map(&_map) {}
|
||||
|
||||
MapIt& operator++() {
|
||||
map->graph.next(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
typename MapTraits<Map>::ConstReturnValue operator*() const {
|
||||
return (*map)[*this];
|
||||
}
|
||||
|
||||
typename MapTraits<Map>::ReturnValue operator*() {
|
||||
return (*map)[*this];
|
||||
}
|
||||
|
||||
void set(const Value& value) {
|
||||
map->set(*this, value);
|
||||
}
|
||||
|
||||
protected:
|
||||
Map* map;
|
||||
|
||||
};
|
||||
|
||||
class ConstMapIt : public Item {
|
||||
typedef Item Parent;
|
||||
|
||||
public:
|
||||
|
||||
typedef typename Map::Value Value;
|
||||
|
||||
ConstMapIt() : map(NULL) {}
|
||||
|
||||
ConstMapIt(Invalid i) : Parent(i), map(NULL) { }
|
||||
|
||||
explicit ConstMapIt(Map& _map) : map(&_map) {
|
||||
map->graph.first(*this);
|
||||
}
|
||||
|
||||
ConstMapIt(const Map& _map, const Item& item)
|
||||
: Parent(item), map(&_map) {}
|
||||
|
||||
ConstMapIt& operator++() {
|
||||
map->graph.next(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
typename MapTraits<Map>::ConstReturnValue operator*() const {
|
||||
return (*map)[*this];
|
||||
}
|
||||
|
||||
protected:
|
||||
const Map* map;
|
||||
};
|
||||
|
||||
class ItemIt : public Item {
|
||||
typedef Item Parent;
|
||||
|
||||
public:
|
||||
ItemIt() : map(NULL) {}
|
||||
|
||||
|
||||
ItemIt(Invalid i) : Parent(i), map(NULL) { }
|
||||
|
||||
explicit ItemIt(Map& _map) : map(&_map) {
|
||||
map->graph.first(*this);
|
||||
}
|
||||
|
||||
ItemIt(const Map& _map, const Item& item)
|
||||
: Parent(item), map(&_map) {}
|
||||
|
||||
ItemIt& operator++() {
|
||||
map->graph.next(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
const Map* map;
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
const GraphType& graph;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,177 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_BITS_PATH_DUMP_H
|
||||
#define LEMON_BITS_PATH_DUMP_H
|
||||
|
||||
#include <lemon/core.h>
|
||||
#include <lemon/concept_check.h>
|
||||
|
||||
namespace lemon {
|
||||
|
||||
template <typename _Digraph, typename _PredMap>
|
||||
class PredMapPath {
|
||||
public:
|
||||
typedef True RevPathTag;
|
||||
|
||||
typedef _Digraph Digraph;
|
||||
typedef typename Digraph::Arc Arc;
|
||||
typedef _PredMap PredMap;
|
||||
|
||||
PredMapPath(const Digraph& _digraph, const PredMap& _predMap,
|
||||
typename Digraph::Node _target)
|
||||
: digraph(_digraph), predMap(_predMap), target(_target) {}
|
||||
|
||||
int length() const {
|
||||
int len = 0;
|
||||
typename Digraph::Node node = target;
|
||||
typename Digraph::Arc arc;
|
||||
while ((arc = predMap[node]) != INVALID) {
|
||||
node = digraph.source(arc);
|
||||
++len;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return predMap[target] == INVALID;
|
||||
}
|
||||
|
||||
class RevArcIt {
|
||||
public:
|
||||
RevArcIt() {}
|
||||
RevArcIt(Invalid) : path(0), current(INVALID) {}
|
||||
RevArcIt(const PredMapPath& _path)
|
||||
: path(&_path), current(_path.target) {
|
||||
if (path->predMap[current] == INVALID) current = INVALID;
|
||||
}
|
||||
|
||||
operator const typename Digraph::Arc() const {
|
||||
return path->predMap[current];
|
||||
}
|
||||
|
||||
RevArcIt& operator++() {
|
||||
current = path->digraph.source(path->predMap[current]);
|
||||
if (path->predMap[current] == INVALID) current = INVALID;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const RevArcIt& e) const {
|
||||
return current == e.current;
|
||||
}
|
||||
|
||||
bool operator!=(const RevArcIt& e) const {
|
||||
return current != e.current;
|
||||
}
|
||||
|
||||
bool operator<(const RevArcIt& e) const {
|
||||
return current < e.current;
|
||||
}
|
||||
|
||||
private:
|
||||
const PredMapPath* path;
|
||||
typename Digraph::Node current;
|
||||
};
|
||||
|
||||
private:
|
||||
const Digraph& digraph;
|
||||
const PredMap& predMap;
|
||||
typename Digraph::Node target;
|
||||
};
|
||||
|
||||
|
||||
template <typename _Digraph, typename _PredMatrixMap>
|
||||
class PredMatrixMapPath {
|
||||
public:
|
||||
typedef True RevPathTag;
|
||||
|
||||
typedef _Digraph Digraph;
|
||||
typedef typename Digraph::Arc Arc;
|
||||
typedef _PredMatrixMap PredMatrixMap;
|
||||
|
||||
PredMatrixMapPath(const Digraph& _digraph,
|
||||
const PredMatrixMap& _predMatrixMap,
|
||||
typename Digraph::Node _source,
|
||||
typename Digraph::Node _target)
|
||||
: digraph(_digraph), predMatrixMap(_predMatrixMap),
|
||||
source(_source), target(_target) {}
|
||||
|
||||
int length() const {
|
||||
int len = 0;
|
||||
typename Digraph::Node node = target;
|
||||
typename Digraph::Arc arc;
|
||||
while ((arc = predMatrixMap(source, node)) != INVALID) {
|
||||
node = digraph.source(arc);
|
||||
++len;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return predMatrixMap(source, target) == INVALID;
|
||||
}
|
||||
|
||||
class RevArcIt {
|
||||
public:
|
||||
RevArcIt() {}
|
||||
RevArcIt(Invalid) : path(0), current(INVALID) {}
|
||||
RevArcIt(const PredMatrixMapPath& _path)
|
||||
: path(&_path), current(_path.target) {
|
||||
if (path->predMatrixMap(path->source, current) == INVALID)
|
||||
current = INVALID;
|
||||
}
|
||||
|
||||
operator const typename Digraph::Arc() const {
|
||||
return path->predMatrixMap(path->source, current);
|
||||
}
|
||||
|
||||
RevArcIt& operator++() {
|
||||
current =
|
||||
path->digraph.source(path->predMatrixMap(path->source, current));
|
||||
if (path->predMatrixMap(path->source, current) == INVALID)
|
||||
current = INVALID;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const RevArcIt& e) const {
|
||||
return current == e.current;
|
||||
}
|
||||
|
||||
bool operator!=(const RevArcIt& e) const {
|
||||
return current != e.current;
|
||||
}
|
||||
|
||||
bool operator<(const RevArcIt& e) const {
|
||||
return current < e.current;
|
||||
}
|
||||
|
||||
private:
|
||||
const PredMatrixMapPath* path;
|
||||
typename Digraph::Node current;
|
||||
};
|
||||
|
||||
private:
|
||||
const Digraph& digraph;
|
||||
const PredMatrixMap& predMatrixMap;
|
||||
typename Digraph::Node source;
|
||||
typename Digraph::Node target;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,194 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_BITS_SOLVER_BITS_H
|
||||
#define LEMON_BITS_SOLVER_BITS_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace lemon {
|
||||
|
||||
namespace _solver_bits {
|
||||
|
||||
class VarIndex {
|
||||
private:
|
||||
struct ItemT {
|
||||
int prev, next;
|
||||
int index;
|
||||
};
|
||||
std::vector<ItemT> items;
|
||||
int first_item, last_item, first_free_item;
|
||||
|
||||
std::vector<int> cross;
|
||||
|
||||
public:
|
||||
|
||||
VarIndex()
|
||||
: first_item(-1), last_item(-1), first_free_item(-1) {
|
||||
}
|
||||
|
||||
void clear() {
|
||||
first_item = -1;
|
||||
last_item = -1;
|
||||
first_free_item = -1;
|
||||
items.clear();
|
||||
cross.clear();
|
||||
}
|
||||
|
||||
int addIndex(int idx) {
|
||||
int n;
|
||||
if (first_free_item == -1) {
|
||||
n = items.size();
|
||||
items.push_back(ItemT());
|
||||
} else {
|
||||
n = first_free_item;
|
||||
first_free_item = items[n].next;
|
||||
if (first_free_item != -1) {
|
||||
items[first_free_item].prev = -1;
|
||||
}
|
||||
}
|
||||
items[n].index = idx;
|
||||
if (static_cast<int>(cross.size()) <= idx) {
|
||||
cross.resize(idx + 1, -1);
|
||||
}
|
||||
cross[idx] = n;
|
||||
|
||||
items[n].prev = last_item;
|
||||
items[n].next = -1;
|
||||
if (last_item != -1) {
|
||||
items[last_item].next = n;
|
||||
} else {
|
||||
first_item = n;
|
||||
}
|
||||
last_item = n;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int addIndex(int idx, int n) {
|
||||
while (n >= static_cast<int>(items.size())) {
|
||||
items.push_back(ItemT());
|
||||
items.back().prev = -1;
|
||||
items.back().next = first_free_item;
|
||||
if (first_free_item != -1) {
|
||||
items[first_free_item].prev = items.size() - 1;
|
||||
}
|
||||
first_free_item = items.size() - 1;
|
||||
}
|
||||
if (items[n].next != -1) {
|
||||
items[items[n].next].prev = items[n].prev;
|
||||
}
|
||||
if (items[n].prev != -1) {
|
||||
items[items[n].prev].next = items[n].next;
|
||||
} else {
|
||||
first_free_item = items[n].next;
|
||||
}
|
||||
|
||||
items[n].index = idx;
|
||||
if (static_cast<int>(cross.size()) <= idx) {
|
||||
cross.resize(idx + 1, -1);
|
||||
}
|
||||
cross[idx] = n;
|
||||
|
||||
items[n].prev = last_item;
|
||||
items[n].next = -1;
|
||||
if (last_item != -1) {
|
||||
items[last_item].next = n;
|
||||
} else {
|
||||
first_item = n;
|
||||
}
|
||||
last_item = n;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void eraseIndex(int idx) {
|
||||
int n = cross[idx];
|
||||
|
||||
if (items[n].prev != -1) {
|
||||
items[items[n].prev].next = items[n].next;
|
||||
} else {
|
||||
first_item = items[n].next;
|
||||
}
|
||||
if (items[n].next != -1) {
|
||||
items[items[n].next].prev = items[n].prev;
|
||||
} else {
|
||||
last_item = items[n].prev;
|
||||
}
|
||||
|
||||
if (first_free_item != -1) {
|
||||
items[first_free_item].prev = n;
|
||||
}
|
||||
items[n].next = first_free_item;
|
||||
items[n].prev = -1;
|
||||
first_free_item = n;
|
||||
|
||||
while (!cross.empty() && cross.back() == -1) {
|
||||
cross.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
int maxIndex() const {
|
||||
return cross.size() - 1;
|
||||
}
|
||||
|
||||
void shiftIndices(int idx) {
|
||||
for (int i = idx + 1; i < static_cast<int>(cross.size()); ++i) {
|
||||
cross[i - 1] = cross[i];
|
||||
if (cross[i] != -1) {
|
||||
--items[cross[i]].index;
|
||||
}
|
||||
}
|
||||
cross.back() = -1;
|
||||
cross.pop_back();
|
||||
while (!cross.empty() && cross.back() == -1) {
|
||||
cross.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void relocateIndex(int idx, int jdx) {
|
||||
cross[idx] = cross[jdx];
|
||||
items[cross[jdx]].index = idx;
|
||||
cross[jdx] = -1;
|
||||
|
||||
while (!cross.empty() && cross.back() == -1) {
|
||||
cross.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
int operator[](int idx) const {
|
||||
return cross[idx];
|
||||
}
|
||||
|
||||
int operator()(int fdx) const {
|
||||
return items[fdx].index;
|
||||
}
|
||||
|
||||
void firstItem(int& fdx) const {
|
||||
fdx = first_item;
|
||||
}
|
||||
|
||||
void nextItem(int& fdx) const {
|
||||
fdx = items[fdx].next;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,388 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_BITS_TRAITS_H
|
||||
#define LEMON_BITS_TRAITS_H
|
||||
|
||||
//\file
|
||||
//\brief Traits for graphs and maps
|
||||
//
|
||||
|
||||
#include <lemon/bits/enable_if.h>
|
||||
|
||||
namespace lemon {
|
||||
|
||||
struct InvalidType {};
|
||||
|
||||
template <typename GR, typename _Item>
|
||||
class ItemSetTraits {};
|
||||
|
||||
|
||||
template <typename GR, typename Enable = void>
|
||||
struct NodeNotifierIndicator {
|
||||
typedef InvalidType Type;
|
||||
};
|
||||
template <typename GR>
|
||||
struct NodeNotifierIndicator<
|
||||
GR,
|
||||
typename enable_if<typename GR::NodeNotifier::Notifier, void>::type
|
||||
> {
|
||||
typedef typename GR::NodeNotifier Type;
|
||||
};
|
||||
|
||||
template <typename GR>
|
||||
class ItemSetTraits<GR, typename GR::Node> {
|
||||
public:
|
||||
|
||||
typedef GR Graph;
|
||||
typedef GR Digraph;
|
||||
|
||||
typedef typename GR::Node Item;
|
||||
typedef typename GR::NodeIt ItemIt;
|
||||
|
||||
typedef typename NodeNotifierIndicator<GR>::Type ItemNotifier;
|
||||
|
||||
template <typename V>
|
||||
class Map : public GR::template NodeMap<V> {
|
||||
typedef typename GR::template NodeMap<V> Parent;
|
||||
|
||||
public:
|
||||
typedef typename GR::template NodeMap<V> Type;
|
||||
typedef typename Parent::Value Value;
|
||||
|
||||
Map(const GR& _digraph) : Parent(_digraph) {}
|
||||
Map(const GR& _digraph, const Value& _value)
|
||||
: Parent(_digraph, _value) {}
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template <typename GR, typename Enable = void>
|
||||
struct ArcNotifierIndicator {
|
||||
typedef InvalidType Type;
|
||||
};
|
||||
template <typename GR>
|
||||
struct ArcNotifierIndicator<
|
||||
GR,
|
||||
typename enable_if<typename GR::ArcNotifier::Notifier, void>::type
|
||||
> {
|
||||
typedef typename GR::ArcNotifier Type;
|
||||
};
|
||||
|
||||
template <typename GR>
|
||||
class ItemSetTraits<GR, typename GR::Arc> {
|
||||
public:
|
||||
|
||||
typedef GR Graph;
|
||||
typedef GR Digraph;
|
||||
|
||||
typedef typename GR::Arc Item;
|
||||
typedef typename GR::ArcIt ItemIt;
|
||||
|
||||
typedef typename ArcNotifierIndicator<GR>::Type ItemNotifier;
|
||||
|
||||
template <typename V>
|
||||
class Map : public GR::template ArcMap<V> {
|
||||
typedef typename GR::template ArcMap<V> Parent;
|
||||
|
||||
public:
|
||||
typedef typename GR::template ArcMap<V> Type;
|
||||
typedef typename Parent::Value Value;
|
||||
|
||||
Map(const GR& _digraph) : Parent(_digraph) {}
|
||||
Map(const GR& _digraph, const Value& _value)
|
||||
: Parent(_digraph, _value) {}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template <typename GR, typename Enable = void>
|
||||
struct EdgeNotifierIndicator {
|
||||
typedef InvalidType Type;
|
||||
};
|
||||
template <typename GR>
|
||||
struct EdgeNotifierIndicator<
|
||||
GR,
|
||||
typename enable_if<typename GR::EdgeNotifier::Notifier, void>::type
|
||||
> {
|
||||
typedef typename GR::EdgeNotifier Type;
|
||||
};
|
||||
|
||||
template <typename GR>
|
||||
class ItemSetTraits<GR, typename GR::Edge> {
|
||||
public:
|
||||
|
||||
typedef GR Graph;
|
||||
typedef GR Digraph;
|
||||
|
||||
typedef typename GR::Edge Item;
|
||||
typedef typename GR::EdgeIt ItemIt;
|
||||
|
||||
typedef typename EdgeNotifierIndicator<GR>::Type ItemNotifier;
|
||||
|
||||
template <typename V>
|
||||
class Map : public GR::template EdgeMap<V> {
|
||||
typedef typename GR::template EdgeMap<V> Parent;
|
||||
|
||||
public:
|
||||
typedef typename GR::template EdgeMap<V> Type;
|
||||
typedef typename Parent::Value Value;
|
||||
|
||||
Map(const GR& _digraph) : Parent(_digraph) {}
|
||||
Map(const GR& _digraph, const Value& _value)
|
||||
: Parent(_digraph, _value) {}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template <typename GR, typename Enable = void>
|
||||
struct RedNodeNotifierIndicator {
|
||||
typedef InvalidType Type;
|
||||
};
|
||||
template <typename GR>
|
||||
struct RedNodeNotifierIndicator<
|
||||
GR,
|
||||
typename enable_if<typename GR::RedNodeNotifier::Notifier, void>::type
|
||||
> {
|
||||
typedef typename GR::RedNodeNotifier Type;
|
||||
};
|
||||
|
||||
template <typename GR>
|
||||
class ItemSetTraits<GR, typename GR::RedNode> {
|
||||
public:
|
||||
|
||||
typedef GR BpGraph;
|
||||
typedef GR Graph;
|
||||
typedef GR Digraph;
|
||||
|
||||
typedef typename GR::RedNode Item;
|
||||
typedef typename GR::RedNodeIt ItemIt;
|
||||
|
||||
typedef typename RedNodeNotifierIndicator<GR>::Type ItemNotifier;
|
||||
|
||||
template <typename V>
|
||||
class Map : public GR::template RedNodeMap<V> {
|
||||
typedef typename GR::template RedNodeMap<V> Parent;
|
||||
|
||||
public:
|
||||
typedef typename GR::template RedNodeMap<V> Type;
|
||||
typedef typename Parent::Value Value;
|
||||
|
||||
Map(const GR& _bpgraph) : Parent(_bpgraph) {}
|
||||
Map(const GR& _bpgraph, const Value& _value)
|
||||
: Parent(_bpgraph, _value) {}
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template <typename GR, typename Enable = void>
|
||||
struct BlueNodeNotifierIndicator {
|
||||
typedef InvalidType Type;
|
||||
};
|
||||
template <typename GR>
|
||||
struct BlueNodeNotifierIndicator<
|
||||
GR,
|
||||
typename enable_if<typename GR::BlueNodeNotifier::Notifier, void>::type
|
||||
> {
|
||||
typedef typename GR::BlueNodeNotifier Type;
|
||||
};
|
||||
|
||||
template <typename GR>
|
||||
class ItemSetTraits<GR, typename GR::BlueNode> {
|
||||
public:
|
||||
|
||||
typedef GR BpGraph;
|
||||
typedef GR Graph;
|
||||
typedef GR Digraph;
|
||||
|
||||
typedef typename GR::BlueNode Item;
|
||||
typedef typename GR::BlueNodeIt ItemIt;
|
||||
|
||||
typedef typename BlueNodeNotifierIndicator<GR>::Type ItemNotifier;
|
||||
|
||||
template <typename V>
|
||||
class Map : public GR::template BlueNodeMap<V> {
|
||||
typedef typename GR::template BlueNodeMap<V> Parent;
|
||||
|
||||
public:
|
||||
typedef typename GR::template BlueNodeMap<V> Type;
|
||||
typedef typename Parent::Value Value;
|
||||
|
||||
Map(const GR& _bpgraph) : Parent(_bpgraph) {}
|
||||
Map(const GR& _bpgraph, const Value& _value)
|
||||
: Parent(_bpgraph, _value) {}
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template <typename Map, typename Enable = void>
|
||||
struct MapTraits {
|
||||
typedef False ReferenceMapTag;
|
||||
|
||||
typedef typename Map::Key Key;
|
||||
typedef typename Map::Value Value;
|
||||
|
||||
typedef Value ConstReturnValue;
|
||||
typedef Value ReturnValue;
|
||||
};
|
||||
|
||||
template <typename Map>
|
||||
struct MapTraits<
|
||||
Map, typename enable_if<typename Map::ReferenceMapTag, void>::type >
|
||||
{
|
||||
typedef True ReferenceMapTag;
|
||||
|
||||
typedef typename Map::Key Key;
|
||||
typedef typename Map::Value Value;
|
||||
|
||||
typedef typename Map::ConstReference ConstReturnValue;
|
||||
typedef typename Map::Reference ReturnValue;
|
||||
|
||||
typedef typename Map::ConstReference ConstReference;
|
||||
typedef typename Map::Reference Reference;
|
||||
};
|
||||
|
||||
template <typename MatrixMap, typename Enable = void>
|
||||
struct MatrixMapTraits {
|
||||
typedef False ReferenceMapTag;
|
||||
|
||||
typedef typename MatrixMap::FirstKey FirstKey;
|
||||
typedef typename MatrixMap::SecondKey SecondKey;
|
||||
typedef typename MatrixMap::Value Value;
|
||||
|
||||
typedef Value ConstReturnValue;
|
||||
typedef Value ReturnValue;
|
||||
};
|
||||
|
||||
template <typename MatrixMap>
|
||||
struct MatrixMapTraits<
|
||||
MatrixMap, typename enable_if<typename MatrixMap::ReferenceMapTag,
|
||||
void>::type >
|
||||
{
|
||||
typedef True ReferenceMapTag;
|
||||
|
||||
typedef typename MatrixMap::FirstKey FirstKey;
|
||||
typedef typename MatrixMap::SecondKey SecondKey;
|
||||
typedef typename MatrixMap::Value Value;
|
||||
|
||||
typedef typename MatrixMap::ConstReference ConstReturnValue;
|
||||
typedef typename MatrixMap::Reference ReturnValue;
|
||||
|
||||
typedef typename MatrixMap::ConstReference ConstReference;
|
||||
typedef typename MatrixMap::Reference Reference;
|
||||
};
|
||||
|
||||
// Indicators for the tags
|
||||
|
||||
template <typename GR, typename Enable = void>
|
||||
struct NodeNumTagIndicator {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template <typename GR>
|
||||
struct NodeNumTagIndicator<
|
||||
GR,
|
||||
typename enable_if<typename GR::NodeNumTag, void>::type
|
||||
> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template <typename GR, typename Enable = void>
|
||||
struct ArcNumTagIndicator {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template <typename GR>
|
||||
struct ArcNumTagIndicator<
|
||||
GR,
|
||||
typename enable_if<typename GR::ArcNumTag, void>::type
|
||||
> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template <typename GR, typename Enable = void>
|
||||
struct EdgeNumTagIndicator {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template <typename GR>
|
||||
struct EdgeNumTagIndicator<
|
||||
GR,
|
||||
typename enable_if<typename GR::EdgeNumTag, void>::type
|
||||
> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template <typename GR, typename Enable = void>
|
||||
struct FindArcTagIndicator {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template <typename GR>
|
||||
struct FindArcTagIndicator<
|
||||
GR,
|
||||
typename enable_if<typename GR::FindArcTag, void>::type
|
||||
> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template <typename GR, typename Enable = void>
|
||||
struct FindEdgeTagIndicator {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template <typename GR>
|
||||
struct FindEdgeTagIndicator<
|
||||
GR,
|
||||
typename enable_if<typename GR::FindEdgeTag, void>::type
|
||||
> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template <typename GR, typename Enable = void>
|
||||
struct UndirectedTagIndicator {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template <typename GR>
|
||||
struct UndirectedTagIndicator<
|
||||
GR,
|
||||
typename enable_if<typename GR::UndirectedTag, void>::type
|
||||
> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template <typename GR, typename Enable = void>
|
||||
struct BuildTagIndicator {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template <typename GR>
|
||||
struct BuildTagIndicator<
|
||||
GR,
|
||||
typename enable_if<typename GR::BuildTag, void>::type
|
||||
> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,494 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2009
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_BITS_VARIANT_H
|
||||
#define LEMON_BITS_VARIANT_H
|
||||
|
||||
#include <lemon/assert.h>
|
||||
|
||||
// \file
|
||||
// \brief Variant types
|
||||
|
||||
namespace lemon {
|
||||
|
||||
namespace _variant_bits {
|
||||
|
||||
template <int left, int right>
|
||||
struct CTMax {
|
||||
static const int value = left < right ? right : left;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
// \brief Simple Variant type for two types
|
||||
//
|
||||
// Simple Variant type for two types. The Variant type is a type-safe
|
||||
// union. C++ has strong limitations for using unions, for
|
||||
// example you cannot store a type with non-default constructor or
|
||||
// destructor in a union. This class always knowns the current
|
||||
// state of the variant and it cares for the proper construction
|
||||
// and destruction.
|
||||
template <typename _First, typename _Second>
|
||||
class BiVariant {
|
||||
public:
|
||||
|
||||
// \brief The \c First type.
|
||||
typedef _First First;
|
||||
// \brief The \c Second type.
|
||||
typedef _Second Second;
|
||||
|
||||
// \brief Constructor
|
||||
//
|
||||
// This constructor initalizes to the default value of the \c First
|
||||
// type.
|
||||
BiVariant() {
|
||||
flag = true;
|
||||
new(reinterpret_cast<First*>(data)) First();
|
||||
}
|
||||
|
||||
// \brief Constructor
|
||||
//
|
||||
// This constructor initalizes to the given value of the \c First
|
||||
// type.
|
||||
BiVariant(const First& f) {
|
||||
flag = true;
|
||||
new(reinterpret_cast<First*>(data)) First(f);
|
||||
}
|
||||
|
||||
// \brief Constructor
|
||||
//
|
||||
// This constructor initalizes to the given value of the \c
|
||||
// Second type.
|
||||
BiVariant(const Second& s) {
|
||||
flag = false;
|
||||
new(reinterpret_cast<Second*>(data)) Second(s);
|
||||
}
|
||||
|
||||
// \brief Copy constructor
|
||||
//
|
||||
// Copy constructor
|
||||
BiVariant(const BiVariant& bivariant) {
|
||||
flag = bivariant.flag;
|
||||
if (flag) {
|
||||
new(reinterpret_cast<First*>(data)) First(bivariant.first());
|
||||
} else {
|
||||
new(reinterpret_cast<Second*>(data)) Second(bivariant.second());
|
||||
}
|
||||
}
|
||||
|
||||
// \brief Destrcutor
|
||||
//
|
||||
// Destructor
|
||||
~BiVariant() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
// \brief Set to the default value of the \c First type.
|
||||
//
|
||||
// This function sets the variant to the default value of the \c
|
||||
// First type.
|
||||
BiVariant& setFirst() {
|
||||
destroy();
|
||||
flag = true;
|
||||
new(reinterpret_cast<First*>(data)) First();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// \brief Set to the given value of the \c First type.
|
||||
//
|
||||
// This function sets the variant to the given value of the \c
|
||||
// First type.
|
||||
BiVariant& setFirst(const First& f) {
|
||||
destroy();
|
||||
flag = true;
|
||||
new(reinterpret_cast<First*>(data)) First(f);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// \brief Set to the default value of the \c Second type.
|
||||
//
|
||||
// This function sets the variant to the default value of the \c
|
||||
// Second type.
|
||||
BiVariant& setSecond() {
|
||||
destroy();
|
||||
flag = false;
|
||||
new(reinterpret_cast<Second*>(data)) Second();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// \brief Set to the given value of the \c Second type.
|
||||
//
|
||||
// This function sets the variant to the given value of the \c
|
||||
// Second type.
|
||||
BiVariant& setSecond(const Second& s) {
|
||||
destroy();
|
||||
flag = false;
|
||||
new(reinterpret_cast<Second*>(data)) Second(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// \brief Operator form of the \c setFirst()
|
||||
BiVariant& operator=(const First& f) {
|
||||
return setFirst(f);
|
||||
}
|
||||
|
||||
// \brief Operator form of the \c setSecond()
|
||||
BiVariant& operator=(const Second& s) {
|
||||
return setSecond(s);
|
||||
}
|
||||
|
||||
// \brief Assign operator
|
||||
BiVariant& operator=(const BiVariant& bivariant) {
|
||||
if (this == &bivariant) return *this;
|
||||
destroy();
|
||||
flag = bivariant.flag;
|
||||
if (flag) {
|
||||
new(reinterpret_cast<First*>(data)) First(bivariant.first());
|
||||
} else {
|
||||
new(reinterpret_cast<Second*>(data)) Second(bivariant.second());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// \brief Reference to the value
|
||||
//
|
||||
// Reference to the value of the \c First type.
|
||||
// \pre The BiVariant should store value of \c First type.
|
||||
First& first() {
|
||||
LEMON_DEBUG(flag, "Variant wrong state");
|
||||
return *reinterpret_cast<First*>(data);
|
||||
}
|
||||
|
||||
// \brief Const reference to the value
|
||||
//
|
||||
// Const reference to the value of the \c First type.
|
||||
// \pre The BiVariant should store value of \c First type.
|
||||
const First& first() const {
|
||||
LEMON_DEBUG(flag, "Variant wrong state");
|
||||
return *reinterpret_cast<const First*>(data);
|
||||
}
|
||||
|
||||
// \brief Operator form of the \c first()
|
||||
operator First&() { return first(); }
|
||||
// \brief Operator form of the const \c first()
|
||||
operator const First&() const { return first(); }
|
||||
|
||||
// \brief Reference to the value
|
||||
//
|
||||
// Reference to the value of the \c Second type.
|
||||
// \pre The BiVariant should store value of \c Second type.
|
||||
Second& second() {
|
||||
LEMON_DEBUG(!flag, "Variant wrong state");
|
||||
return *reinterpret_cast<Second*>(data);
|
||||
}
|
||||
|
||||
// \brief Const reference to the value
|
||||
//
|
||||
// Const reference to the value of the \c Second type.
|
||||
// \pre The BiVariant should store value of \c Second type.
|
||||
const Second& second() const {
|
||||
LEMON_DEBUG(!flag, "Variant wrong state");
|
||||
return *reinterpret_cast<const Second*>(data);
|
||||
}
|
||||
|
||||
// \brief Operator form of the \c second()
|
||||
operator Second&() { return second(); }
|
||||
// \brief Operator form of the const \c second()
|
||||
operator const Second&() const { return second(); }
|
||||
|
||||
// \brief %True when the variant is in the first state
|
||||
//
|
||||
// %True when the variant stores value of the \c First type.
|
||||
bool firstState() const { return flag; }
|
||||
|
||||
// \brief %True when the variant is in the second state
|
||||
//
|
||||
// %True when the variant stores value of the \c Second type.
|
||||
bool secondState() const { return !flag; }
|
||||
|
||||
private:
|
||||
|
||||
void destroy() {
|
||||
if (flag) {
|
||||
reinterpret_cast<First*>(data)->~First();
|
||||
} else {
|
||||
reinterpret_cast<Second*>(data)->~Second();
|
||||
}
|
||||
}
|
||||
|
||||
char data[_variant_bits::CTMax<sizeof(First), sizeof(Second)>::value];
|
||||
bool flag;
|
||||
};
|
||||
|
||||
namespace _variant_bits {
|
||||
|
||||
template <int _idx, typename _TypeMap>
|
||||
struct Memory {
|
||||
|
||||
typedef typename _TypeMap::template Map<_idx>::Type Current;
|
||||
|
||||
static void destroy(int index, char* place) {
|
||||
if (index == _idx) {
|
||||
reinterpret_cast<Current*>(place)->~Current();
|
||||
} else {
|
||||
Memory<_idx - 1, _TypeMap>::destroy(index, place);
|
||||
}
|
||||
}
|
||||
|
||||
static void copy(int index, char* to, const char* from) {
|
||||
if (index == _idx) {
|
||||
new (reinterpret_cast<Current*>(to))
|
||||
Current(reinterpret_cast<const Current*>(from));
|
||||
} else {
|
||||
Memory<_idx - 1, _TypeMap>::copy(index, to, from);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename _TypeMap>
|
||||
struct Memory<-1, _TypeMap> {
|
||||
|
||||
static void destroy(int, char*) {
|
||||
LEMON_DEBUG(false, "Variant wrong index.");
|
||||
}
|
||||
|
||||
static void copy(int, char*, const char*) {
|
||||
LEMON_DEBUG(false, "Variant wrong index.");
|
||||
}
|
||||
};
|
||||
|
||||
template <int _idx, typename _TypeMap>
|
||||
struct Size {
|
||||
static const int value =
|
||||
CTMax<sizeof(typename _TypeMap::template Map<_idx>::Type),
|
||||
Size<_idx - 1, _TypeMap>::value>::value;
|
||||
};
|
||||
|
||||
template <typename _TypeMap>
|
||||
struct Size<0, _TypeMap> {
|
||||
static const int value =
|
||||
sizeof(typename _TypeMap::template Map<0>::Type);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// \brief Variant type
|
||||
//
|
||||
// Simple Variant type. The Variant type is a type-safe union.
|
||||
// C++ has strong limitations for using unions, for example you
|
||||
// cannot store type with non-default constructor or destructor in
|
||||
// a union. This class always knowns the current state of the
|
||||
// variant and it cares for the proper construction and
|
||||
// destruction.
|
||||
//
|
||||
// \param _num The number of the types which can be stored in the
|
||||
// variant type.
|
||||
// \param _TypeMap This class describes the types of the Variant. The
|
||||
// _TypeMap::Map<index>::Type should be a valid type for each index
|
||||
// in the range {0, 1, ..., _num - 1}. The \c VariantTypeMap is helper
|
||||
// class to define such type mappings up to 10 types.
|
||||
//
|
||||
// And the usage of the class:
|
||||
//\code
|
||||
// typedef Variant<3, VariantTypeMap<int, std::string, double> > MyVariant;
|
||||
// MyVariant var;
|
||||
// var.set<0>(12);
|
||||
// std::cout << var.get<0>() << std::endl;
|
||||
// var.set<1>("alpha");
|
||||
// std::cout << var.get<1>() << std::endl;
|
||||
// var.set<2>(0.75);
|
||||
// std::cout << var.get<2>() << std::endl;
|
||||
//\endcode
|
||||
//
|
||||
// The result of course:
|
||||
//\code
|
||||
// 12
|
||||
// alpha
|
||||
// 0.75
|
||||
//\endcode
|
||||
template <int _num, typename _TypeMap>
|
||||
class Variant {
|
||||
public:
|
||||
|
||||
static const int num = _num;
|
||||
|
||||
typedef _TypeMap TypeMap;
|
||||
|
||||
// \brief Constructor
|
||||
//
|
||||
// This constructor initalizes to the default value of the \c type
|
||||
// with 0 index.
|
||||
Variant() {
|
||||
flag = 0;
|
||||
new(reinterpret_cast<typename TypeMap::template Map<0>::Type*>(data))
|
||||
typename TypeMap::template Map<0>::Type();
|
||||
}
|
||||
|
||||
|
||||
// \brief Copy constructor
|
||||
//
|
||||
// Copy constructor
|
||||
Variant(const Variant& variant) {
|
||||
flag = variant.flag;
|
||||
_variant_bits::Memory<num - 1, TypeMap>::copy(flag, data, variant.data);
|
||||
}
|
||||
|
||||
// \brief Assign operator
|
||||
//
|
||||
// Assign operator
|
||||
Variant& operator=(const Variant& variant) {
|
||||
if (this == &variant) return *this;
|
||||
_variant_bits::Memory<num - 1, TypeMap>::
|
||||
destroy(flag, data);
|
||||
flag = variant.flag;
|
||||
_variant_bits::Memory<num - 1, TypeMap>::
|
||||
copy(flag, data, variant.data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// \brief Destrcutor
|
||||
//
|
||||
// Destructor
|
||||
~Variant() {
|
||||
_variant_bits::Memory<num - 1, TypeMap>::destroy(flag, data);
|
||||
}
|
||||
|
||||
// \brief Set to the default value of the type with \c _idx index.
|
||||
//
|
||||
// This function sets the variant to the default value of the
|
||||
// type with \c _idx index.
|
||||
template <int _idx>
|
||||
Variant& set() {
|
||||
_variant_bits::Memory<num - 1, TypeMap>::destroy(flag, data);
|
||||
flag = _idx;
|
||||
new(reinterpret_cast<typename TypeMap::template Map<_idx>::Type*>(data))
|
||||
typename TypeMap::template Map<_idx>::Type();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// \brief Set to the given value of the type with \c _idx index.
|
||||
//
|
||||
// This function sets the variant to the given value of the type
|
||||
// with \c _idx index.
|
||||
template <int _idx>
|
||||
Variant& set(const typename _TypeMap::template Map<_idx>::Type& init) {
|
||||
_variant_bits::Memory<num - 1, TypeMap>::destroy(flag, data);
|
||||
flag = _idx;
|
||||
new(reinterpret_cast<typename TypeMap::template Map<_idx>::Type*>(data))
|
||||
typename TypeMap::template Map<_idx>::Type(init);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// \brief Gets the current value of the type with \c _idx index.
|
||||
//
|
||||
// Gets the current value of the type with \c _idx index.
|
||||
template <int _idx>
|
||||
const typename TypeMap::template Map<_idx>::Type& get() const {
|
||||
LEMON_DEBUG(_idx == flag, "Variant wrong index");
|
||||
return *reinterpret_cast<const typename TypeMap::
|
||||
template Map<_idx>::Type*>(data);
|
||||
}
|
||||
|
||||
// \brief Gets the current value of the type with \c _idx index.
|
||||
//
|
||||
// Gets the current value of the type with \c _idx index.
|
||||
template <int _idx>
|
||||
typename _TypeMap::template Map<_idx>::Type& get() {
|
||||
LEMON_DEBUG(_idx == flag, "Variant wrong index");
|
||||
return *reinterpret_cast<typename TypeMap::template Map<_idx>::Type*>
|
||||
(data);
|
||||
}
|
||||
|
||||
// \brief Returns the current state of the variant.
|
||||
//
|
||||
// Returns the current state of the variant.
|
||||
int state() const {
|
||||
return flag;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
char data[_variant_bits::Size<num - 1, TypeMap>::value];
|
||||
int flag;
|
||||
};
|
||||
|
||||
namespace _variant_bits {
|
||||
|
||||
template <int _index, typename _List>
|
||||
struct Get {
|
||||
typedef typename Get<_index - 1, typename _List::Next>::Type Type;
|
||||
};
|
||||
|
||||
template <typename _List>
|
||||
struct Get<0, _List> {
|
||||
typedef typename _List::Type Type;
|
||||
};
|
||||
|
||||
struct List {};
|
||||
|
||||
template <typename _Type, typename _List>
|
||||
struct Insert {
|
||||
typedef _List Next;
|
||||
typedef _Type Type;
|
||||
};
|
||||
|
||||
template <int _idx, typename _T0, typename _T1, typename _T2,
|
||||
typename _T3, typename _T4, typename _T5, typename _T6,
|
||||
typename _T7, typename _T8, typename _T9>
|
||||
struct Mapper {
|
||||
typedef List L10;
|
||||
typedef Insert<_T9, L10> L9;
|
||||
typedef Insert<_T8, L9> L8;
|
||||
typedef Insert<_T7, L8> L7;
|
||||
typedef Insert<_T6, L7> L6;
|
||||
typedef Insert<_T5, L6> L5;
|
||||
typedef Insert<_T4, L5> L4;
|
||||
typedef Insert<_T3, L4> L3;
|
||||
typedef Insert<_T2, L3> L2;
|
||||
typedef Insert<_T1, L2> L1;
|
||||
typedef Insert<_T0, L1> L0;
|
||||
typedef typename Get<_idx, L0>::Type Type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// \brief Helper class for Variant
|
||||
//
|
||||
// Helper class to define type mappings for Variant. This class
|
||||
// converts the template parameters to be mappable by integer.
|
||||
// \see Variant
|
||||
template <
|
||||
typename _T0,
|
||||
typename _T1 = void, typename _T2 = void, typename _T3 = void,
|
||||
typename _T4 = void, typename _T5 = void, typename _T6 = void,
|
||||
typename _T7 = void, typename _T8 = void, typename _T9 = void>
|
||||
struct VariantTypeMap {
|
||||
template <int _idx>
|
||||
struct Map {
|
||||
typedef typename _variant_bits::
|
||||
Mapper<_idx, _T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9>::Type
|
||||
Type;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,244 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2009
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_BITS_VECTOR_MAP_H
|
||||
#define LEMON_BITS_VECTOR_MAP_H
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <lemon/core.h>
|
||||
#include <lemon/bits/alteration_notifier.h>
|
||||
|
||||
#include <lemon/concept_check.h>
|
||||
#include <lemon/concepts/maps.h>
|
||||
|
||||
//\ingroup graphbits
|
||||
//
|
||||
//\file
|
||||
//\brief Vector based graph maps.
|
||||
namespace lemon {
|
||||
|
||||
// \ingroup graphbits
|
||||
//
|
||||
// \brief Graph map based on the std::vector storage.
|
||||
//
|
||||
// The VectorMap template class is graph map structure that automatically
|
||||
// updates the map when a key is added to or erased from the graph.
|
||||
// This map type uses std::vector to store the values.
|
||||
//
|
||||
// \tparam _Graph The graph this map is attached to.
|
||||
// \tparam _Item The item type of the graph items.
|
||||
// \tparam _Value The value type of the map.
|
||||
template <typename _Graph, typename _Item, typename _Value>
|
||||
class VectorMap
|
||||
: public ItemSetTraits<_Graph, _Item>::ItemNotifier::ObserverBase {
|
||||
private:
|
||||
|
||||
// The container type of the map.
|
||||
typedef std::vector<_Value> Container;
|
||||
|
||||
public:
|
||||
|
||||
// The graph type of the map.
|
||||
typedef _Graph GraphType;
|
||||
// The item type of the map.
|
||||
typedef _Item Item;
|
||||
// The reference map tag.
|
||||
typedef True ReferenceMapTag;
|
||||
|
||||
// The key type of the map.
|
||||
typedef _Item Key;
|
||||
// The value type of the map.
|
||||
typedef _Value Value;
|
||||
|
||||
// The notifier type.
|
||||
typedef typename ItemSetTraits<_Graph, _Item>::ItemNotifier Notifier;
|
||||
|
||||
// The map type.
|
||||
typedef VectorMap Map;
|
||||
|
||||
// The reference type of the map;
|
||||
typedef typename Container::reference Reference;
|
||||
// The const reference type of the map;
|
||||
typedef typename Container::const_reference ConstReference;
|
||||
|
||||
private:
|
||||
|
||||
// The base class of the map.
|
||||
typedef typename Notifier::ObserverBase Parent;
|
||||
|
||||
public:
|
||||
|
||||
// \brief Constructor to attach the new map into the notifier.
|
||||
//
|
||||
// It constructs a map and attachs it into the notifier.
|
||||
// It adds all the items of the graph to the map.
|
||||
VectorMap(const GraphType& graph) {
|
||||
Parent::attach(graph.notifier(Item()));
|
||||
container.resize(Parent::notifier()->maxId() + 1);
|
||||
}
|
||||
|
||||
// \brief Constructor uses given value to initialize the map.
|
||||
//
|
||||
// It constructs a map uses a given value to initialize the map.
|
||||
// It adds all the items of the graph to the map.
|
||||
VectorMap(const GraphType& graph, const Value& value) {
|
||||
Parent::attach(graph.notifier(Item()));
|
||||
container.resize(Parent::notifier()->maxId() + 1, value);
|
||||
}
|
||||
|
||||
private:
|
||||
// \brief Copy constructor
|
||||
//
|
||||
// Copy constructor.
|
||||
VectorMap(const VectorMap& _copy) : Parent() {
|
||||
if (_copy.attached()) {
|
||||
Parent::attach(*_copy.notifier());
|
||||
container = _copy.container;
|
||||
}
|
||||
}
|
||||
|
||||
// \brief Assign operator.
|
||||
//
|
||||
// This operator assigns for each item in the map the
|
||||
// value mapped to the same item in the copied map.
|
||||
// The parameter map should be indiced with the same
|
||||
// itemset because this assign operator does not change
|
||||
// the container of the map.
|
||||
VectorMap& operator=(const VectorMap& cmap) {
|
||||
return operator=<VectorMap>(cmap);
|
||||
}
|
||||
|
||||
|
||||
// \brief Template assign operator.
|
||||
//
|
||||
// The given parameter should conform to the ReadMap
|
||||
// concecpt and could be indiced by the current item set of
|
||||
// the NodeMap. In this case the value for each item
|
||||
// is assigned by the value of the given ReadMap.
|
||||
template <typename CMap>
|
||||
VectorMap& operator=(const CMap& cmap) {
|
||||
checkConcept<concepts::ReadMap<Key, _Value>, CMap>();
|
||||
const typename Parent::Notifier* nf = Parent::notifier();
|
||||
Item it;
|
||||
for (nf->first(it); it != INVALID; nf->next(it)) {
|
||||
set(it, cmap[it]);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// \brief The subcript operator.
|
||||
//
|
||||
// The subscript operator. The map can be subscripted by the
|
||||
// actual items of the graph.
|
||||
Reference operator[](const Key& key) {
|
||||
return container[Parent::notifier()->id(key)];
|
||||
}
|
||||
|
||||
// \brief The const subcript operator.
|
||||
//
|
||||
// The const subscript operator. The map can be subscripted by the
|
||||
// actual items of the graph.
|
||||
ConstReference operator[](const Key& key) const {
|
||||
return container[Parent::notifier()->id(key)];
|
||||
}
|
||||
|
||||
|
||||
// \brief The setter function of the map.
|
||||
//
|
||||
// It the same as operator[](key) = value expression.
|
||||
void set(const Key& key, const Value& value) {
|
||||
(*this)[key] = value;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// \brief Adds a new key to the map.
|
||||
//
|
||||
// It adds a new key to the map. It is called by the observer notifier
|
||||
// and it overrides the add() member function of the observer base.
|
||||
virtual void add(const Key& key) {
|
||||
int id = Parent::notifier()->id(key);
|
||||
if (id >= int(container.size())) {
|
||||
container.resize(id + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// \brief Adds more new keys to the map.
|
||||
//
|
||||
// It adds more new keys to the map. It is called by the observer notifier
|
||||
// and it overrides the add() member function of the observer base.
|
||||
virtual void add(const std::vector<Key>& keys) {
|
||||
int max = container.size() - 1;
|
||||
for (int i = 0; i < int(keys.size()); ++i) {
|
||||
int id = Parent::notifier()->id(keys[i]);
|
||||
if (id >= max) {
|
||||
max = id;
|
||||
}
|
||||
}
|
||||
container.resize(max + 1);
|
||||
}
|
||||
|
||||
// \brief Erase a key from the map.
|
||||
//
|
||||
// Erase a key from the map. It is called by the observer notifier
|
||||
// and it overrides the erase() member function of the observer base.
|
||||
virtual void erase(const Key& key) {
|
||||
container[Parent::notifier()->id(key)] = Value();
|
||||
}
|
||||
|
||||
// \brief Erase more keys from the map.
|
||||
//
|
||||
// It erases more keys from the map. It is called by the observer notifier
|
||||
// and it overrides the erase() member function of the observer base.
|
||||
virtual void erase(const std::vector<Key>& keys) {
|
||||
for (int i = 0; i < int(keys.size()); ++i) {
|
||||
container[Parent::notifier()->id(keys[i])] = Value();
|
||||
}
|
||||
}
|
||||
|
||||
// \brief Build the map.
|
||||
//
|
||||
// It builds the map. It is called by the observer notifier
|
||||
// and it overrides the build() member function of the observer base.
|
||||
virtual void build() {
|
||||
int size = Parent::notifier()->maxId() + 1;
|
||||
container.reserve(size);
|
||||
container.resize(size);
|
||||
}
|
||||
|
||||
// \brief Clear the map.
|
||||
//
|
||||
// It erases all items from the map. It is called by the observer notifier
|
||||
// and it overrides the clear() member function of the observer base.
|
||||
virtual void clear() {
|
||||
container.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Container container;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,166 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
///\file
|
||||
///\brief Some basic non-inline functions and static global data.
|
||||
|
||||
#include<lemon/bits/windows.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#ifdef UNICODE
|
||||
#undef UNICODE
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#ifdef LOCALE_INVARIANT
|
||||
#define MY_LOCALE LOCALE_INVARIANT
|
||||
#else
|
||||
#define MY_LOCALE LOCALE_NEUTRAL
|
||||
#endif
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <ctime>
|
||||
#ifndef WIN32
|
||||
#include <sys/times.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
|
||||
namespace lemon {
|
||||
namespace bits {
|
||||
void getWinProcTimes(double &rtime,
|
||||
double &utime, double &stime,
|
||||
double &cutime, double &cstime)
|
||||
{
|
||||
#ifdef WIN32
|
||||
static const double ch = 4294967296.0e-7;
|
||||
static const double cl = 1.0e-7;
|
||||
|
||||
FILETIME system;
|
||||
GetSystemTimeAsFileTime(&system);
|
||||
rtime = ch * system.dwHighDateTime + cl * system.dwLowDateTime;
|
||||
|
||||
FILETIME create, exit, kernel, user;
|
||||
if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) {
|
||||
utime = ch * user.dwHighDateTime + cl * user.dwLowDateTime;
|
||||
stime = ch * kernel.dwHighDateTime + cl * kernel.dwLowDateTime;
|
||||
cutime = 0;
|
||||
cstime = 0;
|
||||
} else {
|
||||
rtime = 0;
|
||||
utime = 0;
|
||||
stime = 0;
|
||||
cutime = 0;
|
||||
cstime = 0;
|
||||
}
|
||||
#else
|
||||
timeval tv;
|
||||
gettimeofday(&tv, 0);
|
||||
rtime=tv.tv_sec+double(tv.tv_usec)/1e6;
|
||||
|
||||
tms ts;
|
||||
double tck=sysconf(_SC_CLK_TCK);
|
||||
times(&ts);
|
||||
utime=ts.tms_utime/tck;
|
||||
stime=ts.tms_stime/tck;
|
||||
cutime=ts.tms_cutime/tck;
|
||||
cstime=ts.tms_cstime/tck;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string getWinFormattedDate()
|
||||
{
|
||||
std::ostringstream os;
|
||||
#ifdef WIN32
|
||||
SYSTEMTIME time;
|
||||
GetSystemTime(&time);
|
||||
char buf1[11], buf2[9], buf3[5];
|
||||
if (GetDateFormat(MY_LOCALE, 0, &time,
|
||||
("ddd MMM dd"), buf1, 11) &&
|
||||
GetTimeFormat(MY_LOCALE, 0, &time,
|
||||
("HH':'mm':'ss"), buf2, 9) &&
|
||||
GetDateFormat(MY_LOCALE, 0, &time,
|
||||
("yyyy"), buf3, 5)) {
|
||||
os << buf1 << ' ' << buf2 << ' ' << buf3;
|
||||
}
|
||||
else os << "unknown";
|
||||
#else
|
||||
timeval tv;
|
||||
gettimeofday(&tv, 0);
|
||||
|
||||
char cbuf[26];
|
||||
ctime_r(&tv.tv_sec,cbuf);
|
||||
os << cbuf;
|
||||
#endif
|
||||
return os.str();
|
||||
}
|
||||
|
||||
int getWinRndSeed()
|
||||
{
|
||||
#ifdef WIN32
|
||||
FILETIME time;
|
||||
GetSystemTimeAsFileTime(&time);
|
||||
return GetCurrentProcessId() + time.dwHighDateTime + time.dwLowDateTime;
|
||||
#else
|
||||
timeval tv;
|
||||
gettimeofday(&tv, 0);
|
||||
return getpid() + tv.tv_sec + tv.tv_usec;
|
||||
#endif
|
||||
}
|
||||
|
||||
WinLock::WinLock() {
|
||||
#ifdef WIN32
|
||||
CRITICAL_SECTION *lock = new CRITICAL_SECTION;
|
||||
InitializeCriticalSection(lock);
|
||||
_repr = lock;
|
||||
#else
|
||||
_repr = 0; //Just to avoid 'unused variable' warning with clang
|
||||
#endif
|
||||
}
|
||||
|
||||
WinLock::~WinLock() {
|
||||
#ifdef WIN32
|
||||
CRITICAL_SECTION *lock = static_cast<CRITICAL_SECTION*>(_repr);
|
||||
DeleteCriticalSection(lock);
|
||||
delete lock;
|
||||
#endif
|
||||
}
|
||||
|
||||
void WinLock::lock() {
|
||||
#ifdef WIN32
|
||||
CRITICAL_SECTION *lock = static_cast<CRITICAL_SECTION*>(_repr);
|
||||
EnterCriticalSection(lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
void WinLock::unlock() {
|
||||
#ifdef WIN32
|
||||
CRITICAL_SECTION *lock = static_cast<CRITICAL_SECTION*>(_repr);
|
||||
LeaveCriticalSection(lock);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_BITS_WINDOWS_H
|
||||
#define LEMON_BITS_WINDOWS_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace lemon {
|
||||
namespace bits {
|
||||
void getWinProcTimes(double &rtime,
|
||||
double &utime, double &stime,
|
||||
double &cutime, double &cstime);
|
||||
std::string getWinFormattedDate();
|
||||
int getWinRndSeed();
|
||||
|
||||
class WinLock {
|
||||
public:
|
||||
WinLock();
|
||||
~WinLock();
|
||||
void lock();
|
||||
void unlock();
|
||||
private:
|
||||
void *_repr;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,594 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2010
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_BUCKET_HEAP_H
|
||||
#define LEMON_BUCKET_HEAP_H
|
||||
|
||||
///\ingroup heaps
|
||||
///\file
|
||||
///\brief Bucket heap implementation.
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
|
||||
namespace lemon {
|
||||
|
||||
namespace _bucket_heap_bits {
|
||||
|
||||
template <bool MIN>
|
||||
struct DirectionTraits {
|
||||
static bool less(int left, int right) {
|
||||
return left < right;
|
||||
}
|
||||
static void increase(int& value) {
|
||||
++value;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DirectionTraits<false> {
|
||||
static bool less(int left, int right) {
|
||||
return left > right;
|
||||
}
|
||||
static void increase(int& value) {
|
||||
--value;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/// \ingroup heaps
|
||||
///
|
||||
/// \brief Bucket heap data structure.
|
||||
///
|
||||
/// This class implements the \e bucket \e heap data structure.
|
||||
/// It practically conforms to the \ref concepts::Heap "heap concept",
|
||||
/// but it has some limitations.
|
||||
///
|
||||
/// The bucket heap is a very simple structure. It can store only
|
||||
/// \c int priorities and it maintains a list of items for each priority
|
||||
/// in the range <tt>[0..C)</tt>. So it should only be used when the
|
||||
/// priorities are small. It is not intended to use as a Dijkstra heap.
|
||||
///
|
||||
/// \tparam IM A read-writable item map with \c int values, used
|
||||
/// internally to handle the cross references.
|
||||
/// \tparam MIN Indicate if the heap is a \e min-heap or a \e max-heap.
|
||||
/// The default is \e min-heap. If this parameter is set to \c false,
|
||||
/// then the comparison is reversed, so the top(), prio() and pop()
|
||||
/// functions deal with the item having maximum priority instead of the
|
||||
/// minimum.
|
||||
///
|
||||
/// \sa SimpleBucketHeap
|
||||
template <typename IM, bool MIN = true>
|
||||
class BucketHeap {
|
||||
|
||||
public:
|
||||
|
||||
/// Type of the item-int map.
|
||||
typedef IM ItemIntMap;
|
||||
/// Type of the priorities.
|
||||
typedef int Prio;
|
||||
/// Type of the items stored in the heap.
|
||||
typedef typename ItemIntMap::Key Item;
|
||||
/// Type of the item-priority pairs.
|
||||
typedef std::pair<Item,Prio> Pair;
|
||||
|
||||
private:
|
||||
|
||||
typedef _bucket_heap_bits::DirectionTraits<MIN> Direction;
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Type to represent the states of the items.
|
||||
///
|
||||
/// Each item has a state associated to it. It can be "in heap",
|
||||
/// "pre-heap" or "post-heap". The latter two are indifferent from the
|
||||
/// heap's point of view, but may be useful to the user.
|
||||
///
|
||||
/// The item-int map must be initialized in such way that it assigns
|
||||
/// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
|
||||
enum State {
|
||||
IN_HEAP = 0, ///< = 0.
|
||||
PRE_HEAP = -1, ///< = -1.
|
||||
POST_HEAP = -2 ///< = -2.
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Constructor.
|
||||
///
|
||||
/// Constructor.
|
||||
/// \param map A map that assigns \c int values to the items.
|
||||
/// It is used internally to handle the cross references.
|
||||
/// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
|
||||
explicit BucketHeap(ItemIntMap &map) : _iim(map), _minimum(0) {}
|
||||
|
||||
/// \brief The number of items stored in the heap.
|
||||
///
|
||||
/// This function returns the number of items stored in the heap.
|
||||
int size() const { return _data.size(); }
|
||||
|
||||
/// \brief Check if the heap is empty.
|
||||
///
|
||||
/// This function returns \c true if the heap is empty.
|
||||
bool empty() const { return _data.empty(); }
|
||||
|
||||
/// \brief Make the heap empty.
|
||||
///
|
||||
/// This functon makes the heap empty.
|
||||
/// It does not change the cross reference map. If you want to reuse
|
||||
/// a heap that is not surely empty, you should first clear it and
|
||||
/// then you should set the cross reference map to \c PRE_HEAP
|
||||
/// for each item.
|
||||
void clear() {
|
||||
_data.clear(); _first.clear(); _minimum = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void relocateLast(int idx) {
|
||||
if (idx + 1 < int(_data.size())) {
|
||||
_data[idx] = _data.back();
|
||||
if (_data[idx].prev != -1) {
|
||||
_data[_data[idx].prev].next = idx;
|
||||
} else {
|
||||
_first[_data[idx].value] = idx;
|
||||
}
|
||||
if (_data[idx].next != -1) {
|
||||
_data[_data[idx].next].prev = idx;
|
||||
}
|
||||
_iim[_data[idx].item] = idx;
|
||||
}
|
||||
_data.pop_back();
|
||||
}
|
||||
|
||||
void unlace(int idx) {
|
||||
if (_data[idx].prev != -1) {
|
||||
_data[_data[idx].prev].next = _data[idx].next;
|
||||
} else {
|
||||
_first[_data[idx].value] = _data[idx].next;
|
||||
}
|
||||
if (_data[idx].next != -1) {
|
||||
_data[_data[idx].next].prev = _data[idx].prev;
|
||||
}
|
||||
}
|
||||
|
||||
void lace(int idx) {
|
||||
if (int(_first.size()) <= _data[idx].value) {
|
||||
_first.resize(_data[idx].value + 1, -1);
|
||||
}
|
||||
_data[idx].next = _first[_data[idx].value];
|
||||
if (_data[idx].next != -1) {
|
||||
_data[_data[idx].next].prev = idx;
|
||||
}
|
||||
_first[_data[idx].value] = idx;
|
||||
_data[idx].prev = -1;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Insert a pair of item and priority into the heap.
|
||||
///
|
||||
/// This function inserts \c p.first to the heap with priority
|
||||
/// \c p.second.
|
||||
/// \param p The pair to insert.
|
||||
/// \pre \c p.first must not be stored in the heap.
|
||||
void push(const Pair& p) {
|
||||
push(p.first, p.second);
|
||||
}
|
||||
|
||||
/// \brief Insert an item into the heap with the given priority.
|
||||
///
|
||||
/// This function inserts the given item into the heap with the
|
||||
/// given priority.
|
||||
/// \param i The item to insert.
|
||||
/// \param p The priority of the item.
|
||||
/// \pre \e i must not be stored in the heap.
|
||||
void push(const Item &i, const Prio &p) {
|
||||
int idx = _data.size();
|
||||
_iim[i] = idx;
|
||||
_data.push_back(BucketItem(i, p));
|
||||
lace(idx);
|
||||
if (Direction::less(p, _minimum)) {
|
||||
_minimum = p;
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Return the item having minimum priority.
|
||||
///
|
||||
/// This function returns the item having minimum priority.
|
||||
/// \pre The heap must be non-empty.
|
||||
Item top() const {
|
||||
while (_first[_minimum] == -1) {
|
||||
Direction::increase(_minimum);
|
||||
}
|
||||
return _data[_first[_minimum]].item;
|
||||
}
|
||||
|
||||
/// \brief The minimum priority.
|
||||
///
|
||||
/// This function returns the minimum priority.
|
||||
/// \pre The heap must be non-empty.
|
||||
Prio prio() const {
|
||||
while (_first[_minimum] == -1) {
|
||||
Direction::increase(_minimum);
|
||||
}
|
||||
return _minimum;
|
||||
}
|
||||
|
||||
/// \brief Remove the item having minimum priority.
|
||||
///
|
||||
/// This function removes the item having minimum priority.
|
||||
/// \pre The heap must be non-empty.
|
||||
void pop() {
|
||||
while (_first[_minimum] == -1) {
|
||||
Direction::increase(_minimum);
|
||||
}
|
||||
int idx = _first[_minimum];
|
||||
_iim[_data[idx].item] = -2;
|
||||
unlace(idx);
|
||||
relocateLast(idx);
|
||||
}
|
||||
|
||||
/// \brief Remove the given item from the heap.
|
||||
///
|
||||
/// This function removes the given item from the heap if it is
|
||||
/// already stored.
|
||||
/// \param i The item to delete.
|
||||
/// \pre \e i must be in the heap.
|
||||
void erase(const Item &i) {
|
||||
int idx = _iim[i];
|
||||
_iim[_data[idx].item] = -2;
|
||||
unlace(idx);
|
||||
relocateLast(idx);
|
||||
}
|
||||
|
||||
/// \brief The priority of the given item.
|
||||
///
|
||||
/// This function returns the priority of the given item.
|
||||
/// \param i The item.
|
||||
/// \pre \e i must be in the heap.
|
||||
Prio operator[](const Item &i) const {
|
||||
int idx = _iim[i];
|
||||
return _data[idx].value;
|
||||
}
|
||||
|
||||
/// \brief Set the priority of an item or insert it, if it is
|
||||
/// not stored in the heap.
|
||||
///
|
||||
/// This method sets the priority of the given item if it is
|
||||
/// already stored in the heap. Otherwise it inserts the given
|
||||
/// item into the heap with the given priority.
|
||||
/// \param i The item.
|
||||
/// \param p The priority.
|
||||
void set(const Item &i, const Prio &p) {
|
||||
int idx = _iim[i];
|
||||
if (idx < 0) {
|
||||
push(i, p);
|
||||
} else if (Direction::less(p, _data[idx].value)) {
|
||||
decrease(i, p);
|
||||
} else {
|
||||
increase(i, p);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Decrease the priority of an item to the given value.
|
||||
///
|
||||
/// This function decreases the priority of an item to the given value.
|
||||
/// \param i The item.
|
||||
/// \param p The priority.
|
||||
/// \pre \e i must be stored in the heap with priority at least \e p.
|
||||
void decrease(const Item &i, const Prio &p) {
|
||||
int idx = _iim[i];
|
||||
unlace(idx);
|
||||
_data[idx].value = p;
|
||||
if (Direction::less(p, _minimum)) {
|
||||
_minimum = p;
|
||||
}
|
||||
lace(idx);
|
||||
}
|
||||
|
||||
/// \brief Increase the priority of an item to the given value.
|
||||
///
|
||||
/// This function increases the priority of an item to the given value.
|
||||
/// \param i The item.
|
||||
/// \param p The priority.
|
||||
/// \pre \e i must be stored in the heap with priority at most \e p.
|
||||
void increase(const Item &i, const Prio &p) {
|
||||
int idx = _iim[i];
|
||||
unlace(idx);
|
||||
_data[idx].value = p;
|
||||
lace(idx);
|
||||
}
|
||||
|
||||
/// \brief Return the state of an item.
|
||||
///
|
||||
/// This method returns \c PRE_HEAP if the given item has never
|
||||
/// been in the heap, \c IN_HEAP if it is in the heap at the moment,
|
||||
/// and \c POST_HEAP otherwise.
|
||||
/// In the latter case it is possible that the item will get back
|
||||
/// to the heap again.
|
||||
/// \param i The item.
|
||||
State state(const Item &i) const {
|
||||
int idx = _iim[i];
|
||||
if (idx >= 0) idx = 0;
|
||||
return State(idx);
|
||||
}
|
||||
|
||||
/// \brief Set the state of an item in the heap.
|
||||
///
|
||||
/// This function sets the state of the given item in the heap.
|
||||
/// It can be used to manually clear the heap when it is important
|
||||
/// to achive better time complexity.
|
||||
/// \param i The item.
|
||||
/// \param st The state. It should not be \c IN_HEAP.
|
||||
void state(const Item& i, State st) {
|
||||
switch (st) {
|
||||
case POST_HEAP:
|
||||
case PRE_HEAP:
|
||||
if (state(i) == IN_HEAP) {
|
||||
erase(i);
|
||||
}
|
||||
_iim[i] = st;
|
||||
break;
|
||||
case IN_HEAP:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct BucketItem {
|
||||
BucketItem(const Item& _item, int _value)
|
||||
: item(_item), value(_value) {}
|
||||
|
||||
Item item;
|
||||
int value;
|
||||
|
||||
int prev, next;
|
||||
};
|
||||
|
||||
ItemIntMap& _iim;
|
||||
std::vector<int> _first;
|
||||
std::vector<BucketItem> _data;
|
||||
mutable int _minimum;
|
||||
|
||||
}; // class BucketHeap
|
||||
|
||||
/// \ingroup heaps
|
||||
///
|
||||
/// \brief Simplified bucket heap data structure.
|
||||
///
|
||||
/// This class implements a simplified \e bucket \e heap data
|
||||
/// structure. It does not provide some functionality, but it is
|
||||
/// faster and simpler than BucketHeap. The main difference is
|
||||
/// that BucketHeap stores a doubly-linked list for each key while
|
||||
/// this class stores only simply-linked lists. It supports erasing
|
||||
/// only for the item having minimum priority and it does not support
|
||||
/// key increasing and decreasing.
|
||||
///
|
||||
/// Note that this implementation does not conform to the
|
||||
/// \ref concepts::Heap "heap concept" due to the lack of some
|
||||
/// functionality.
|
||||
///
|
||||
/// \tparam IM A read-writable item map with \c int values, used
|
||||
/// internally to handle the cross references.
|
||||
/// \tparam MIN Indicate if the heap is a \e min-heap or a \e max-heap.
|
||||
/// The default is \e min-heap. If this parameter is set to \c false,
|
||||
/// then the comparison is reversed, so the top(), prio() and pop()
|
||||
/// functions deal with the item having maximum priority instead of the
|
||||
/// minimum.
|
||||
///
|
||||
/// \sa BucketHeap
|
||||
template <typename IM, bool MIN = true >
|
||||
class SimpleBucketHeap {
|
||||
|
||||
public:
|
||||
|
||||
/// Type of the item-int map.
|
||||
typedef IM ItemIntMap;
|
||||
/// Type of the priorities.
|
||||
typedef int Prio;
|
||||
/// Type of the items stored in the heap.
|
||||
typedef typename ItemIntMap::Key Item;
|
||||
/// Type of the item-priority pairs.
|
||||
typedef std::pair<Item,Prio> Pair;
|
||||
|
||||
private:
|
||||
|
||||
typedef _bucket_heap_bits::DirectionTraits<MIN> Direction;
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Type to represent the states of the items.
|
||||
///
|
||||
/// Each item has a state associated to it. It can be "in heap",
|
||||
/// "pre-heap" or "post-heap". The latter two are indifferent from the
|
||||
/// heap's point of view, but may be useful to the user.
|
||||
///
|
||||
/// The item-int map must be initialized in such way that it assigns
|
||||
/// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
|
||||
enum State {
|
||||
IN_HEAP = 0, ///< = 0.
|
||||
PRE_HEAP = -1, ///< = -1.
|
||||
POST_HEAP = -2 ///< = -2.
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Constructor.
|
||||
///
|
||||
/// Constructor.
|
||||
/// \param map A map that assigns \c int values to the items.
|
||||
/// It is used internally to handle the cross references.
|
||||
/// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
|
||||
explicit SimpleBucketHeap(ItemIntMap &map)
|
||||
: _iim(map), _free(-1), _num(0), _minimum(0) {}
|
||||
|
||||
/// \brief The number of items stored in the heap.
|
||||
///
|
||||
/// This function returns the number of items stored in the heap.
|
||||
int size() const { return _num; }
|
||||
|
||||
/// \brief Check if the heap is empty.
|
||||
///
|
||||
/// This function returns \c true if the heap is empty.
|
||||
bool empty() const { return _num == 0; }
|
||||
|
||||
/// \brief Make the heap empty.
|
||||
///
|
||||
/// This functon makes the heap empty.
|
||||
/// It does not change the cross reference map. If you want to reuse
|
||||
/// a heap that is not surely empty, you should first clear it and
|
||||
/// then you should set the cross reference map to \c PRE_HEAP
|
||||
/// for each item.
|
||||
void clear() {
|
||||
_data.clear(); _first.clear(); _free = -1; _num = 0; _minimum = 0;
|
||||
}
|
||||
|
||||
/// \brief Insert a pair of item and priority into the heap.
|
||||
///
|
||||
/// This function inserts \c p.first to the heap with priority
|
||||
/// \c p.second.
|
||||
/// \param p The pair to insert.
|
||||
/// \pre \c p.first must not be stored in the heap.
|
||||
void push(const Pair& p) {
|
||||
push(p.first, p.second);
|
||||
}
|
||||
|
||||
/// \brief Insert an item into the heap with the given priority.
|
||||
///
|
||||
/// This function inserts the given item into the heap with the
|
||||
/// given priority.
|
||||
/// \param i The item to insert.
|
||||
/// \param p The priority of the item.
|
||||
/// \pre \e i must not be stored in the heap.
|
||||
void push(const Item &i, const Prio &p) {
|
||||
int idx;
|
||||
if (_free == -1) {
|
||||
idx = _data.size();
|
||||
_data.push_back(BucketItem(i));
|
||||
} else {
|
||||
idx = _free;
|
||||
_free = _data[idx].next;
|
||||
_data[idx].item = i;
|
||||
}
|
||||
_iim[i] = idx;
|
||||
if (p >= int(_first.size())) _first.resize(p + 1, -1);
|
||||
_data[idx].next = _first[p];
|
||||
_first[p] = idx;
|
||||
if (Direction::less(p, _minimum)) {
|
||||
_minimum = p;
|
||||
}
|
||||
++_num;
|
||||
}
|
||||
|
||||
/// \brief Return the item having minimum priority.
|
||||
///
|
||||
/// This function returns the item having minimum priority.
|
||||
/// \pre The heap must be non-empty.
|
||||
Item top() const {
|
||||
while (_first[_minimum] == -1) {
|
||||
Direction::increase(_minimum);
|
||||
}
|
||||
return _data[_first[_minimum]].item;
|
||||
}
|
||||
|
||||
/// \brief The minimum priority.
|
||||
///
|
||||
/// This function returns the minimum priority.
|
||||
/// \pre The heap must be non-empty.
|
||||
Prio prio() const {
|
||||
while (_first[_minimum] == -1) {
|
||||
Direction::increase(_minimum);
|
||||
}
|
||||
return _minimum;
|
||||
}
|
||||
|
||||
/// \brief Remove the item having minimum priority.
|
||||
///
|
||||
/// This function removes the item having minimum priority.
|
||||
/// \pre The heap must be non-empty.
|
||||
void pop() {
|
||||
while (_first[_minimum] == -1) {
|
||||
Direction::increase(_minimum);
|
||||
}
|
||||
int idx = _first[_minimum];
|
||||
_iim[_data[idx].item] = -2;
|
||||
_first[_minimum] = _data[idx].next;
|
||||
_data[idx].next = _free;
|
||||
_free = idx;
|
||||
--_num;
|
||||
}
|
||||
|
||||
/// \brief The priority of the given item.
|
||||
///
|
||||
/// This function returns the priority of the given item.
|
||||
/// \param i The item.
|
||||
/// \pre \e i must be in the heap.
|
||||
/// \warning This operator is not a constant time function because
|
||||
/// it scans the whole data structure to find the proper value.
|
||||
Prio operator[](const Item &i) const {
|
||||
for (int k = 0; k < int(_first.size()); ++k) {
|
||||
int idx = _first[k];
|
||||
while (idx != -1) {
|
||||
if (_data[idx].item == i) {
|
||||
return k;
|
||||
}
|
||||
idx = _data[idx].next;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// \brief Return the state of an item.
|
||||
///
|
||||
/// This method returns \c PRE_HEAP if the given item has never
|
||||
/// been in the heap, \c IN_HEAP if it is in the heap at the moment,
|
||||
/// and \c POST_HEAP otherwise.
|
||||
/// In the latter case it is possible that the item will get back
|
||||
/// to the heap again.
|
||||
/// \param i The item.
|
||||
State state(const Item &i) const {
|
||||
int idx = _iim[i];
|
||||
if (idx >= 0) idx = 0;
|
||||
return State(idx);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct BucketItem {
|
||||
BucketItem(const Item& _item)
|
||||
: item(_item) {}
|
||||
|
||||
Item item;
|
||||
int next;
|
||||
};
|
||||
|
||||
ItemIntMap& _iim;
|
||||
std::vector<int> _first;
|
||||
std::vector<BucketItem> _data;
|
||||
int _free, _num;
|
||||
mutable int _minimum;
|
||||
|
||||
}; // class SimpleBucketHeap
|
||||
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,460 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
///\file
|
||||
///\brief Implementation of the CBC MIP solver interface.
|
||||
|
||||
#include "cbc.h"
|
||||
|
||||
#include <coin/CoinModel.hpp>
|
||||
#include <coin/CbcModel.hpp>
|
||||
#include <coin/OsiSolverInterface.hpp>
|
||||
|
||||
#include "coin/OsiClpSolverInterface.hpp"
|
||||
|
||||
#include "coin/CbcCutGenerator.hpp"
|
||||
#include "coin/CbcHeuristicLocal.hpp"
|
||||
#include "coin/CbcHeuristicGreedy.hpp"
|
||||
#include "coin/CbcHeuristicFPump.hpp"
|
||||
#include "coin/CbcHeuristicRINS.hpp"
|
||||
|
||||
#include "coin/CglGomory.hpp"
|
||||
#include "coin/CglProbing.hpp"
|
||||
#include "coin/CglKnapsackCover.hpp"
|
||||
#include "coin/CglOddHole.hpp"
|
||||
#include "coin/CglClique.hpp"
|
||||
#include "coin/CglFlowCover.hpp"
|
||||
#include "coin/CglMixedIntegerRounding.hpp"
|
||||
|
||||
#include "coin/CbcHeuristic.hpp"
|
||||
|
||||
namespace lemon {
|
||||
|
||||
CbcMip::CbcMip() {
|
||||
_prob = new CoinModel();
|
||||
_prob->setProblemName("LEMON");
|
||||
_osi_solver = 0;
|
||||
_cbc_model = 0;
|
||||
messageLevel(MESSAGE_NOTHING);
|
||||
}
|
||||
|
||||
CbcMip::CbcMip(const CbcMip& other) {
|
||||
_prob = new CoinModel(*other._prob);
|
||||
_prob->setProblemName("LEMON");
|
||||
_osi_solver = 0;
|
||||
_cbc_model = 0;
|
||||
messageLevel(MESSAGE_NOTHING);
|
||||
}
|
||||
|
||||
CbcMip::~CbcMip() {
|
||||
delete _prob;
|
||||
if (_osi_solver) delete _osi_solver;
|
||||
if (_cbc_model) delete _cbc_model;
|
||||
}
|
||||
|
||||
const char* CbcMip::_solverName() const { return "CbcMip"; }
|
||||
|
||||
int CbcMip::_addCol() {
|
||||
_prob->addColumn(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX, 0.0, 0, false);
|
||||
return _prob->numberColumns() - 1;
|
||||
}
|
||||
|
||||
CbcMip* CbcMip::newSolver() const {
|
||||
CbcMip* newlp = new CbcMip;
|
||||
return newlp;
|
||||
}
|
||||
|
||||
CbcMip* CbcMip::cloneSolver() const {
|
||||
CbcMip* copylp = new CbcMip(*this);
|
||||
return copylp;
|
||||
}
|
||||
|
||||
int CbcMip::_addRow() {
|
||||
_prob->addRow(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX);
|
||||
return _prob->numberRows() - 1;
|
||||
}
|
||||
|
||||
int CbcMip::_addRow(Value l, ExprIterator b, ExprIterator e, Value u) {
|
||||
std::vector<int> indexes;
|
||||
std::vector<Value> values;
|
||||
|
||||
for(ExprIterator it = b; it != e; ++it) {
|
||||
indexes.push_back(it->first);
|
||||
values.push_back(it->second);
|
||||
}
|
||||
|
||||
_prob->addRow(values.size(), &indexes.front(), &values.front(), l, u);
|
||||
return _prob->numberRows() - 1;
|
||||
}
|
||||
|
||||
void CbcMip::_eraseCol(int i) {
|
||||
_prob->deleteColumn(i);
|
||||
}
|
||||
|
||||
void CbcMip::_eraseRow(int i) {
|
||||
_prob->deleteRow(i);
|
||||
}
|
||||
|
||||
void CbcMip::_eraseColId(int i) {
|
||||
cols.eraseIndex(i);
|
||||
}
|
||||
|
||||
void CbcMip::_eraseRowId(int i) {
|
||||
rows.eraseIndex(i);
|
||||
}
|
||||
|
||||
void CbcMip::_getColName(int c, std::string& name) const {
|
||||
name = _prob->getColumnName(c);
|
||||
}
|
||||
|
||||
void CbcMip::_setColName(int c, const std::string& name) {
|
||||
_prob->setColumnName(c, name.c_str());
|
||||
}
|
||||
|
||||
int CbcMip::_colByName(const std::string& name) const {
|
||||
return _prob->column(name.c_str());
|
||||
}
|
||||
|
||||
void CbcMip::_getRowName(int r, std::string& name) const {
|
||||
name = _prob->getRowName(r);
|
||||
}
|
||||
|
||||
void CbcMip::_setRowName(int r, const std::string& name) {
|
||||
_prob->setRowName(r, name.c_str());
|
||||
}
|
||||
|
||||
int CbcMip::_rowByName(const std::string& name) const {
|
||||
return _prob->row(name.c_str());
|
||||
}
|
||||
|
||||
void CbcMip::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
|
||||
for (ExprIterator it = b; it != e; ++it) {
|
||||
_prob->setElement(i, it->first, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
void CbcMip::_getRowCoeffs(int ix, InsertIterator b) const {
|
||||
int length = _prob->numberRows();
|
||||
|
||||
std::vector<int> indices(length);
|
||||
std::vector<Value> values(length);
|
||||
|
||||
length = _prob->getRow(ix, &indices[0], &values[0]);
|
||||
|
||||
for (int i = 0; i < length; ++i) {
|
||||
*b = std::make_pair(indices[i], values[i]);
|
||||
++b;
|
||||
}
|
||||
}
|
||||
|
||||
void CbcMip::_setColCoeffs(int ix, ExprIterator b, ExprIterator e) {
|
||||
for (ExprIterator it = b; it != e; ++it) {
|
||||
_prob->setElement(it->first, ix, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
void CbcMip::_getColCoeffs(int ix, InsertIterator b) const {
|
||||
int length = _prob->numberColumns();
|
||||
|
||||
std::vector<int> indices(length);
|
||||
std::vector<Value> values(length);
|
||||
|
||||
length = _prob->getColumn(ix, &indices[0], &values[0]);
|
||||
|
||||
for (int i = 0; i < length; ++i) {
|
||||
*b = std::make_pair(indices[i], values[i]);
|
||||
++b;
|
||||
}
|
||||
}
|
||||
|
||||
void CbcMip::_setCoeff(int ix, int jx, Value value) {
|
||||
_prob->setElement(ix, jx, value);
|
||||
}
|
||||
|
||||
CbcMip::Value CbcMip::_getCoeff(int ix, int jx) const {
|
||||
return _prob->getElement(ix, jx);
|
||||
}
|
||||
|
||||
|
||||
void CbcMip::_setColLowerBound(int i, Value lo) {
|
||||
LEMON_ASSERT(lo != INF, "Invalid bound");
|
||||
_prob->setColumnLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
|
||||
}
|
||||
|
||||
CbcMip::Value CbcMip::_getColLowerBound(int i) const {
|
||||
double val = _prob->getColumnLower(i);
|
||||
return val == - COIN_DBL_MAX ? - INF : val;
|
||||
}
|
||||
|
||||
void CbcMip::_setColUpperBound(int i, Value up) {
|
||||
LEMON_ASSERT(up != -INF, "Invalid bound");
|
||||
_prob->setColumnUpper(i, up == INF ? COIN_DBL_MAX : up);
|
||||
}
|
||||
|
||||
CbcMip::Value CbcMip::_getColUpperBound(int i) const {
|
||||
double val = _prob->getColumnUpper(i);
|
||||
return val == COIN_DBL_MAX ? INF : val;
|
||||
}
|
||||
|
||||
void CbcMip::_setRowLowerBound(int i, Value lo) {
|
||||
LEMON_ASSERT(lo != INF, "Invalid bound");
|
||||
_prob->setRowLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
|
||||
}
|
||||
|
||||
CbcMip::Value CbcMip::_getRowLowerBound(int i) const {
|
||||
double val = _prob->getRowLower(i);
|
||||
return val == - COIN_DBL_MAX ? - INF : val;
|
||||
}
|
||||
|
||||
void CbcMip::_setRowUpperBound(int i, Value up) {
|
||||
LEMON_ASSERT(up != -INF, "Invalid bound");
|
||||
_prob->setRowUpper(i, up == INF ? COIN_DBL_MAX : up);
|
||||
}
|
||||
|
||||
CbcMip::Value CbcMip::_getRowUpperBound(int i) const {
|
||||
double val = _prob->getRowUpper(i);
|
||||
return val == COIN_DBL_MAX ? INF : val;
|
||||
}
|
||||
|
||||
void CbcMip::_setObjCoeffs(ExprIterator b, ExprIterator e) {
|
||||
int num = _prob->numberColumns();
|
||||
for (int i = 0; i < num; ++i) {
|
||||
_prob->setColumnObjective(i, 0.0);
|
||||
}
|
||||
for (ExprIterator it = b; it != e; ++it) {
|
||||
_prob->setColumnObjective(it->first, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
void CbcMip::_getObjCoeffs(InsertIterator b) const {
|
||||
int num = _prob->numberColumns();
|
||||
for (int i = 0; i < num; ++i) {
|
||||
Value coef = _prob->getColumnObjective(i);
|
||||
if (coef != 0.0) {
|
||||
*b = std::make_pair(i, coef);
|
||||
++b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CbcMip::_setObjCoeff(int i, Value obj_coef) {
|
||||
_prob->setColumnObjective(i, obj_coef);
|
||||
}
|
||||
|
||||
CbcMip::Value CbcMip::_getObjCoeff(int i) const {
|
||||
return _prob->getColumnObjective(i);
|
||||
}
|
||||
|
||||
CbcMip::SolveExitStatus CbcMip::_solve() {
|
||||
|
||||
if (_osi_solver) {
|
||||
delete _osi_solver;
|
||||
}
|
||||
_osi_solver = new OsiClpSolverInterface();
|
||||
|
||||
_osi_solver->loadFromCoinModel(*_prob);
|
||||
|
||||
if (_cbc_model) {
|
||||
delete _cbc_model;
|
||||
}
|
||||
_cbc_model= new CbcModel(*_osi_solver);
|
||||
|
||||
_osi_solver->messageHandler()->setLogLevel(_message_level);
|
||||
_cbc_model->setLogLevel(_message_level);
|
||||
|
||||
_cbc_model->initialSolve();
|
||||
_cbc_model->solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry);
|
||||
|
||||
if (!_cbc_model->isInitialSolveAbandoned() &&
|
||||
_cbc_model->isInitialSolveProvenOptimal() &&
|
||||
!_cbc_model->isInitialSolveProvenPrimalInfeasible() &&
|
||||
!_cbc_model->isInitialSolveProvenDualInfeasible()) {
|
||||
|
||||
CglProbing generator1;
|
||||
generator1.setUsingObjective(true);
|
||||
generator1.setMaxPass(3);
|
||||
generator1.setMaxProbe(100);
|
||||
generator1.setMaxLook(50);
|
||||
generator1.setRowCuts(3);
|
||||
_cbc_model->addCutGenerator(&generator1, -1, "Probing");
|
||||
|
||||
CglGomory generator2;
|
||||
generator2.setLimit(300);
|
||||
_cbc_model->addCutGenerator(&generator2, -1, "Gomory");
|
||||
|
||||
CglKnapsackCover generator3;
|
||||
_cbc_model->addCutGenerator(&generator3, -1, "Knapsack");
|
||||
|
||||
CglOddHole generator4;
|
||||
generator4.setMinimumViolation(0.005);
|
||||
generator4.setMinimumViolationPer(0.00002);
|
||||
generator4.setMaximumEntries(200);
|
||||
_cbc_model->addCutGenerator(&generator4, -1, "OddHole");
|
||||
|
||||
CglClique generator5;
|
||||
generator5.setStarCliqueReport(false);
|
||||
generator5.setRowCliqueReport(false);
|
||||
_cbc_model->addCutGenerator(&generator5, -1, "Clique");
|
||||
|
||||
CglMixedIntegerRounding mixedGen;
|
||||
_cbc_model->addCutGenerator(&mixedGen, -1, "MixedIntegerRounding");
|
||||
|
||||
CglFlowCover flowGen;
|
||||
_cbc_model->addCutGenerator(&flowGen, -1, "FlowCover");
|
||||
|
||||
OsiClpSolverInterface* osiclp =
|
||||
dynamic_cast<OsiClpSolverInterface*>(_cbc_model->solver());
|
||||
if (osiclp->getNumRows() < 300 && osiclp->getNumCols() < 500) {
|
||||
osiclp->setupForRepeatedUse(2, 0);
|
||||
}
|
||||
|
||||
CbcRounding heuristic1(*_cbc_model);
|
||||
heuristic1.setWhen(3);
|
||||
_cbc_model->addHeuristic(&heuristic1);
|
||||
|
||||
CbcHeuristicLocal heuristic2(*_cbc_model);
|
||||
heuristic2.setWhen(3);
|
||||
_cbc_model->addHeuristic(&heuristic2);
|
||||
|
||||
CbcHeuristicGreedyCover heuristic3(*_cbc_model);
|
||||
heuristic3.setAlgorithm(11);
|
||||
heuristic3.setWhen(3);
|
||||
_cbc_model->addHeuristic(&heuristic3);
|
||||
|
||||
CbcHeuristicFPump heuristic4(*_cbc_model);
|
||||
heuristic4.setWhen(3);
|
||||
_cbc_model->addHeuristic(&heuristic4);
|
||||
|
||||
CbcHeuristicRINS heuristic5(*_cbc_model);
|
||||
heuristic5.setWhen(3);
|
||||
_cbc_model->addHeuristic(&heuristic5);
|
||||
|
||||
if (_cbc_model->getNumCols() < 500) {
|
||||
_cbc_model->setMaximumCutPassesAtRoot(-100);
|
||||
} else if (_cbc_model->getNumCols() < 5000) {
|
||||
_cbc_model->setMaximumCutPassesAtRoot(100);
|
||||
} else {
|
||||
_cbc_model->setMaximumCutPassesAtRoot(20);
|
||||
}
|
||||
|
||||
if (_cbc_model->getNumCols() < 5000) {
|
||||
_cbc_model->setNumberStrong(10);
|
||||
}
|
||||
|
||||
_cbc_model->solver()->setIntParam(OsiMaxNumIterationHotStart, 100);
|
||||
_cbc_model->branchAndBound();
|
||||
}
|
||||
|
||||
if (_cbc_model->isAbandoned()) {
|
||||
return UNSOLVED;
|
||||
} else {
|
||||
return SOLVED;
|
||||
}
|
||||
}
|
||||
|
||||
CbcMip::Value CbcMip::_getSol(int i) const {
|
||||
return _cbc_model->getColSolution()[i];
|
||||
}
|
||||
|
||||
CbcMip::Value CbcMip::_getSolValue() const {
|
||||
return _cbc_model->getObjValue();
|
||||
}
|
||||
|
||||
CbcMip::ProblemType CbcMip::_getType() const {
|
||||
if (_cbc_model->isProvenOptimal()) {
|
||||
return OPTIMAL;
|
||||
} else if (_cbc_model->isContinuousUnbounded()) {
|
||||
return UNBOUNDED;
|
||||
}
|
||||
return FEASIBLE;
|
||||
}
|
||||
|
||||
void CbcMip::_setSense(Sense sense) {
|
||||
switch (sense) {
|
||||
case MIN:
|
||||
_prob->setOptimizationDirection(1.0);
|
||||
break;
|
||||
case MAX:
|
||||
_prob->setOptimizationDirection(- 1.0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CbcMip::Sense CbcMip::_getSense() const {
|
||||
if (_prob->optimizationDirection() > 0.0) {
|
||||
return MIN;
|
||||
} else if (_prob->optimizationDirection() < 0.0) {
|
||||
return MAX;
|
||||
} else {
|
||||
LEMON_ASSERT(false, "Wrong sense");
|
||||
return CbcMip::Sense();
|
||||
}
|
||||
}
|
||||
|
||||
void CbcMip::_setColType(int i, CbcMip::ColTypes col_type) {
|
||||
switch (col_type){
|
||||
case INTEGER:
|
||||
_prob->setInteger(i);
|
||||
break;
|
||||
case REAL:
|
||||
_prob->setContinuous(i);
|
||||
break;
|
||||
default:;
|
||||
LEMON_ASSERT(false, "Wrong sense");
|
||||
}
|
||||
}
|
||||
|
||||
CbcMip::ColTypes CbcMip::_getColType(int i) const {
|
||||
return _prob->getColumnIsInteger(i) ? INTEGER : REAL;
|
||||
}
|
||||
|
||||
void CbcMip::_clear() {
|
||||
delete _prob;
|
||||
if (_osi_solver) {
|
||||
delete _osi_solver;
|
||||
_osi_solver = 0;
|
||||
}
|
||||
if (_cbc_model) {
|
||||
delete _cbc_model;
|
||||
_cbc_model = 0;
|
||||
}
|
||||
|
||||
_prob = new CoinModel();
|
||||
}
|
||||
|
||||
void CbcMip::_messageLevel(MessageLevel level) {
|
||||
switch (level) {
|
||||
case MESSAGE_NOTHING:
|
||||
_message_level = 0;
|
||||
break;
|
||||
case MESSAGE_ERROR:
|
||||
_message_level = 1;
|
||||
break;
|
||||
case MESSAGE_WARNING:
|
||||
_message_level = 1;
|
||||
break;
|
||||
case MESSAGE_NORMAL:
|
||||
_message_level = 2;
|
||||
break;
|
||||
case MESSAGE_VERBOSE:
|
||||
_message_level = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} //END OF NAMESPACE LEMON
|
|
@ -0,0 +1,129 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_CBC_H
|
||||
#define LEMON_CBC_H
|
||||
|
||||
///\file
|
||||
///\brief Header of the LEMON-CBC mip solver interface.
|
||||
///\ingroup lp_group
|
||||
|
||||
#include <lemon/lp_base.h>
|
||||
|
||||
class CoinModel;
|
||||
class OsiSolverInterface;
|
||||
class CbcModel;
|
||||
|
||||
namespace lemon {
|
||||
|
||||
/// \brief Interface for the CBC MIP solver
|
||||
///
|
||||
/// This class implements an interface for the CBC MIP solver.
|
||||
///\ingroup lp_group
|
||||
class CbcMip : public MipSolver {
|
||||
protected:
|
||||
|
||||
CoinModel *_prob;
|
||||
OsiSolverInterface *_osi_solver;
|
||||
CbcModel *_cbc_model;
|
||||
|
||||
public:
|
||||
|
||||
/// \e
|
||||
CbcMip();
|
||||
/// \e
|
||||
CbcMip(const CbcMip&);
|
||||
/// \e
|
||||
~CbcMip();
|
||||
/// \e
|
||||
virtual CbcMip* newSolver() const;
|
||||
/// \e
|
||||
virtual CbcMip* cloneSolver() const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual const char* _solverName() const;
|
||||
|
||||
virtual int _addCol();
|
||||
virtual int _addRow();
|
||||
virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u);
|
||||
|
||||
virtual void _eraseCol(int i);
|
||||
virtual void _eraseRow(int i);
|
||||
|
||||
virtual void _eraseColId(int i);
|
||||
virtual void _eraseRowId(int i);
|
||||
|
||||
virtual void _getColName(int col, std::string& name) const;
|
||||
virtual void _setColName(int col, const std::string& name);
|
||||
virtual int _colByName(const std::string& name) const;
|
||||
|
||||
virtual void _getRowName(int row, std::string& name) const;
|
||||
virtual void _setRowName(int row, const std::string& name);
|
||||
virtual int _rowByName(const std::string& name) const;
|
||||
|
||||
virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
|
||||
virtual void _getRowCoeffs(int i, InsertIterator b) const;
|
||||
|
||||
virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
|
||||
virtual void _getColCoeffs(int i, InsertIterator b) const;
|
||||
|
||||
virtual void _setCoeff(int row, int col, Value value);
|
||||
virtual Value _getCoeff(int row, int col) const;
|
||||
|
||||
virtual void _setColLowerBound(int i, Value value);
|
||||
virtual Value _getColLowerBound(int i) const;
|
||||
virtual void _setColUpperBound(int i, Value value);
|
||||
virtual Value _getColUpperBound(int i) const;
|
||||
|
||||
virtual void _setRowLowerBound(int i, Value value);
|
||||
virtual Value _getRowLowerBound(int i) const;
|
||||
virtual void _setRowUpperBound(int i, Value value);
|
||||
virtual Value _getRowUpperBound(int i) const;
|
||||
|
||||
virtual void _setObjCoeffs(ExprIterator b, ExprIterator e);
|
||||
virtual void _getObjCoeffs(InsertIterator b) const;
|
||||
|
||||
virtual void _setObjCoeff(int i, Value obj_coef);
|
||||
virtual Value _getObjCoeff(int i) const;
|
||||
|
||||
virtual void _setSense(Sense sense);
|
||||
virtual Sense _getSense() const;
|
||||
|
||||
virtual ColTypes _getColType(int col) const;
|
||||
virtual void _setColType(int col, ColTypes col_type);
|
||||
|
||||
virtual SolveExitStatus _solve();
|
||||
virtual ProblemType _getType() const;
|
||||
virtual Value _getSol(int i) const;
|
||||
virtual Value _getSolValue() const;
|
||||
|
||||
virtual void _clear();
|
||||
|
||||
virtual void _messageLevel(MessageLevel level);
|
||||
void _applyMessageLevel();
|
||||
|
||||
int _message_level;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,254 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_CHRISTOFIDES_TSP_H
|
||||
#define LEMON_CHRISTOFIDES_TSP_H
|
||||
|
||||
/// \ingroup tsp
|
||||
/// \file
|
||||
/// \brief Christofides algorithm for symmetric TSP
|
||||
|
||||
#include <lemon/full_graph.h>
|
||||
#include <lemon/smart_graph.h>
|
||||
#include <lemon/kruskal.h>
|
||||
#include <lemon/matching.h>
|
||||
#include <lemon/euler.h>
|
||||
|
||||
namespace lemon {
|
||||
|
||||
/// \ingroup tsp
|
||||
///
|
||||
/// \brief Christofides algorithm for symmetric TSP.
|
||||
///
|
||||
/// ChristofidesTsp implements Christofides' heuristic for solving
|
||||
/// symmetric \ref tsp "TSP".
|
||||
///
|
||||
/// This a well-known approximation method for the TSP problem with
|
||||
/// metric cost function.
|
||||
/// It has a guaranteed approximation factor of 3/2 (i.e. it finds a tour
|
||||
/// whose total cost is at most 3/2 of the optimum), but it usually
|
||||
/// provides better solutions in practice.
|
||||
/// This implementation runs in O(n<sup>3</sup>log(n)) time.
|
||||
///
|
||||
/// The algorithm starts with a \ref spantree "minimum cost spanning tree" and
|
||||
/// finds a \ref MaxWeightedPerfectMatching "minimum cost perfect matching"
|
||||
/// in the subgraph induced by the nodes that have odd degree in the
|
||||
/// spanning tree.
|
||||
/// Finally, it constructs the tour from the \ref EulerIt "Euler traversal"
|
||||
/// of the union of the spanning tree and the matching.
|
||||
/// During this last step, the algorithm simply skips the visited nodes
|
||||
/// (i.e. creates shortcuts) assuming that the triangle inequality holds
|
||||
/// for the cost function.
|
||||
///
|
||||
/// \tparam CM Type of the cost map.
|
||||
///
|
||||
/// \warning CM::Value must be a signed number type.
|
||||
template <typename CM>
|
||||
class ChristofidesTsp
|
||||
{
|
||||
public:
|
||||
|
||||
/// Type of the cost map
|
||||
typedef CM CostMap;
|
||||
/// Type of the edge costs
|
||||
typedef typename CM::Value Cost;
|
||||
|
||||
private:
|
||||
|
||||
GRAPH_TYPEDEFS(FullGraph);
|
||||
|
||||
const FullGraph &_gr;
|
||||
const CostMap &_cost;
|
||||
std::vector<Node> _path;
|
||||
Cost _sum;
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Constructor
|
||||
///
|
||||
/// Constructor.
|
||||
/// \param gr The \ref FullGraph "full graph" the algorithm runs on.
|
||||
/// \param cost The cost map.
|
||||
ChristofidesTsp(const FullGraph &gr, const CostMap &cost)
|
||||
: _gr(gr), _cost(cost) {}
|
||||
|
||||
/// \name Execution Control
|
||||
/// @{
|
||||
|
||||
/// \brief Runs the algorithm.
|
||||
///
|
||||
/// This function runs the algorithm.
|
||||
///
|
||||
/// \return The total cost of the found tour.
|
||||
Cost run() {
|
||||
_path.clear();
|
||||
|
||||
if (_gr.nodeNum() == 0) return _sum = 0;
|
||||
else if (_gr.nodeNum() == 1) {
|
||||
_path.push_back(_gr(0));
|
||||
return _sum = 0;
|
||||
}
|
||||
else if (_gr.nodeNum() == 2) {
|
||||
_path.push_back(_gr(0));
|
||||
_path.push_back(_gr(1));
|
||||
return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))];
|
||||
}
|
||||
|
||||
// Compute min. cost spanning tree
|
||||
std::vector<Edge> tree;
|
||||
kruskal(_gr, _cost, std::back_inserter(tree));
|
||||
|
||||
FullGraph::NodeMap<int> deg(_gr, 0);
|
||||
for (int i = 0; i != int(tree.size()); ++i) {
|
||||
Edge e = tree[i];
|
||||
++deg[_gr.u(e)];
|
||||
++deg[_gr.v(e)];
|
||||
}
|
||||
|
||||
// Copy the induced subgraph of odd nodes
|
||||
std::vector<Node> odd_nodes;
|
||||
for (NodeIt u(_gr); u != INVALID; ++u) {
|
||||
if (deg[u] % 2 == 1) odd_nodes.push_back(u);
|
||||
}
|
||||
|
||||
SmartGraph sgr;
|
||||
SmartGraph::EdgeMap<Cost> scost(sgr);
|
||||
for (int i = 0; i != int(odd_nodes.size()); ++i) {
|
||||
sgr.addNode();
|
||||
}
|
||||
for (int i = 0; i != int(odd_nodes.size()); ++i) {
|
||||
for (int j = 0; j != int(odd_nodes.size()); ++j) {
|
||||
if (j == i) continue;
|
||||
SmartGraph::Edge e =
|
||||
sgr.addEdge(sgr.nodeFromId(i), sgr.nodeFromId(j));
|
||||
scost[e] = -_cost[_gr.edge(odd_nodes[i], odd_nodes[j])];
|
||||
}
|
||||
}
|
||||
|
||||
// Compute min. cost perfect matching
|
||||
MaxWeightedPerfectMatching<SmartGraph, SmartGraph::EdgeMap<Cost> >
|
||||
mwpm(sgr, scost);
|
||||
mwpm.run();
|
||||
|
||||
for (SmartGraph::EdgeIt e(sgr); e != INVALID; ++e) {
|
||||
if (mwpm.matching(e)) {
|
||||
tree.push_back( _gr.edge(odd_nodes[sgr.id(sgr.u(e))],
|
||||
odd_nodes[sgr.id(sgr.v(e))]) );
|
||||
}
|
||||
}
|
||||
|
||||
// Join the spanning tree and the matching
|
||||
sgr.clear();
|
||||
for (int i = 0; i != _gr.nodeNum(); ++i) {
|
||||
sgr.addNode();
|
||||
}
|
||||
for (int i = 0; i != int(tree.size()); ++i) {
|
||||
int ui = _gr.id(_gr.u(tree[i])),
|
||||
vi = _gr.id(_gr.v(tree[i]));
|
||||
sgr.addEdge(sgr.nodeFromId(ui), sgr.nodeFromId(vi));
|
||||
}
|
||||
|
||||
// Compute the tour from the Euler traversal
|
||||
SmartGraph::NodeMap<bool> visited(sgr, false);
|
||||
for (EulerIt<SmartGraph> e(sgr); e != INVALID; ++e) {
|
||||
SmartGraph::Node n = sgr.target(e);
|
||||
if (!visited[n]) {
|
||||
_path.push_back(_gr(sgr.id(n)));
|
||||
visited[n] = true;
|
||||
}
|
||||
}
|
||||
|
||||
_sum = _cost[_gr.edge(_path.back(), _path.front())];
|
||||
for (int i = 0; i < int(_path.size())-1; ++i) {
|
||||
_sum += _cost[_gr.edge(_path[i], _path[i+1])];
|
||||
}
|
||||
|
||||
return _sum;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Query Functions
|
||||
/// @{
|
||||
|
||||
/// \brief The total cost of the found tour.
|
||||
///
|
||||
/// This function returns the total cost of the found tour.
|
||||
///
|
||||
/// \pre run() must be called before using this function.
|
||||
Cost tourCost() const {
|
||||
return _sum;
|
||||
}
|
||||
|
||||
/// \brief Returns a const reference to the node sequence of the
|
||||
/// found tour.
|
||||
///
|
||||
/// This function returns a const reference to a vector
|
||||
/// that stores the node sequence of the found tour.
|
||||
///
|
||||
/// \pre run() must be called before using this function.
|
||||
const std::vector<Node>& tourNodes() const {
|
||||
return _path;
|
||||
}
|
||||
|
||||
/// \brief Gives back the node sequence of the found tour.
|
||||
///
|
||||
/// This function copies the node sequence of the found tour into
|
||||
/// an STL container through the given output iterator. The
|
||||
/// <tt>value_type</tt> of the container must be <tt>FullGraph::Node</tt>.
|
||||
/// For example,
|
||||
/// \code
|
||||
/// std::vector<FullGraph::Node> nodes(countNodes(graph));
|
||||
/// tsp.tourNodes(nodes.begin());
|
||||
/// \endcode
|
||||
/// or
|
||||
/// \code
|
||||
/// std::list<FullGraph::Node> nodes;
|
||||
/// tsp.tourNodes(std::back_inserter(nodes));
|
||||
/// \endcode
|
||||
///
|
||||
/// \pre run() must be called before using this function.
|
||||
template <typename Iterator>
|
||||
void tourNodes(Iterator out) const {
|
||||
std::copy(_path.begin(), _path.end(), out);
|
||||
}
|
||||
|
||||
/// \brief Gives back the found tour as a path.
|
||||
///
|
||||
/// This function copies the found tour as a list of arcs/edges into
|
||||
/// the given \ref lemon::concepts::Path "path structure".
|
||||
///
|
||||
/// \pre run() must be called before using this function.
|
||||
template <typename Path>
|
||||
void tour(Path &path) const {
|
||||
path.clear();
|
||||
for (int i = 0; i < int(_path.size()) - 1; ++i) {
|
||||
path.addBack(_gr.arc(_path[i], _path[i+1]));
|
||||
}
|
||||
if (int(_path.size()) >= 2) {
|
||||
path.addBack(_gr.arc(_path.back(), _path.front()));
|
||||
}
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
};
|
||||
|
||||
}; // namespace lemon
|
||||
|
||||
#endif
|
|
@ -0,0 +1,807 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_CIRCULATION_H
|
||||
#define LEMON_CIRCULATION_H
|
||||
|
||||
#include <lemon/tolerance.h>
|
||||
#include <lemon/elevator.h>
|
||||
#include <limits>
|
||||
|
||||
///\ingroup max_flow
|
||||
///\file
|
||||
///\brief Push-relabel algorithm for finding a feasible circulation.
|
||||
///
|
||||
namespace lemon {
|
||||
|
||||
/// \brief Default traits class of Circulation class.
|
||||
///
|
||||
/// Default traits class of Circulation class.
|
||||
///
|
||||
/// \tparam GR Type of the digraph the algorithm runs on.
|
||||
/// \tparam LM The type of the lower bound map.
|
||||
/// \tparam UM The type of the upper bound (capacity) map.
|
||||
/// \tparam SM The type of the supply map.
|
||||
template <typename GR, typename LM,
|
||||
typename UM, typename SM>
|
||||
struct CirculationDefaultTraits {
|
||||
|
||||
/// \brief The type of the digraph the algorithm runs on.
|
||||
typedef GR Digraph;
|
||||
|
||||
/// \brief The type of the lower bound map.
|
||||
///
|
||||
/// The type of the map that stores the lower bounds on the arcs.
|
||||
/// It must conform to the \ref concepts::ReadMap "ReadMap" concept.
|
||||
typedef LM LowerMap;
|
||||
|
||||
/// \brief The type of the upper bound (capacity) map.
|
||||
///
|
||||
/// The type of the map that stores the upper bounds (capacities)
|
||||
/// on the arcs.
|
||||
/// It must conform to the \ref concepts::ReadMap "ReadMap" concept.
|
||||
typedef UM UpperMap;
|
||||
|
||||
/// \brief The type of supply map.
|
||||
///
|
||||
/// The type of the map that stores the signed supply values of the
|
||||
/// nodes.
|
||||
/// It must conform to the \ref concepts::ReadMap "ReadMap" concept.
|
||||
typedef SM SupplyMap;
|
||||
|
||||
/// \brief The type of the flow and supply values.
|
||||
typedef typename SupplyMap::Value Value;
|
||||
|
||||
/// \brief The type of the map that stores the flow values.
|
||||
///
|
||||
/// The type of the map that stores the flow values.
|
||||
/// It must conform to the \ref concepts::ReadWriteMap "ReadWriteMap"
|
||||
/// concept.
|
||||
#ifdef DOXYGEN
|
||||
typedef GR::ArcMap<Value> FlowMap;
|
||||
#else
|
||||
typedef typename Digraph::template ArcMap<Value> FlowMap;
|
||||
#endif
|
||||
|
||||
/// \brief Instantiates a FlowMap.
|
||||
///
|
||||
/// This function instantiates a \ref FlowMap.
|
||||
/// \param digraph The digraph for which we would like to define
|
||||
/// the flow map.
|
||||
static FlowMap* createFlowMap(const Digraph& digraph) {
|
||||
return new FlowMap(digraph);
|
||||
}
|
||||
|
||||
/// \brief The elevator type used by the algorithm.
|
||||
///
|
||||
/// The elevator type used by the algorithm.
|
||||
///
|
||||
/// \sa Elevator, LinkedElevator
|
||||
#ifdef DOXYGEN
|
||||
typedef lemon::Elevator<GR, GR::Node> Elevator;
|
||||
#else
|
||||
typedef lemon::Elevator<Digraph, typename Digraph::Node> Elevator;
|
||||
#endif
|
||||
|
||||
/// \brief Instantiates an Elevator.
|
||||
///
|
||||
/// This function instantiates an \ref Elevator.
|
||||
/// \param digraph The digraph for which we would like to define
|
||||
/// the elevator.
|
||||
/// \param max_level The maximum level of the elevator.
|
||||
static Elevator* createElevator(const Digraph& digraph, int max_level) {
|
||||
return new Elevator(digraph, max_level);
|
||||
}
|
||||
|
||||
/// \brief The tolerance used by the algorithm
|
||||
///
|
||||
/// The tolerance used by the algorithm to handle inexact computation.
|
||||
typedef lemon::Tolerance<Value> Tolerance;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Push-relabel algorithm for the network circulation problem.
|
||||
|
||||
\ingroup max_flow
|
||||
This class implements a push-relabel algorithm for the \e network
|
||||
\e circulation problem.
|
||||
It is to find a feasible circulation when lower and upper bounds
|
||||
are given for the flow values on the arcs and lower bounds are
|
||||
given for the difference between the outgoing and incoming flow
|
||||
at the nodes.
|
||||
|
||||
The exact formulation of this problem is the following.
|
||||
Let \f$G=(V,A)\f$ be a digraph, \f$lower: A\rightarrow\mathbf{R}\f$
|
||||
\f$upper: A\rightarrow\mathbf{R}\cup\{\infty\}\f$ denote the lower and
|
||||
upper bounds on the arcs, for which \f$lower(uv) \leq upper(uv)\f$
|
||||
holds for all \f$uv\in A\f$, and \f$sup: V\rightarrow\mathbf{R}\f$
|
||||
denotes the signed supply values of the nodes.
|
||||
If \f$sup(u)>0\f$, then \f$u\f$ is a supply node with \f$sup(u)\f$
|
||||
supply, if \f$sup(u)<0\f$, then \f$u\f$ is a demand node with
|
||||
\f$-sup(u)\f$ demand.
|
||||
A feasible circulation is an \f$f: A\rightarrow\mathbf{R}\f$
|
||||
solution of the following problem.
|
||||
|
||||
\f[ \sum_{uv\in A} f(uv) - \sum_{vu\in A} f(vu)
|
||||
\geq sup(u) \quad \forall u\in V, \f]
|
||||
\f[ lower(uv) \leq f(uv) \leq upper(uv) \quad \forall uv\in A. \f]
|
||||
|
||||
The sum of the supply values, i.e. \f$\sum_{u\in V} sup(u)\f$ must be
|
||||
zero or negative in order to have a feasible solution (since the sum
|
||||
of the expressions on the left-hand side of the inequalities is zero).
|
||||
It means that the total demand must be greater or equal to the total
|
||||
supply and all the supplies have to be carried out from the supply nodes,
|
||||
but there could be demands that are not satisfied.
|
||||
If \f$\sum_{u\in V} sup(u)\f$ is zero, then all the supply/demand
|
||||
constraints have to be satisfied with equality, i.e. all demands
|
||||
have to be satisfied and all supplies have to be used.
|
||||
|
||||
If you need the opposite inequalities in the supply/demand constraints
|
||||
(i.e. the total demand is less than the total supply and all the demands
|
||||
have to be satisfied while there could be supplies that are not used),
|
||||
then you could easily transform the problem to the above form by reversing
|
||||
the direction of the arcs and taking the negative of the supply values
|
||||
(e.g. using \ref ReverseDigraph and \ref NegMap adaptors).
|
||||
|
||||
This algorithm either calculates a feasible circulation, or provides
|
||||
a \ref barrier() "barrier", which prooves that a feasible soultion
|
||||
cannot exist.
|
||||
|
||||
Note that this algorithm also provides a feasible solution for the
|
||||
\ref min_cost_flow "minimum cost flow problem".
|
||||
|
||||
\tparam GR The type of the digraph the algorithm runs on.
|
||||
\tparam LM The type of the lower bound map. The default
|
||||
map type is \ref concepts::Digraph::ArcMap "GR::ArcMap<int>".
|
||||
\tparam UM The type of the upper bound (capacity) map.
|
||||
The default map type is \c LM.
|
||||
\tparam SM The type of the supply map. The default map type is
|
||||
\ref concepts::Digraph::NodeMap "GR::NodeMap<UM::Value>".
|
||||
\tparam TR The traits class that defines various types used by the
|
||||
algorithm. By default, it is \ref CirculationDefaultTraits
|
||||
"CirculationDefaultTraits<GR, LM, UM, SM>".
|
||||
In most cases, this parameter should not be set directly,
|
||||
consider to use the named template parameters instead.
|
||||
*/
|
||||
#ifdef DOXYGEN
|
||||
template< typename GR,
|
||||
typename LM,
|
||||
typename UM,
|
||||
typename SM,
|
||||
typename TR >
|
||||
#else
|
||||
template< typename GR,
|
||||
typename LM = typename GR::template ArcMap<int>,
|
||||
typename UM = LM,
|
||||
typename SM = typename GR::template NodeMap<typename UM::Value>,
|
||||
typename TR = CirculationDefaultTraits<GR, LM, UM, SM> >
|
||||
#endif
|
||||
class Circulation {
|
||||
public:
|
||||
|
||||
/// \brief The \ref lemon::CirculationDefaultTraits "traits class"
|
||||
/// of the algorithm.
|
||||
typedef TR Traits;
|
||||
///The type of the digraph the algorithm runs on.
|
||||
typedef typename Traits::Digraph Digraph;
|
||||
///The type of the flow and supply values.
|
||||
typedef typename Traits::Value Value;
|
||||
|
||||
///The type of the lower bound map.
|
||||
typedef typename Traits::LowerMap LowerMap;
|
||||
///The type of the upper bound (capacity) map.
|
||||
typedef typename Traits::UpperMap UpperMap;
|
||||
///The type of the supply map.
|
||||
typedef typename Traits::SupplyMap SupplyMap;
|
||||
///The type of the flow map.
|
||||
typedef typename Traits::FlowMap FlowMap;
|
||||
|
||||
///The type of the elevator.
|
||||
typedef typename Traits::Elevator Elevator;
|
||||
///The type of the tolerance.
|
||||
typedef typename Traits::Tolerance Tolerance;
|
||||
|
||||
private:
|
||||
|
||||
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
|
||||
|
||||
const Digraph &_g;
|
||||
int _node_num;
|
||||
|
||||
const LowerMap *_lo;
|
||||
const UpperMap *_up;
|
||||
const SupplyMap *_supply;
|
||||
|
||||
FlowMap *_flow;
|
||||
bool _local_flow;
|
||||
|
||||
Elevator* _level;
|
||||
bool _local_level;
|
||||
|
||||
typedef typename Digraph::template NodeMap<Value> ExcessMap;
|
||||
ExcessMap* _excess;
|
||||
|
||||
Tolerance _tol;
|
||||
int _el;
|
||||
|
||||
public:
|
||||
|
||||
typedef Circulation Create;
|
||||
|
||||
///\name Named Template Parameters
|
||||
|
||||
///@{
|
||||
|
||||
template <typename T>
|
||||
struct SetFlowMapTraits : public Traits {
|
||||
typedef T FlowMap;
|
||||
static FlowMap *createFlowMap(const Digraph&) {
|
||||
LEMON_ASSERT(false, "FlowMap is not initialized");
|
||||
return 0; // ignore warnings
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief \ref named-templ-param "Named parameter" for setting
|
||||
/// FlowMap type
|
||||
///
|
||||
/// \ref named-templ-param "Named parameter" for setting FlowMap
|
||||
/// type.
|
||||
template <typename T>
|
||||
struct SetFlowMap
|
||||
: public Circulation<Digraph, LowerMap, UpperMap, SupplyMap,
|
||||
SetFlowMapTraits<T> > {
|
||||
typedef Circulation<Digraph, LowerMap, UpperMap, SupplyMap,
|
||||
SetFlowMapTraits<T> > Create;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct SetElevatorTraits : public Traits {
|
||||
typedef T Elevator;
|
||||
static Elevator *createElevator(const Digraph&, int) {
|
||||
LEMON_ASSERT(false, "Elevator is not initialized");
|
||||
return 0; // ignore warnings
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief \ref named-templ-param "Named parameter" for setting
|
||||
/// Elevator type
|
||||
///
|
||||
/// \ref named-templ-param "Named parameter" for setting Elevator
|
||||
/// type. If this named parameter is used, then an external
|
||||
/// elevator object must be passed to the algorithm using the
|
||||
/// \ref elevator(Elevator&) "elevator()" function before calling
|
||||
/// \ref run() or \ref init().
|
||||
/// \sa SetStandardElevator
|
||||
template <typename T>
|
||||
struct SetElevator
|
||||
: public Circulation<Digraph, LowerMap, UpperMap, SupplyMap,
|
||||
SetElevatorTraits<T> > {
|
||||
typedef Circulation<Digraph, LowerMap, UpperMap, SupplyMap,
|
||||
SetElevatorTraits<T> > Create;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct SetStandardElevatorTraits : public Traits {
|
||||
typedef T Elevator;
|
||||
static Elevator *createElevator(const Digraph& digraph, int max_level) {
|
||||
return new Elevator(digraph, max_level);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief \ref named-templ-param "Named parameter" for setting
|
||||
/// Elevator type with automatic allocation
|
||||
///
|
||||
/// \ref named-templ-param "Named parameter" for setting Elevator
|
||||
/// type with automatic allocation.
|
||||
/// The Elevator should have standard constructor interface to be
|
||||
/// able to automatically created by the algorithm (i.e. the
|
||||
/// digraph and the maximum level should be passed to it).
|
||||
/// However, an external elevator object could also be passed to the
|
||||
/// algorithm with the \ref elevator(Elevator&) "elevator()" function
|
||||
/// before calling \ref run() or \ref init().
|
||||
/// \sa SetElevator
|
||||
template <typename T>
|
||||
struct SetStandardElevator
|
||||
: public Circulation<Digraph, LowerMap, UpperMap, SupplyMap,
|
||||
SetStandardElevatorTraits<T> > {
|
||||
typedef Circulation<Digraph, LowerMap, UpperMap, SupplyMap,
|
||||
SetStandardElevatorTraits<T> > Create;
|
||||
};
|
||||
|
||||
/// @}
|
||||
|
||||
protected:
|
||||
|
||||
Circulation() {}
|
||||
|
||||
public:
|
||||
|
||||
/// Constructor.
|
||||
|
||||
/// The constructor of the class.
|
||||
///
|
||||
/// \param graph The digraph the algorithm runs on.
|
||||
/// \param lower The lower bounds for the flow values on the arcs.
|
||||
/// \param upper The upper bounds (capacities) for the flow values
|
||||
/// on the arcs.
|
||||
/// \param supply The signed supply values of the nodes.
|
||||
Circulation(const Digraph &graph, const LowerMap &lower,
|
||||
const UpperMap &upper, const SupplyMap &supply)
|
||||
: _g(graph), _lo(&lower), _up(&upper), _supply(&supply),
|
||||
_flow(NULL), _local_flow(false), _level(NULL), _local_level(false),
|
||||
_excess(NULL) {}
|
||||
|
||||
/// Destructor.
|
||||
~Circulation() {
|
||||
destroyStructures();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
bool checkBoundMaps() {
|
||||
for (ArcIt e(_g);e!=INVALID;++e) {
|
||||
if (_tol.less((*_up)[e], (*_lo)[e])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void createStructures() {
|
||||
_node_num = _el = countNodes(_g);
|
||||
|
||||
if (!_flow) {
|
||||
_flow = Traits::createFlowMap(_g);
|
||||
_local_flow = true;
|
||||
}
|
||||
if (!_level) {
|
||||
_level = Traits::createElevator(_g, _node_num);
|
||||
_local_level = true;
|
||||
}
|
||||
if (!_excess) {
|
||||
_excess = new ExcessMap(_g);
|
||||
}
|
||||
}
|
||||
|
||||
void destroyStructures() {
|
||||
if (_local_flow) {
|
||||
delete _flow;
|
||||
}
|
||||
if (_local_level) {
|
||||
delete _level;
|
||||
}
|
||||
if (_excess) {
|
||||
delete _excess;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// Sets the lower bound map.
|
||||
|
||||
/// Sets the lower bound map.
|
||||
/// \return <tt>(*this)</tt>
|
||||
Circulation& lowerMap(const LowerMap& map) {
|
||||
_lo = ↦
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Sets the upper bound (capacity) map.
|
||||
|
||||
/// Sets the upper bound (capacity) map.
|
||||
/// \return <tt>(*this)</tt>
|
||||
Circulation& upperMap(const UpperMap& map) {
|
||||
_up = ↦
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Sets the supply map.
|
||||
|
||||
/// Sets the supply map.
|
||||
/// \return <tt>(*this)</tt>
|
||||
Circulation& supplyMap(const SupplyMap& map) {
|
||||
_supply = ↦
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Sets the flow map.
|
||||
///
|
||||
/// Sets the flow map.
|
||||
/// If you don't use this function before calling \ref run() or
|
||||
/// \ref init(), an instance will be allocated automatically.
|
||||
/// The destructor deallocates this automatically allocated map,
|
||||
/// of course.
|
||||
/// \return <tt>(*this)</tt>
|
||||
Circulation& flowMap(FlowMap& map) {
|
||||
if (_local_flow) {
|
||||
delete _flow;
|
||||
_local_flow = false;
|
||||
}
|
||||
_flow = ↦
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Sets the elevator used by algorithm.
|
||||
///
|
||||
/// Sets the elevator used by algorithm.
|
||||
/// If you don't use this function before calling \ref run() or
|
||||
/// \ref init(), an instance will be allocated automatically.
|
||||
/// The destructor deallocates this automatically allocated elevator,
|
||||
/// of course.
|
||||
/// \return <tt>(*this)</tt>
|
||||
Circulation& elevator(Elevator& elevator) {
|
||||
if (_local_level) {
|
||||
delete _level;
|
||||
_local_level = false;
|
||||
}
|
||||
_level = &elevator;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Returns a const reference to the elevator.
|
||||
///
|
||||
/// Returns a const reference to the elevator.
|
||||
///
|
||||
/// \pre Either \ref run() or \ref init() must be called before
|
||||
/// using this function.
|
||||
const Elevator& elevator() const {
|
||||
return *_level;
|
||||
}
|
||||
|
||||
/// \brief Sets the tolerance used by the algorithm.
|
||||
///
|
||||
/// Sets the tolerance object used by the algorithm.
|
||||
/// \return <tt>(*this)</tt>
|
||||
Circulation& tolerance(const Tolerance& tolerance) {
|
||||
_tol = tolerance;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Returns a const reference to the tolerance.
|
||||
///
|
||||
/// Returns a const reference to the tolerance object used by
|
||||
/// the algorithm.
|
||||
const Tolerance& tolerance() const {
|
||||
return _tol;
|
||||
}
|
||||
|
||||
/// \name Execution Control
|
||||
/// The simplest way to execute the algorithm is to call \ref run().\n
|
||||
/// If you need better control on the initial solution or the execution,
|
||||
/// you have to call one of the \ref init() functions first, then
|
||||
/// the \ref start() function.
|
||||
|
||||
///@{
|
||||
|
||||
/// Initializes the internal data structures.
|
||||
|
||||
/// Initializes the internal data structures and sets all flow values
|
||||
/// to the lower bound.
|
||||
void init()
|
||||
{
|
||||
LEMON_DEBUG(checkBoundMaps(),
|
||||
"Upper bounds must be greater or equal to the lower bounds");
|
||||
|
||||
createStructures();
|
||||
|
||||
for(NodeIt n(_g);n!=INVALID;++n) {
|
||||
(*_excess)[n] = (*_supply)[n];
|
||||
}
|
||||
|
||||
for (ArcIt e(_g);e!=INVALID;++e) {
|
||||
_flow->set(e, (*_lo)[e]);
|
||||
(*_excess)[_g.target(e)] += (*_flow)[e];
|
||||
(*_excess)[_g.source(e)] -= (*_flow)[e];
|
||||
}
|
||||
|
||||
// global relabeling tested, but in general case it provides
|
||||
// worse performance for random digraphs
|
||||
_level->initStart();
|
||||
for(NodeIt n(_g);n!=INVALID;++n)
|
||||
_level->initAddItem(n);
|
||||
_level->initFinish();
|
||||
for(NodeIt n(_g);n!=INVALID;++n)
|
||||
if(_tol.positive((*_excess)[n]))
|
||||
_level->activate(n);
|
||||
}
|
||||
|
||||
/// Initializes the internal data structures using a greedy approach.
|
||||
|
||||
/// Initializes the internal data structures using a greedy approach
|
||||
/// to construct the initial solution.
|
||||
void greedyInit()
|
||||
{
|
||||
LEMON_DEBUG(checkBoundMaps(),
|
||||
"Upper bounds must be greater or equal to the lower bounds");
|
||||
|
||||
createStructures();
|
||||
|
||||
for(NodeIt n(_g);n!=INVALID;++n) {
|
||||
(*_excess)[n] = (*_supply)[n];
|
||||
}
|
||||
|
||||
for (ArcIt e(_g);e!=INVALID;++e) {
|
||||
if (!_tol.less(-(*_excess)[_g.target(e)], (*_up)[e])) {
|
||||
_flow->set(e, (*_up)[e]);
|
||||
(*_excess)[_g.target(e)] += (*_up)[e];
|
||||
(*_excess)[_g.source(e)] -= (*_up)[e];
|
||||
} else if (_tol.less(-(*_excess)[_g.target(e)], (*_lo)[e])) {
|
||||
_flow->set(e, (*_lo)[e]);
|
||||
(*_excess)[_g.target(e)] += (*_lo)[e];
|
||||
(*_excess)[_g.source(e)] -= (*_lo)[e];
|
||||
} else {
|
||||
Value fc = -(*_excess)[_g.target(e)];
|
||||
_flow->set(e, fc);
|
||||
(*_excess)[_g.target(e)] = 0;
|
||||
(*_excess)[_g.source(e)] -= fc;
|
||||
}
|
||||
}
|
||||
|
||||
_level->initStart();
|
||||
for(NodeIt n(_g);n!=INVALID;++n)
|
||||
_level->initAddItem(n);
|
||||
_level->initFinish();
|
||||
for(NodeIt n(_g);n!=INVALID;++n)
|
||||
if(_tol.positive((*_excess)[n]))
|
||||
_level->activate(n);
|
||||
}
|
||||
|
||||
///Executes the algorithm
|
||||
|
||||
///This function executes the algorithm.
|
||||
///
|
||||
///\return \c true if a feasible circulation is found.
|
||||
///
|
||||
///\sa barrier()
|
||||
///\sa barrierMap()
|
||||
bool start()
|
||||
{
|
||||
|
||||
Node act;
|
||||
while((act=_level->highestActive())!=INVALID) {
|
||||
int actlevel=(*_level)[act];
|
||||
int mlevel=_node_num;
|
||||
Value exc=(*_excess)[act];
|
||||
|
||||
for(OutArcIt e(_g,act);e!=INVALID; ++e) {
|
||||
Node v = _g.target(e);
|
||||
Value fc=(*_up)[e]-(*_flow)[e];
|
||||
if(!_tol.positive(fc)) continue;
|
||||
if((*_level)[v]<actlevel) {
|
||||
if(!_tol.less(fc, exc)) {
|
||||
_flow->set(e, (*_flow)[e] + exc);
|
||||
(*_excess)[v] += exc;
|
||||
if(!_level->active(v) && _tol.positive((*_excess)[v]))
|
||||
_level->activate(v);
|
||||
(*_excess)[act] = 0;
|
||||
_level->deactivate(act);
|
||||
goto next_l;
|
||||
}
|
||||
else {
|
||||
_flow->set(e, (*_up)[e]);
|
||||
(*_excess)[v] += fc;
|
||||
if(!_level->active(v) && _tol.positive((*_excess)[v]))
|
||||
_level->activate(v);
|
||||
exc-=fc;
|
||||
}
|
||||
}
|
||||
else if((*_level)[v]<mlevel) mlevel=(*_level)[v];
|
||||
}
|
||||
for(InArcIt e(_g,act);e!=INVALID; ++e) {
|
||||
Node v = _g.source(e);
|
||||
Value fc=(*_flow)[e]-(*_lo)[e];
|
||||
if(!_tol.positive(fc)) continue;
|
||||
if((*_level)[v]<actlevel) {
|
||||
if(!_tol.less(fc, exc)) {
|
||||
_flow->set(e, (*_flow)[e] - exc);
|
||||
(*_excess)[v] += exc;
|
||||
if(!_level->active(v) && _tol.positive((*_excess)[v]))
|
||||
_level->activate(v);
|
||||
(*_excess)[act] = 0;
|
||||
_level->deactivate(act);
|
||||
goto next_l;
|
||||
}
|
||||
else {
|
||||
_flow->set(e, (*_lo)[e]);
|
||||
(*_excess)[v] += fc;
|
||||
if(!_level->active(v) && _tol.positive((*_excess)[v]))
|
||||
_level->activate(v);
|
||||
exc-=fc;
|
||||
}
|
||||
}
|
||||
else if((*_level)[v]<mlevel) mlevel=(*_level)[v];
|
||||
}
|
||||
|
||||
(*_excess)[act] = exc;
|
||||
if(!_tol.positive(exc)) _level->deactivate(act);
|
||||
else if(mlevel==_node_num) {
|
||||
_level->liftHighestActiveToTop();
|
||||
_el = _node_num;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
_level->liftHighestActive(mlevel+1);
|
||||
if(_level->onLevel(actlevel)==0) {
|
||||
_el = actlevel;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
next_l:
|
||||
;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Runs the algorithm.
|
||||
|
||||
/// This function runs the algorithm.
|
||||
///
|
||||
/// \return \c true if a feasible circulation is found.
|
||||
///
|
||||
/// \note Apart from the return value, c.run() is just a shortcut of
|
||||
/// the following code.
|
||||
/// \code
|
||||
/// c.greedyInit();
|
||||
/// c.start();
|
||||
/// \endcode
|
||||
bool run() {
|
||||
greedyInit();
|
||||
return start();
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Query Functions
|
||||
/// The results of the circulation algorithm can be obtained using
|
||||
/// these functions.\n
|
||||
/// Either \ref run() or \ref start() should be called before
|
||||
/// using them.
|
||||
|
||||
///@{
|
||||
|
||||
/// \brief Returns the flow value on the given arc.
|
||||
///
|
||||
/// Returns the flow value on the given arc.
|
||||
///
|
||||
/// \pre Either \ref run() or \ref init() must be called before
|
||||
/// using this function.
|
||||
Value flow(const Arc& arc) const {
|
||||
return (*_flow)[arc];
|
||||
}
|
||||
|
||||
/// \brief Returns a const reference to the flow map.
|
||||
///
|
||||
/// Returns a const reference to the arc map storing the found flow.
|
||||
///
|
||||
/// \pre Either \ref run() or \ref init() must be called before
|
||||
/// using this function.
|
||||
const FlowMap& flowMap() const {
|
||||
return *_flow;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Returns \c true if the given node is in a barrier.
|
||||
|
||||
Barrier is a set \e B of nodes for which
|
||||
|
||||
\f[ \sum_{uv\in A: u\in B} upper(uv) -
|
||||
\sum_{uv\in A: v\in B} lower(uv) < \sum_{v\in B} sup(v) \f]
|
||||
|
||||
holds. The existence of a set with this property prooves that a
|
||||
feasible circualtion cannot exist.
|
||||
|
||||
This function returns \c true if the given node is in the found
|
||||
barrier. If a feasible circulation is found, the function
|
||||
gives back \c false for every node.
|
||||
|
||||
\pre Either \ref run() or \ref init() must be called before
|
||||
using this function.
|
||||
|
||||
\sa barrierMap()
|
||||
\sa checkBarrier()
|
||||
*/
|
||||
bool barrier(const Node& node) const
|
||||
{
|
||||
return (*_level)[node] >= _el;
|
||||
}
|
||||
|
||||
/// \brief Gives back a barrier.
|
||||
///
|
||||
/// This function sets \c bar to the characteristic vector of the
|
||||
/// found barrier. \c bar should be a \ref concepts::WriteMap "writable"
|
||||
/// node map with \c bool (or convertible) value type.
|
||||
///
|
||||
/// If a feasible circulation is found, the function gives back an
|
||||
/// empty set, so \c bar[v] will be \c false for all nodes \c v.
|
||||
///
|
||||
/// \note This function calls \ref barrier() for each node,
|
||||
/// so it runs in O(n) time.
|
||||
///
|
||||
/// \pre Either \ref run() or \ref init() must be called before
|
||||
/// using this function.
|
||||
///
|
||||
/// \sa barrier()
|
||||
/// \sa checkBarrier()
|
||||
template<class BarrierMap>
|
||||
void barrierMap(BarrierMap &bar) const
|
||||
{
|
||||
for(NodeIt n(_g);n!=INVALID;++n)
|
||||
bar.set(n, (*_level)[n] >= _el);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Checker Functions
|
||||
/// The feasibility of the results can be checked using
|
||||
/// these functions.\n
|
||||
/// Either \ref run() or \ref start() should be called before
|
||||
/// using them.
|
||||
|
||||
///@{
|
||||
|
||||
///Check if the found flow is a feasible circulation
|
||||
|
||||
///Check if the found flow is a feasible circulation,
|
||||
///
|
||||
bool checkFlow() const {
|
||||
for(ArcIt e(_g);e!=INVALID;++e)
|
||||
if((*_flow)[e]<(*_lo)[e]||(*_flow)[e]>(*_up)[e]) return false;
|
||||
for(NodeIt n(_g);n!=INVALID;++n)
|
||||
{
|
||||
Value dif=-(*_supply)[n];
|
||||
for(InArcIt e(_g,n);e!=INVALID;++e) dif-=(*_flow)[e];
|
||||
for(OutArcIt e(_g,n);e!=INVALID;++e) dif+=(*_flow)[e];
|
||||
if(_tol.negative(dif)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
///Check whether or not the last execution provides a barrier
|
||||
|
||||
///Check whether or not the last execution provides a barrier.
|
||||
///\sa barrier()
|
||||
///\sa barrierMap()
|
||||
bool checkBarrier() const
|
||||
{
|
||||
Value delta=0;
|
||||
Value inf_cap = std::numeric_limits<Value>::has_infinity ?
|
||||
std::numeric_limits<Value>::infinity() :
|
||||
std::numeric_limits<Value>::max();
|
||||
for(NodeIt n(_g);n!=INVALID;++n)
|
||||
if(barrier(n))
|
||||
delta-=(*_supply)[n];
|
||||
for(ArcIt e(_g);e!=INVALID;++e)
|
||||
{
|
||||
Node s=_g.source(e);
|
||||
Node t=_g.target(e);
|
||||
if(barrier(s)&&!barrier(t)) {
|
||||
if (_tol.less(inf_cap - (*_up)[e], delta)) return false;
|
||||
delta+=(*_up)[e];
|
||||
}
|
||||
else if(barrier(t)&&!barrier(s)) delta-=(*_lo)[e];
|
||||
}
|
||||
return _tol.negative(delta);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,464 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <lemon/clp.h>
|
||||
#include <coin/ClpSimplex.hpp>
|
||||
|
||||
namespace lemon {
|
||||
|
||||
ClpLp::ClpLp() {
|
||||
_prob = new ClpSimplex();
|
||||
_init_temporals();
|
||||
messageLevel(MESSAGE_NOTHING);
|
||||
}
|
||||
|
||||
ClpLp::ClpLp(const ClpLp& other) {
|
||||
_prob = new ClpSimplex(*other._prob);
|
||||
rows = other.rows;
|
||||
cols = other.cols;
|
||||
_init_temporals();
|
||||
messageLevel(MESSAGE_NOTHING);
|
||||
}
|
||||
|
||||
ClpLp::~ClpLp() {
|
||||
delete _prob;
|
||||
_clear_temporals();
|
||||
}
|
||||
|
||||
void ClpLp::_init_temporals() {
|
||||
_primal_ray = 0;
|
||||
_dual_ray = 0;
|
||||
}
|
||||
|
||||
void ClpLp::_clear_temporals() {
|
||||
if (_primal_ray) {
|
||||
delete[] _primal_ray;
|
||||
_primal_ray = 0;
|
||||
}
|
||||
if (_dual_ray) {
|
||||
delete[] _dual_ray;
|
||||
_dual_ray = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ClpLp* ClpLp::newSolver() const {
|
||||
ClpLp* newlp = new ClpLp;
|
||||
return newlp;
|
||||
}
|
||||
|
||||
ClpLp* ClpLp::cloneSolver() const {
|
||||
ClpLp* copylp = new ClpLp(*this);
|
||||
return copylp;
|
||||
}
|
||||
|
||||
const char* ClpLp::_solverName() const { return "ClpLp"; }
|
||||
|
||||
int ClpLp::_addCol() {
|
||||
_prob->addColumn(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX, 0.0);
|
||||
return _prob->numberColumns() - 1;
|
||||
}
|
||||
|
||||
int ClpLp::_addRow() {
|
||||
_prob->addRow(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX);
|
||||
return _prob->numberRows() - 1;
|
||||
}
|
||||
|
||||
int ClpLp::_addRow(Value l, ExprIterator b, ExprIterator e, Value u) {
|
||||
std::vector<int> indexes;
|
||||
std::vector<Value> values;
|
||||
|
||||
for(ExprIterator it = b; it != e; ++it) {
|
||||
indexes.push_back(it->first);
|
||||
values.push_back(it->second);
|
||||
}
|
||||
|
||||
_prob->addRow(values.size(), &indexes.front(), &values.front(), l, u);
|
||||
return _prob->numberRows() - 1;
|
||||
}
|
||||
|
||||
|
||||
void ClpLp::_eraseCol(int c) {
|
||||
_col_names_ref.erase(_prob->getColumnName(c));
|
||||
_prob->deleteColumns(1, &c);
|
||||
}
|
||||
|
||||
void ClpLp::_eraseRow(int r) {
|
||||
_row_names_ref.erase(_prob->getRowName(r));
|
||||
_prob->deleteRows(1, &r);
|
||||
}
|
||||
|
||||
void ClpLp::_eraseColId(int i) {
|
||||
cols.eraseIndex(i);
|
||||
cols.shiftIndices(i);
|
||||
}
|
||||
|
||||
void ClpLp::_eraseRowId(int i) {
|
||||
rows.eraseIndex(i);
|
||||
rows.shiftIndices(i);
|
||||
}
|
||||
|
||||
void ClpLp::_getColName(int c, std::string& name) const {
|
||||
name = _prob->getColumnName(c);
|
||||
}
|
||||
|
||||
void ClpLp::_setColName(int c, const std::string& name) {
|
||||
_prob->setColumnName(c, const_cast<std::string&>(name));
|
||||
_col_names_ref[name] = c;
|
||||
}
|
||||
|
||||
int ClpLp::_colByName(const std::string& name) const {
|
||||
std::map<std::string, int>::const_iterator it = _col_names_ref.find(name);
|
||||
return it != _col_names_ref.end() ? it->second : -1;
|
||||
}
|
||||
|
||||
void ClpLp::_getRowName(int r, std::string& name) const {
|
||||
name = _prob->getRowName(r);
|
||||
}
|
||||
|
||||
void ClpLp::_setRowName(int r, const std::string& name) {
|
||||
_prob->setRowName(r, const_cast<std::string&>(name));
|
||||
_row_names_ref[name] = r;
|
||||
}
|
||||
|
||||
int ClpLp::_rowByName(const std::string& name) const {
|
||||
std::map<std::string, int>::const_iterator it = _row_names_ref.find(name);
|
||||
return it != _row_names_ref.end() ? it->second : -1;
|
||||
}
|
||||
|
||||
|
||||
void ClpLp::_setRowCoeffs(int ix, ExprIterator b, ExprIterator e) {
|
||||
std::map<int, Value> coeffs;
|
||||
|
||||
int n = _prob->clpMatrix()->getNumCols();
|
||||
|
||||
const int* indices = _prob->clpMatrix()->getIndices();
|
||||
const double* elements = _prob->clpMatrix()->getElements();
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[i];
|
||||
CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[i];
|
||||
|
||||
const int* it = std::lower_bound(indices + begin, indices + end, ix);
|
||||
if (it != indices + end && *it == ix && elements[it - indices] != 0.0) {
|
||||
coeffs[i] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
for (ExprIterator it = b; it != e; ++it) {
|
||||
coeffs[it->first] = it->second;
|
||||
}
|
||||
|
||||
for (std::map<int, Value>::iterator it = coeffs.begin();
|
||||
it != coeffs.end(); ++it) {
|
||||
_prob->modifyCoefficient(ix, it->first, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
void ClpLp::_getRowCoeffs(int ix, InsertIterator b) const {
|
||||
int n = _prob->clpMatrix()->getNumCols();
|
||||
|
||||
const int* indices = _prob->clpMatrix()->getIndices();
|
||||
const double* elements = _prob->clpMatrix()->getElements();
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[i];
|
||||
CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[i];
|
||||
|
||||
const int* it = std::lower_bound(indices + begin, indices + end, ix);
|
||||
if (it != indices + end && *it == ix) {
|
||||
*b = std::make_pair(i, elements[it - indices]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClpLp::_setColCoeffs(int ix, ExprIterator b, ExprIterator e) {
|
||||
std::map<int, Value> coeffs;
|
||||
|
||||
CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix];
|
||||
CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix];
|
||||
|
||||
const int* indices = _prob->clpMatrix()->getIndices();
|
||||
const double* elements = _prob->clpMatrix()->getElements();
|
||||
|
||||
for (CoinBigIndex i = begin; i != end; ++i) {
|
||||
if (elements[i] != 0.0) {
|
||||
coeffs[indices[i]] = 0.0;
|
||||
}
|
||||
}
|
||||
for (ExprIterator it = b; it != e; ++it) {
|
||||
coeffs[it->first] = it->second;
|
||||
}
|
||||
for (std::map<int, Value>::iterator it = coeffs.begin();
|
||||
it != coeffs.end(); ++it) {
|
||||
_prob->modifyCoefficient(it->first, ix, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
void ClpLp::_getColCoeffs(int ix, InsertIterator b) const {
|
||||
CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix];
|
||||
CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix];
|
||||
|
||||
const int* indices = _prob->clpMatrix()->getIndices();
|
||||
const double* elements = _prob->clpMatrix()->getElements();
|
||||
|
||||
for (CoinBigIndex i = begin; i != end; ++i) {
|
||||
*b = std::make_pair(indices[i], elements[i]);
|
||||
++b;
|
||||
}
|
||||
}
|
||||
|
||||
void ClpLp::_setCoeff(int ix, int jx, Value value) {
|
||||
_prob->modifyCoefficient(ix, jx, value);
|
||||
}
|
||||
|
||||
ClpLp::Value ClpLp::_getCoeff(int ix, int jx) const {
|
||||
CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix];
|
||||
CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix];
|
||||
|
||||
const int* indices = _prob->clpMatrix()->getIndices();
|
||||
const double* elements = _prob->clpMatrix()->getElements();
|
||||
|
||||
const int* it = std::lower_bound(indices + begin, indices + end, jx);
|
||||
if (it != indices + end && *it == jx) {
|
||||
return elements[it - indices];
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void ClpLp::_setColLowerBound(int i, Value lo) {
|
||||
_prob->setColumnLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
|
||||
}
|
||||
|
||||
ClpLp::Value ClpLp::_getColLowerBound(int i) const {
|
||||
double val = _prob->getColLower()[i];
|
||||
return val == - COIN_DBL_MAX ? - INF : val;
|
||||
}
|
||||
|
||||
void ClpLp::_setColUpperBound(int i, Value up) {
|
||||
_prob->setColumnUpper(i, up == INF ? COIN_DBL_MAX : up);
|
||||
}
|
||||
|
||||
ClpLp::Value ClpLp::_getColUpperBound(int i) const {
|
||||
double val = _prob->getColUpper()[i];
|
||||
return val == COIN_DBL_MAX ? INF : val;
|
||||
}
|
||||
|
||||
void ClpLp::_setRowLowerBound(int i, Value lo) {
|
||||
_prob->setRowLower(i, lo == - INF ? - COIN_DBL_MAX : lo);
|
||||
}
|
||||
|
||||
ClpLp::Value ClpLp::_getRowLowerBound(int i) const {
|
||||
double val = _prob->getRowLower()[i];
|
||||
return val == - COIN_DBL_MAX ? - INF : val;
|
||||
}
|
||||
|
||||
void ClpLp::_setRowUpperBound(int i, Value up) {
|
||||
_prob->setRowUpper(i, up == INF ? COIN_DBL_MAX : up);
|
||||
}
|
||||
|
||||
ClpLp::Value ClpLp::_getRowUpperBound(int i) const {
|
||||
double val = _prob->getRowUpper()[i];
|
||||
return val == COIN_DBL_MAX ? INF : val;
|
||||
}
|
||||
|
||||
void ClpLp::_setObjCoeffs(ExprIterator b, ExprIterator e) {
|
||||
int num = _prob->clpMatrix()->getNumCols();
|
||||
for (int i = 0; i < num; ++i) {
|
||||
_prob->setObjectiveCoefficient(i, 0.0);
|
||||
}
|
||||
for (ExprIterator it = b; it != e; ++it) {
|
||||
_prob->setObjectiveCoefficient(it->first, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
void ClpLp::_getObjCoeffs(InsertIterator b) const {
|
||||
int num = _prob->clpMatrix()->getNumCols();
|
||||
for (int i = 0; i < num; ++i) {
|
||||
Value coef = _prob->getObjCoefficients()[i];
|
||||
if (coef != 0.0) {
|
||||
*b = std::make_pair(i, coef);
|
||||
++b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClpLp::_setObjCoeff(int i, Value obj_coef) {
|
||||
_prob->setObjectiveCoefficient(i, obj_coef);
|
||||
}
|
||||
|
||||
ClpLp::Value ClpLp::_getObjCoeff(int i) const {
|
||||
return _prob->getObjCoefficients()[i];
|
||||
}
|
||||
|
||||
ClpLp::SolveExitStatus ClpLp::_solve() {
|
||||
return _prob->primal() >= 0 ? SOLVED : UNSOLVED;
|
||||
}
|
||||
|
||||
ClpLp::SolveExitStatus ClpLp::solvePrimal() {
|
||||
return _prob->primal() >= 0 ? SOLVED : UNSOLVED;
|
||||
}
|
||||
|
||||
ClpLp::SolveExitStatus ClpLp::solveDual() {
|
||||
return _prob->dual() >= 0 ? SOLVED : UNSOLVED;
|
||||
}
|
||||
|
||||
ClpLp::SolveExitStatus ClpLp::solveBarrier() {
|
||||
return _prob->barrier() >= 0 ? SOLVED : UNSOLVED;
|
||||
}
|
||||
|
||||
ClpLp::Value ClpLp::_getPrimal(int i) const {
|
||||
return _prob->primalColumnSolution()[i];
|
||||
}
|
||||
ClpLp::Value ClpLp::_getPrimalValue() const {
|
||||
return _prob->objectiveValue();
|
||||
}
|
||||
|
||||
ClpLp::Value ClpLp::_getDual(int i) const {
|
||||
return _prob->dualRowSolution()[i];
|
||||
}
|
||||
|
||||
ClpLp::Value ClpLp::_getPrimalRay(int i) const {
|
||||
if (!_primal_ray) {
|
||||
_primal_ray = _prob->unboundedRay();
|
||||
LEMON_ASSERT(_primal_ray != 0, "Primal ray is not provided");
|
||||
}
|
||||
return _primal_ray[i];
|
||||
}
|
||||
|
||||
ClpLp::Value ClpLp::_getDualRay(int i) const {
|
||||
if (!_dual_ray) {
|
||||
_dual_ray = _prob->infeasibilityRay();
|
||||
LEMON_ASSERT(_dual_ray != 0, "Dual ray is not provided");
|
||||
}
|
||||
return _dual_ray[i];
|
||||
}
|
||||
|
||||
ClpLp::VarStatus ClpLp::_getColStatus(int i) const {
|
||||
switch (_prob->getColumnStatus(i)) {
|
||||
case ClpSimplex::basic:
|
||||
return BASIC;
|
||||
case ClpSimplex::isFree:
|
||||
return FREE;
|
||||
case ClpSimplex::atUpperBound:
|
||||
return UPPER;
|
||||
case ClpSimplex::atLowerBound:
|
||||
return LOWER;
|
||||
case ClpSimplex::isFixed:
|
||||
return FIXED;
|
||||
case ClpSimplex::superBasic:
|
||||
return FREE;
|
||||
default:
|
||||
LEMON_ASSERT(false, "Wrong column status");
|
||||
return VarStatus();
|
||||
}
|
||||
}
|
||||
|
||||
ClpLp::VarStatus ClpLp::_getRowStatus(int i) const {
|
||||
switch (_prob->getColumnStatus(i)) {
|
||||
case ClpSimplex::basic:
|
||||
return BASIC;
|
||||
case ClpSimplex::isFree:
|
||||
return FREE;
|
||||
case ClpSimplex::atUpperBound:
|
||||
return UPPER;
|
||||
case ClpSimplex::atLowerBound:
|
||||
return LOWER;
|
||||
case ClpSimplex::isFixed:
|
||||
return FIXED;
|
||||
case ClpSimplex::superBasic:
|
||||
return FREE;
|
||||
default:
|
||||
LEMON_ASSERT(false, "Wrong row status");
|
||||
return VarStatus();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ClpLp::ProblemType ClpLp::_getPrimalType() const {
|
||||
if (_prob->isProvenOptimal()) {
|
||||
return OPTIMAL;
|
||||
} else if (_prob->isProvenPrimalInfeasible()) {
|
||||
return INFEASIBLE;
|
||||
} else if (_prob->isProvenDualInfeasible()) {
|
||||
return UNBOUNDED;
|
||||
} else {
|
||||
return UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
ClpLp::ProblemType ClpLp::_getDualType() const {
|
||||
if (_prob->isProvenOptimal()) {
|
||||
return OPTIMAL;
|
||||
} else if (_prob->isProvenDualInfeasible()) {
|
||||
return INFEASIBLE;
|
||||
} else if (_prob->isProvenPrimalInfeasible()) {
|
||||
return INFEASIBLE;
|
||||
} else {
|
||||
return UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
void ClpLp::_setSense(ClpLp::Sense sense) {
|
||||
switch (sense) {
|
||||
case MIN:
|
||||
_prob->setOptimizationDirection(1);
|
||||
break;
|
||||
case MAX:
|
||||
_prob->setOptimizationDirection(-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ClpLp::Sense ClpLp::_getSense() const {
|
||||
double dir = _prob->optimizationDirection();
|
||||
if (dir > 0.0) {
|
||||
return MIN;
|
||||
} else {
|
||||
return MAX;
|
||||
}
|
||||
}
|
||||
|
||||
void ClpLp::_clear() {
|
||||
delete _prob;
|
||||
_prob = new ClpSimplex();
|
||||
_col_names_ref.clear();
|
||||
_clear_temporals();
|
||||
}
|
||||
|
||||
void ClpLp::_messageLevel(MessageLevel level) {
|
||||
switch (level) {
|
||||
case MESSAGE_NOTHING:
|
||||
_prob->setLogLevel(0);
|
||||
break;
|
||||
case MESSAGE_ERROR:
|
||||
_prob->setLogLevel(1);
|
||||
break;
|
||||
case MESSAGE_WARNING:
|
||||
_prob->setLogLevel(2);
|
||||
break;
|
||||
case MESSAGE_NORMAL:
|
||||
_prob->setLogLevel(3);
|
||||
break;
|
||||
case MESSAGE_VERBOSE:
|
||||
_prob->setLogLevel(4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} //END OF NAMESPACE LEMON
|
|
@ -0,0 +1,164 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2013
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_CLP_H
|
||||
#define LEMON_CLP_H
|
||||
|
||||
///\file
|
||||
///\brief Header of the LEMON-CLP lp solver interface.
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <lemon/lp_base.h>
|
||||
|
||||
class ClpSimplex;
|
||||
|
||||
namespace lemon {
|
||||
|
||||
/// \ingroup lp_group
|
||||
///
|
||||
/// \brief Interface for the CLP solver
|
||||
///
|
||||
/// This class implements an interface for the Clp LP solver. The
|
||||
/// Clp library is an object oriented lp solver library developed at
|
||||
/// the IBM. The CLP is part of the COIN-OR package and it can be
|
||||
/// used with Common Public License.
|
||||
class ClpLp : public LpSolver {
|
||||
protected:
|
||||
|
||||
ClpSimplex* _prob;
|
||||
|
||||
std::map<std::string, int> _col_names_ref;
|
||||
std::map<std::string, int> _row_names_ref;
|
||||
|
||||
public:
|
||||
|
||||
/// \e
|
||||
ClpLp();
|
||||
/// \e
|
||||
ClpLp(const ClpLp&);
|
||||
/// \e
|
||||
~ClpLp();
|
||||
|
||||
/// \e
|
||||
virtual ClpLp* newSolver() const;
|
||||
/// \e
|
||||
virtual ClpLp* cloneSolver() const;
|
||||
|
||||
protected:
|
||||
|
||||
mutable double* _primal_ray;
|
||||
mutable double* _dual_ray;
|
||||
|
||||
void _init_temporals();
|
||||
void _clear_temporals();
|
||||
|
||||
protected:
|
||||
|
||||
virtual const char* _solverName() const;
|
||||
|
||||
virtual int _addCol();
|
||||
virtual int _addRow();
|
||||
virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u);
|
||||
|
||||
virtual void _eraseCol(int i);
|
||||
virtual void _eraseRow(int i);
|
||||
|
||||
virtual void _eraseColId(int i);
|
||||
virtual void _eraseRowId(int i);
|
||||
|
||||
virtual void _getColName(int col, std::string& name) const;
|
||||
virtual void _setColName(int col, const std::string& name);
|
||||
virtual int _colByName(const std::string& name) const;
|
||||
|
||||
virtual void _getRowName(int row, std::string& name) const;
|
||||
virtual void _setRowName(int row, const std::string& name);
|
||||
virtual int _rowByName(const std::string& name) const;
|
||||
|
||||
virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e);
|
||||
virtual void _getRowCoeffs(int i, InsertIterator b) const;
|
||||
|
||||
virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e);
|
||||
virtual void _getColCoeffs(int i, InsertIterator b) const;
|
||||
|
||||
virtual void _setCoeff(int row, int col, Value value);
|
||||
virtual Value _getCoeff(int row, int col) const;
|
||||
|
||||
virtual void _setColLowerBound(int i, Value value);
|
||||
virtual Value _getColLowerBound(int i) const;
|
||||
virtual void _setColUpperBound(int i, Value value);
|
||||
virtual Value _getColUpperBound(int i) const;
|
||||
|
||||
virtual void _setRowLowerBound(int i, Value value);
|
||||
virtual Value _getRowLowerBound(int i) const;
|
||||
virtual void _setRowUpperBound(int i, Value value);
|
||||
virtual Value _getRowUpperBound(int i) const;
|
||||
|
||||
virtual void _setObjCoeffs(ExprIterator, ExprIterator);
|
||||
virtual void _getObjCoeffs(InsertIterator) const;
|
||||
|
||||
virtual void _setObjCoeff(int i, Value obj_coef);
|
||||
virtual Value _getObjCoeff(int i) const;
|
||||
|
||||
virtual void _setSense(Sense sense);
|
||||
virtual Sense _getSense() const;
|
||||
|
||||
virtual SolveExitStatus _solve();
|
||||
|
||||
virtual Value _getPrimal(int i) const;
|
||||
virtual Value _getDual(int i) const;
|
||||
|
||||
virtual Value _getPrimalValue() const;
|
||||
|
||||
virtual Value _getPrimalRay(int i) const;
|
||||
virtual Value _getDualRay(int i) const;
|
||||
|
||||
virtual VarStatus _getColStatus(int i) const;
|
||||
virtual VarStatus _getRowStatus(int i) const;
|
||||
|
||||
virtual ProblemType _getPrimalType() const;
|
||||
virtual ProblemType _getDualType() const;
|
||||
|
||||
virtual void _clear();
|
||||
|
||||
virtual void _messageLevel(MessageLevel);
|
||||
|
||||
public:
|
||||
|
||||
///Solves LP with primal simplex method.
|
||||
SolveExitStatus solvePrimal();
|
||||
|
||||
///Solves LP with dual simplex method.
|
||||
SolveExitStatus solveDual();
|
||||
|
||||
///Solves LP with barrier method.
|
||||
SolveExitStatus solveBarrier();
|
||||
|
||||
///Returns the constraint identifier understood by CLP.
|
||||
int clpRow(Row r) const { return rows(id(r)); }
|
||||
|
||||
///Returns the variable identifier understood by CLP.
|
||||
int clpCol(Col c) const { return cols(id(c)); }
|
||||
|
||||
};
|
||||
|
||||
} //END OF NAMESPACE LEMON
|
||||
|
||||
#endif //LEMON_CLP_H
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2009
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
///\file
|
||||
///\brief Color constants
|
||||
|
||||
#include<lemon/color.h>
|
||||
|
||||
namespace lemon {
|
||||
|
||||
const Color WHITE(1,1,1);
|
||||
|
||||
const Color BLACK(0,0,0);
|
||||
const Color RED(1,0,0);
|
||||
const Color GREEN(0,1,0);
|
||||
const Color BLUE(0,0,1);
|
||||
const Color YELLOW(1,1,0);
|
||||
const Color MAGENTA(1,0,1);
|
||||
const Color CYAN(0,1,1);
|
||||
|
||||
const Color GREY(0,0,0);
|
||||
const Color DARK_RED(.5,0,0);
|
||||
const Color DARK_GREEN(0,.5,0);
|
||||
const Color DARK_BLUE(0,0,.5);
|
||||
const Color DARK_YELLOW(.5,.5,0);
|
||||
const Color DARK_MAGENTA(.5,0,.5);
|
||||
const Color DARK_CYAN(0,.5,.5);
|
||||
|
||||
} //namespace lemon
|
|
@ -0,0 +1,204 @@
|
|||
/* -*- mode: C++; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* This file is a part of LEMON, a generic C++ optimization library.
|
||||
*
|
||||
* Copyright (C) 2003-2009
|
||||
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
||||
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
||||
*
|
||||
* Permission to use, modify and distribute this software is granted
|
||||
* provided that this copyright notice appears in all copies. For
|
||||
* precise terms see the accompanying LICENSE file.
|
||||
*
|
||||
* This software is provided "AS IS" with no warranty of any kind,
|
||||
* express or implied, and with no claim as to its suitability for any
|
||||
* purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LEMON_COLOR_H
|
||||
#define LEMON_COLOR_H
|
||||
|
||||
#include<vector>
|
||||
#include<lemon/math.h>
|
||||
#include<lemon/maps.h>
|
||||
|
||||
|
||||
///\ingroup misc
|
||||
///\file
|
||||
///\brief Tools to manage RGB colors.
|
||||
|
||||
namespace lemon {
|
||||
|
||||
|
||||
/// \addtogroup misc
|
||||
/// @{
|
||||
|
||||
///Data structure representing RGB colors.
|
||||
|
||||
///Data structure representing RGB colors.
|
||||
class Color
|
||||
{
|
||||
double _r,_g,_b;
|
||||
public:
|
||||
///Default constructor
|
||||
Color() {}
|
||||
///Constructor
|
||||
Color(double r,double g,double b) :_r(r),_g(g),_b(b) {};
|
||||
///Set the red component
|
||||
double & red() {return _r;}
|
||||
///Return the red component
|
||||
const double & red() const {return _r;}
|
||||
///Set the green component
|
||||
double & green() {return _g;}
|
||||
///Return the green component
|
||||
const double & green() const {return _g;}
|
||||
///Set the blue component
|
||||
double & blue() {return _b;}
|
||||
///Return the blue component
|
||||
const double & blue() const {return _b;}
|
||||
///Set the color components
|
||||
void set(double r,double g,double b) { _r=r;_g=g;_b=b; };
|
||||
};
|
||||
|
||||
/// White color constant
|
||||
extern const Color WHITE;
|
||||
/// Black color constant
|
||||
extern const Color BLACK;
|
||||
/// Red color constant
|
||||
extern const Color RED;
|
||||
/// Green color constant
|
||||
extern const Color GREEN;
|
||||
/// Blue color constant
|
||||
extern const Color BLUE;
|
||||
/// Yellow color constant
|
||||
extern const Color YELLOW;
|
||||
/// Magenta color constant
|
||||
extern const Color MAGENTA;
|
||||
/// Cyan color constant
|
||||
extern const Color CYAN;
|
||||
/// Grey color constant
|
||||
extern const Color GREY;
|
||||
/// Dark red color constant
|
||||
extern const Color DARK_RED;
|
||||
/// Dark green color constant
|
||||
extern const Color DARK_GREEN;
|
||||
/// Drak blue color constant
|
||||
extern const Color DARK_BLUE;
|
||||
/// Dark yellow color constant
|
||||
extern const Color DARK_YELLOW;
|
||||
/// Dark magenta color constant
|
||||
extern const Color DARK_MAGENTA;
|
||||
/// Dark cyan color constant
|
||||
extern const Color DARK_CYAN;
|
||||
|
||||
///Map <tt>int</tt>s to different <tt>Color</tt>s
|
||||
|
||||
///This map assigns one of the predefined \ref Color "Color"s to
|
||||
///each <tt>int</tt>. It is possible to change the colors as well as
|
||||
///their number. The integer range is cyclically mapped to the
|
||||
///provided set of colors.
|
||||
///
|
||||
///This is a true \ref concepts::ReferenceMap "reference map", so
|
||||
///you can also change the actual colors.
|
||||
|
||||
class Palette : public MapBase<int,Color>
|
||||
{
|
||||
std::vector<Color> colors;
|
||||
public:
|
||||
///Constructor
|
||||
|
||||
///Constructor.
|
||||
///\param have_white Indicates whether white is among the
|
||||
///provided initial colors (\c true) or not (\c false). If it is true,
|
||||
///white will be assigned to \c 0.
|
||||
///\param num The number of the allocated colors. If it is \c -1,
|
||||
///the default color configuration is set up (26 color plus optionaly the
|
||||
///white). If \c num is less then 26/27 then the default color
|
||||
///list is cut. Otherwise the color list is filled repeatedly with
|
||||
///the default color list. (The colors can be changed later on.)
|
||||
Palette(bool have_white=false,int num=-1)
|
||||
{
|
||||
if (num==0) return;
|
||||
do {
|
||||
if(have_white) colors.push_back(Color(1,1,1));
|
||||
|
||||
colors.push_back(Color(0,0,0));
|
||||
colors.push_back(Color(1,0,0));
|
||||
colors.push_back(Color(0,1,0));
|
||||
colors.push_back(Color(0,0,1));
|
||||
colors.push_back(Color(1,1,0));
|
||||
colors.push_back(Color(1,0,1));
|
||||
colors.push_back(Color(0,1,1));
|
||||
|
||||
colors.push_back(Color(.5,0,0));
|
||||
colors.push_back(Color(0,.5,0));
|
||||
colors.push_back(Color(0,0,.5));
|
||||
colors.push_back(Color(.5,.5,0));
|
||||
colors.push_back(Color(.5,0,.5));
|
||||
colors.push_back(Color(0,.5,.5));
|
||||
|
||||
colors.push_back(Color(.5,.5,.5));
|
||||
colors.push_back(Color(1,.5,.5));
|
||||
colors.push_back(Color(.5,1,.5));
|
||||
colors.push_back(Color(.5,.5,1));
|
||||
colors.push_back(Color(1,1,.5));
|
||||
colors.push_back(Color(1,.5,1));
|
||||
colors.push_back(Color(.5,1,1));
|
||||
|
||||
colors.push_back(Color(1,.5,0));
|
||||
colors.push_back(Color(.5,1,0));
|
||||
colors.push_back(Color(1,0,.5));
|
||||
colors.push_back(Color(0,1,.5));
|
||||
colors.push_back(Color(0,.5,1));
|
||||
colors.push_back(Color(.5,0,1));
|
||||
} while(int(colors.size())<num);
|
||||
if(num>=0) colors.resize(num);
|
||||
}
|
||||
///\e
|
||||
Color &operator[](int i)
|
||||
{
|
||||
return colors[i%colors.size()];
|
||||
}
|
||||
///\e
|
||||
const Color &operator[](int i) const
|
||||
{
|
||||
return colors[i%colors.size()];
|
||||
}
|
||||
///\e
|
||||
void set(int i,const Color &c)
|
||||
{
|
||||
colors[i%colors.size()]=c;
|
||||
}
|
||||
///Adds a new color to the end of the color list.
|
||||
void add(const Color &c)
|
||||
{
|
||||
colors.push_back(c);
|
||||
}
|
||||
|
||||
///Sets the number of the existing colors.
|
||||
void resize(int s) { colors.resize(s);}
|
||||
///Returns the number of the existing colors.
|
||||
int size() const { return int(colors.size());}
|
||||
};
|
||||
|
||||
///Returns a visibly distinct \ref Color
|
||||
|
||||
///Returns a \ref Color which is as different from the given parameter
|
||||
///as it is possible.
|
||||
inline Color distantColor(const Color &c)
|
||||
{
|
||||
return Color(c.red()<.5?1:0,c.green()<.5?1:0,c.blue()<.5?1:0);
|
||||
}
|
||||
///Returns black for light colors and white for the dark ones.
|
||||
|
||||
///Returns black for light colors and white for the dark ones.
|
||||
inline Color distantBW(const Color &c){
|
||||
return (.2125*c.red()+.7154*c.green()+.0721*c.blue())<.5 ? WHITE : BLACK;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
} //END OF NAMESPACE LEMON
|
||||
|
||||
#endif // LEMON_COLOR_H
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue