DCLN cooking and various bug fixes

This commit is contained in:
Jack Andersen 2017-10-16 19:51:53 -10:00
parent 4af2d975f4
commit 5149128b60
84 changed files with 23876 additions and 52 deletions

View File

@ -34,6 +34,7 @@ set(DNACOMMON_SOURCES
BabeDead.hpp BabeDead.cpp
RigInverter.hpp RigInverter.cpp
AROTBuilder.hpp AROTBuilder.cpp
OBBTreeBuilder.hpp OBBTreeBuilder.cpp
Tweaks/ITweak.hpp
Tweaks/TweakWriter.hpp
Tweaks/ITweakGame.hpp

View File

@ -83,16 +83,40 @@ template void DeafBabeSendToBlender<DNAMP1::DeafBabe>(hecl::BlenderConnection::P
template void DeafBabeSendToBlender<DNAMP2::DeafBabe>(hecl::BlenderConnection::PyOutStream& os, const DNAMP2::DeafBabe& db, bool isDcln, atInt32 idx);
template void DeafBabeSendToBlender<DNAMP1::DCLN::Collision>(hecl::BlenderConnection::PyOutStream& os, const DNAMP1::DCLN::Collision& db, bool isDcln, atInt32 idx);
template<class DEAFBABE>
static void PopulateAreaFields(DEAFBABE& db,
const hecl::BlenderConnection::DataStream::ColMesh& colMesh,
const zeus::CAABox& fullAABB,
std::enable_if_t<std::is_same<DEAFBABE, DNAMP1::DeafBabe>::value ||
std::is_same<DEAFBABE, DNAMP2::DeafBabe>::value, int>* = 0)
{
AROTBuilder builder;
auto octree = builder.buildCol(colMesh, db.rootNodeType);
static_cast<std::unique_ptr<atUint8[]>&>(db.bspTree) = std::move(octree.first);
db.bspSize = octree.second;
db.unk1 = 0x1000000;
db.length = db.binarySize(0) - 8;
db.magic = 0xDEAFBABE;
db.version = 3;
db.aabb[0] = fullAABB.min;
db.aabb[1] = fullAABB.max;
}
template<class DEAFBABE>
static void PopulateAreaFields(DEAFBABE& db,
const hecl::BlenderConnection::DataStream::ColMesh& colMesh,
const zeus::CAABox& fullAABB,
std::enable_if_t<std::is_same<DEAFBABE, DNAMP1::DCLN::Collision>::value, int>* = 0)
{
db.magic = 0xDEAFBABE;
db.version = 2;
db.memSize = 0;
}
template<class DEAFBABE>
void DeafBabeBuildFromBlender(DEAFBABE& db, const hecl::BlenderConnection::DataStream::ColMesh& colMesh)
{
{
AROTBuilder builder;
auto octree = builder.buildCol(colMesh, db.rootNodeType);
static_cast<std::unique_ptr<atUint8[]>&>(db.bspTree) = std::move(octree.first);
db.bspSize = octree.second;
}
db.materials.reserve(colMesh.materials.size());
for (const hecl::BlenderConnection::DataStream::ColMesh::Material& mat : colMesh.materials)
{
@ -186,15 +210,11 @@ void DeafBabeBuildFromBlender(DEAFBABE& db, const hecl::BlenderConnection::DataS
db.triMatsCount = colMesh.trianges.size();
db.triangleEdgesCount = colMesh.trianges.size() * 3;
db.unk1 = 0x1000000;
db.length = db.binarySize(0) - 8;
db.magic = 0xDEAFBABE;
db.version = 3;
db.aabb[0] = fullAABB.min;
db.aabb[1] = fullAABB.max;
PopulateAreaFields(db, colMesh, fullAABB);
}
template void DeafBabeBuildFromBlender<DNAMP1::DeafBabe>(DNAMP1::DeafBabe& db, const hecl::BlenderConnection::DataStream::ColMesh& colMesh);
template void DeafBabeBuildFromBlender<DNAMP2::DeafBabe>(DNAMP2::DeafBabe& db, const hecl::BlenderConnection::DataStream::ColMesh& colMesh);
template void DeafBabeBuildFromBlender<DNAMP1::DCLN::Collision>(DNAMP1::DCLN::Collision& db, const hecl::BlenderConnection::DataStream::ColMesh& colMesh);
}

View File

@ -0,0 +1,256 @@
#include <athena/Types.hpp>
#include "OBBTreeBuilder.hpp"
#include "zeus/CTransform.hpp"
#include "DataSpec/DNAMP1/DCLN.hpp"
#include "gmm/gmm.h"
namespace DataSpec
{
using ColMesh = hecl::BlenderConnection::DataStream::ColMesh;
struct FittedOBB
{
zeus::CTransform xf;
zeus::CVector3f he;
};
static std::vector<int> MakeRootTriangleIndex(const ColMesh& mesh)
{
std::vector<int> ret;
ret.reserve(mesh.trianges.size());
for (int i = 0; i < mesh.trianges.size(); ++i)
ret.push_back(i);
return ret;
}
static std::unordered_set<uint32_t> GetTriangleVerts(const ColMesh& mesh, int triIdx)
{
const ColMesh::Triangle& T = mesh.trianges[triIdx];
std::unordered_set<uint32_t> verts;
verts.insert(mesh.edges[T.edges[0]].verts[0]);
verts.insert(mesh.edges[T.edges[0]].verts[1]);
verts.insert(mesh.edges[T.edges[1]].verts[0]);
verts.insert(mesh.edges[T.edges[1]].verts[1]);
verts.insert(mesh.edges[T.edges[2]].verts[0]);
verts.insert(mesh.edges[T.edges[2]].verts[1]);
return verts;
}
// method to set the OBB parameters which produce a box oriented according to
// the covariance matrix C, which just containts the points pnts
static FittedOBB BuildFromCovarianceMatrix(gmm::dense_matrix<float>& C,
const ColMesh& mesh, const std::vector<int>& index)
{
FittedOBB ret;
// extract the eigenvalues and eigenvectors from C
gmm::dense_matrix<float> eigvec(3,3);
std::vector<float> eigval(3);
gmm::symmetric_qr_algorithm(C, eigval, eigvec);
// find the right, up and forward vectors from the eigenvectors
zeus::CVector3f r(eigvec(0,0), eigvec(1,0), eigvec(2,0));
zeus::CVector3f u(eigvec(0,1), eigvec(1,1), eigvec(2,1));
zeus::CVector3f f(eigvec(0,2), eigvec(1,2), eigvec(2,2));
r.normalize(); u.normalize(), f.normalize();
// set the rotation matrix using the eigvenvectors
ret.xf.basis[0][0]=r.x; ret.xf.basis[1][0]=u.x; ret.xf.basis[2][0]=f.x;
ret.xf.basis[0][1]=r.y; ret.xf.basis[1][1]=u.y; ret.xf.basis[2][1]=f.y;
ret.xf.basis[0][2]=r.z; ret.xf.basis[1][2]=u.z; ret.xf.basis[2][2]=f.z;
// now build the bounding box extents in the rotated frame
zeus::CVector3f minim(1e10f, 1e10f, 1e10f), maxim(-1e10f, -1e10f, -1e10f);
for (int triIdx : index)
{
std::unordered_set<uint32_t> verts = GetTriangleVerts(mesh, triIdx);
for (uint32_t v : verts)
{
const zeus::CVector3f& p = mesh.verts[v].val;
zeus::CVector3f p_prime(r.dot(p), u.dot(p), f.dot(p));
minim = zeus::min(minim, p_prime);
maxim = zeus::max(maxim, p_prime);
}
}
// set the center of the OBB to be the average of the
// minimum and maximum, and the extents be half of the
// difference between the minimum and maximum
zeus::CVector3f center = (maxim + minim) * 0.5f;
ret.xf.origin = ret.xf.basis * center;
ret.he = (maxim - minim) * 0.5f;
return ret;
}
// builds an OBB from triangles specified as an array of
// points with integer indices into the point array. Forms
// the covariance matrix for the triangles, then uses the
// method build_from_covariance_matrix() method to fit
// the box. ALL points will be fit in the box, regardless
// of whether they are indexed by a triangle or not.
static FittedOBB FitOBB(const ColMesh& mesh, const std::vector<int>& index)
{
float Ai, Am=0.0;
zeus::CVector3f mu, mui;
gmm::dense_matrix<float> C(3,3);
float cxx=0.0, cxy=0.0, cxz=0.0, cyy=0.0, cyz=0.0, czz=0.0;
// loop over the triangles this time to find the
// mean location
for (int i : index)
{
const ColMesh::Triangle& T = mesh.trianges[i];
std::unordered_set<uint32_t> verts = GetTriangleVerts(mesh, i);
auto it = verts.begin();
zeus::CVector3f p = mesh.verts[*it++].val;
zeus::CVector3f q = mesh.verts[*it++].val;
zeus::CVector3f r = mesh.verts[*it++].val;
mui = (p+q+r)/3.f;
Ai = (q-p).cross(r-p).magnitude() / 2.f;
mu += mui*Ai;
Am += Ai;
// these bits set the c terms to Am*E[xx], Am*E[xy], Am*E[xz]....
cxx += ( 9.0*mui.x*mui.x + p.x*p.x + q.x*q.x + r.x*r.x )*(Ai/12.0);
cxy += ( 9.0*mui.x*mui.y + p.x*p.y + q.x*q.y + r.x*r.y )*(Ai/12.0);
cxz += ( 9.0*mui.x*mui.z + p.x*p.z + q.x*q.z + r.x*r.z )*(Ai/12.0);
cyy += ( 9.0*mui.y*mui.y + p.y*p.y + q.y*q.y + r.y*r.y )*(Ai/12.0);
cyz += ( 9.0*mui.y*mui.z + p.y*p.z + q.y*q.z + r.y*r.z )*(Ai/12.0);
}
// divide out the Am fraction from the average position and
// covariance terms
mu = mu / Am;
cxx /= Am; cxy /= Am; cxz /= Am; cyy /= Am; cyz /= Am; czz /= Am;
// now subtract off the E[x]*E[x], E[x]*E[y], ... terms
cxx -= mu.x*mu.x; cxy -= mu.x*mu.y; cxz -= mu.x*mu.z;
cyy -= mu.y*mu.y; cyz -= mu.y*mu.z; czz -= mu.z*mu.z;
// now build the covariance matrix
C(0,0)=cxx; C(0,1)=cxy; C(0,2)=cxz;
C(1,0)=cxy; C(1,1)=cyy; C(1,2)=cyz;
C(2,0)=cxz; C(1,2)=cyz; C(2,2)=czz;
// set the obb parameters from the covariance matrix
return BuildFromCovarianceMatrix(C, mesh, index);
}
template <typename Node>
static void MakeLeaf(const ColMesh& mesh, const std::vector<int>& index, Node& n)
{
n.left.reset();
n.right.reset();
n.isLeaf = true;
n.leafData = std::make_unique<typename Node::LeafData>();
n.leafData->edgeIndexCount = atUint32(index.size() * 3);
n.leafData->edgeIndices.reserve(n.leafData->edgeIndexCount);
for (int i : index)
{
const ColMesh::Triangle& T = mesh.trianges[i];
for (int j = 0; j < 3; ++j)
n.leafData->edgeIndices.push_back(T.edges[j]);
}
}
template <typename Node>
static std::unique_ptr<Node> RecursiveMakeNode(const ColMesh& mesh, const std::vector<int>& index)
{
// calculate root OBB
FittedOBB obb = FitOBB(mesh, index);
// make results row-major and also invert the rotation basis
obb.xf.basis.transpose();
std::unique_ptr<Node> n = std::make_unique<Node>();
for (int i = 0; i < 3; ++i)
{
n->xf[i] = zeus::CVector4f{obb.xf.basis[i]};
n->xf[i].vec[3] = obb.xf.origin[i];
}
n->halfExtent = obb.he;
// terminate branch when volume < 1.0
if (obb.he[0] * obb.he[1] * obb.he[2] < 1.f)
{
MakeLeaf(mesh, index, *n);
return n;
}
n->isLeaf = false;
std::vector<int> indexNeg[3];
std::vector<int> indexPos[3];
for (int c = 0; c < 3; ++c)
{
// subdivide negative side
indexNeg[c].reserve(index.size());
for (int i : index)
{
std::unordered_set<uint32_t> verts = GetTriangleVerts(mesh, i);
for (uint32_t vtx : verts)
{
zeus::CVector3f v = mesh.verts[vtx].val;
v = obb.xf.basis * (v - obb.xf.origin);
if (v[c] < 0.f)
{
indexNeg[c].push_back(i);
break;
}
}
}
// subdivide positive side
indexPos[c].reserve(index.size());
for (int i : index)
{
std::unordered_set<uint32_t> verts = GetTriangleVerts(mesh, i);
for (uint32_t vtx : verts)
{
zeus::CVector3f v = mesh.verts[vtx].val;
v = obb.xf.basis * (v - obb.xf.origin);
if (v[c] >= 0.f)
{
indexPos[c].push_back(i);
break;
}
}
}
}
size_t idxMin = index.size();
int minComp = -1;
for (int c = 0; c < 3; ++c)
{
size_t test = std::max(indexNeg[c].size(), indexPos[c].size());
if (test < idxMin && test < index.size() * 3 / 4)
{
minComp = c;
idxMin = test;
}
}
if (minComp == -1)
{
MakeLeaf(mesh, index, *n);
return n;
}
n->left = RecursiveMakeNode<Node>(mesh, indexNeg[minComp]);
n->right = RecursiveMakeNode<Node>(mesh, indexPos[minComp]);
return n;
}
template <typename Node>
std::unique_ptr<Node> OBBTreeBuilder::buildCol(const ColMesh& mesh)
{
std::vector<int> root = MakeRootTriangleIndex(mesh);
return RecursiveMakeNode<Node>(mesh, root);
}
template std::unique_ptr<DNAMP1::DCLN::Collision::Node>
OBBTreeBuilder::buildCol<DNAMP1::DCLN::Collision::Node>(const ColMesh& mesh);
}

View File

@ -0,0 +1,18 @@
#ifndef DNACOMMON_OBBTREEBUILDER_HPP
#define DNACOMMON_OBBTREEBUILDER_HPP
#include "DNACommon.hpp"
namespace DataSpec
{
struct OBBTreeBuilder
{
using ColMesh = hecl::BlenderConnection::DataStream::ColMesh;
template <typename Node>
static std::unique_ptr<Node> buildCol(const ColMesh& mesh);
};
}
#endif // DNACOMMON_OBBTREEBUILDER_HPP

View File

@ -1,8 +1,10 @@
#ifndef __DNAMP1_DCLN_HPP__
#define __DNAMP1_DCLN_HPP__
#include <athena/Types.hpp>
#include "../DNACommon/DeafBabe.hpp"
#include "../DNACommon/PAK.hpp"
#include "../DNACommon/OBBTreeBuilder.hpp"
#include "DNAMP1.hpp"
#include "DeafBabe.hpp"
@ -13,6 +15,8 @@ namespace DNAMP1
struct DCLN : BigDNA
{
using Mesh = hecl::BlenderConnection::DataStream::ColMesh;
DECL_DNA
Value<atUint32> colCount;
struct Collision : BigDNA
@ -40,19 +44,20 @@ struct DCLN : BigDNA
Value<atUint32> vertCount;
Vector<atVec3f, DNA_COUNT(vertCount)> verts;
struct LeafData : BigDNA
{
DECL_DNA
Value<atUint32> edgeIndexCount;
Vector<atUint16, DNA_COUNT(edgeIndexCount)> edgeIndices;
size_t getMemoryUsage() const { return (((edgeIndices.size() * 2) + 16) + 3) & ~3; }
};
struct Node : BigDNA
{
Delete _d;
struct LeafData : BigDNA
{
DECL_DNA
Value<atUint32> edgeIndexCount;
Vector<atUint16, DNA_COUNT(edgeIndexCount)> edgeIndices;
size_t getMemoryUsage() const { return (((edgeIndices.size() * 2) + 16) + 3) & ~3; }
};
Value<atVec4f> xf[3];
Value<atVec3f> origin;
Value<atVec3f> halfExtent;
Value<bool> isLeaf;
std::unique_ptr<LeafData> leafData;
std::unique_ptr<Node> left;
@ -63,7 +68,7 @@ struct DCLN : BigDNA
xf[0] = __dna_reader.readVec4fBig();
xf[1] = __dna_reader.readVec4fBig();
xf[2] = __dna_reader.readVec4fBig();
origin = __dna_reader.readVec3fBig();
halfExtent = __dna_reader.readVec3fBig();
isLeaf = __dna_reader.readBool();
if (isLeaf)
{
@ -84,7 +89,7 @@ struct DCLN : BigDNA
__dna_writer.writeVec4fBig(xf[0]);
__dna_writer.writeVec4fBig(xf[1]);
__dna_writer.writeVec4fBig(xf[2]);
__dna_writer.writeVec3fBig(origin);
__dna_writer.writeVec3fBig(halfExtent);
__dna_writer.writeBool(isLeaf);
if (isLeaf && leafData)
leafData->write(__dna_writer);
@ -121,6 +126,30 @@ struct DCLN : BigDNA
return (ret + 3) & ~3;
}
void sendToBlender(hecl::BlenderConnection::PyOutStream& os) const
{
os.format("obj = bpy.data.objects.new('%s', None)\n"
"obj.empty_draw_type = 'CUBE'\n"
"bpy.context.scene.objects.link(obj)\n"
"mtx = Matrix(((%f,%f,%f,%f),(%f,%f,%f,%f),(%f,%f,%f,%f),(0.0,0.0,0.0,1.0)))\n"
"mtxd = mtx.decompose()\n"
"obj.rotation_mode = 'QUATERNION'\n"
"obj.location = mtxd[0]\n"
"obj.rotation_quaternion = mtxd[1]\n"
"obj.scale = (%f,%f,%f)\n", isLeaf ? "leaf" : "branch",
xf[0].vec[0], xf[0].vec[1], xf[0].vec[2], xf[0].vec[3],
xf[1].vec[0], xf[1].vec[1], xf[1].vec[2], xf[1].vec[3],
xf[2].vec[0], xf[2].vec[1], xf[2].vec[2], xf[2].vec[3],
halfExtent.vec[0], halfExtent.vec[1], halfExtent.vec[2]);
if (isLeaf)
os << "obj.show_name = True\n";
if (!isLeaf)
{
left->sendToBlender(os);
right->sendToBlender(os);
}
}
};
Node root;
size_t getMemoryUsage()
@ -141,7 +170,8 @@ struct DCLN : BigDNA
hecl::BlenderConnection::PyOutStream os = conn.beginPythonOut(true);
os.format("import bpy\n"
"import bmesh\n"
"from mathutils import Vector\n"
"from mathutils import Vector, Matrix\n"
"\n"
"bpy.context.scene.name = '%s'\n"
"# Clear Scene\n"
@ -154,7 +184,10 @@ struct DCLN : BigDNA
DeafBabe::BlenderInit(os);
atInt32 idx = 0;
for (const Collision& col : collision)
{
DeafBabeSendToBlender(os, col, true, idx++);
col.root.sendToBlender(os);
}
os.centerView();
os.close();
}
@ -171,12 +204,33 @@ struct DCLN : BigDNA
DCLN dcln;
dcln.read(rs);
hecl::BlenderConnection& conn = btok.getBlenderConnection();
if (!conn.createBlend(outPath, hecl::BlenderConnection::BlendType::Mesh))
if (!conn.createBlend(outPath, hecl::BlenderConnection::BlendType::ColMesh))
return false;
dcln.sendToBlender(conn, pakRouter.getBestEntryName(entry, false));
return conn.saveBlend();
}
static bool Cook(const hecl::ProjectPath& outPath,
const hecl::ProjectPath& inPath,
const std::vector<Mesh>& meshes,
hecl::BlenderConnection* conn = nullptr)
{
DCLN dcln;
dcln.colCount = atUint32(meshes.size());
for (const Mesh& mesh : meshes)
{
dcln.collision.emplace_back();
Collision& colOut = dcln.collision.back();
DeafBabeBuildFromBlender(colOut, mesh);
colOut.root = std::move(*OBBTreeBuilder::buildCol<Collision::Node>(mesh));
colOut.memSize = atUint32(colOut.root.getMemoryUsage());
}
athena::io::FileWriter w(outPath.getAbsolutePath());
dcln.write(w);
return true;
}
};
}

View File

@ -22,7 +22,7 @@ struct CameraHint : IScriptObject
{
DECL_YAML
Value<atUint32> propertyCount;
Value<bool> unknown1; // 0x1
Value<bool> calculateCamPos; // 0x1
Value<bool> chaseAllowed; // 0x2
Value<bool> boostAllowed; // 0x4
Value<bool> obscureAvoidance; // 0x8

View File

@ -249,6 +249,12 @@ void SpecBase::doCook(const hecl::ProjectPath& path, const hecl::ProjectPath& co
cookMesh(cookedPath, path, ds, fast, btok, progress);
break;
}
case hecl::BlenderConnection::BlendType::ColMesh:
{
hecl::BlenderConnection::DataStream ds = conn.beginData();
cookColMesh(cookedPath, path, ds, fast, btok, progress);
break;
}
case hecl::BlenderConnection::BlendType::Actor:
{
hecl::BlenderConnection::DataStream ds = conn.beginData();

View File

@ -71,6 +71,9 @@ struct SpecBase : hecl::Database::IDataSpec
virtual void cookMesh(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
FCookProgress progress)=0;
virtual void cookColMesh(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
FCookProgress progress)=0;
virtual void cookActor(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
FCookProgress progress)=0;

View File

@ -10,6 +10,7 @@
#include "DNAMP1/STRG.hpp"
#include "DNAMP1/SCAN.hpp"
#include "DNAMP1/CMDL.hpp"
#include "DNAMP1/DCLN.hpp"
#include "DNAMP1/MREA.hpp"
#include "DNAMP1/ANCS.hpp"
#include "DNAMP1/AGSC.hpp"
@ -555,6 +556,8 @@ struct SpecMP1 : SpecBase
{
case hecl::BlenderConnection::BlendType::Mesh:
return {SBIG('CMDL'), path.hash().val32()};
case hecl::BlenderConnection::BlendType::ColMesh:
return {SBIG('DCLN'), path.hash().val32()};
case hecl::BlenderConnection::BlendType::Actor:
if (path.getAuxInfo().size())
{
@ -728,6 +731,14 @@ struct SpecMP1 : SpecBase
DNAMP1::CMDL::Cook(out, in, mesh);
}
void cookColMesh(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast,
hecl::BlenderToken& btok, FCookProgress progress)
{
std::vector<ColMesh> mesh = ds.compileColMeshes();
ds.close();
DNAMP1::DCLN::Cook(out, in, mesh);
}
void cookActor(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast,
hecl::BlenderToken& btok, FCookProgress progress)
{

View File

@ -329,6 +329,12 @@ struct SpecMP2 : SpecBase
{
}
void cookColMesh(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
FCookProgress progress)
{
}
void cookActor(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
FCookProgress progress)

View File

@ -523,6 +523,12 @@ struct SpecMP3 : SpecBase
{
}
void cookColMesh(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
FCookProgress progress)
{
}
void cookActor(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
FCookProgress progress)

View File

@ -37,6 +37,7 @@ void ViewManager::BuildTestPART()
void ViewManager::InitMP1(MP1::CMain& main)
{
main.Init(m_fileStoreManager, m_mainWindow.get(), m_voiceEngine.get(), *m_amuseAllocWrapper);
main.WarmupShaders();
}
void ViewManager::TestGameView::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub)

13
GMM-LICENSE Normal file
View File

@ -0,0 +1,13 @@
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and the GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program (see GNU_GPL_V3, GNU_LGPL_V3 and
GNU_GCC_RUNTIME_EXCEPTION files); if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

View File

@ -2423,9 +2423,9 @@ void CBallCamera::ApplyCameraHint(CStateManager& mgr)
zeus::CVector3f camPos = mgr.GetPlayer().GetBallPosition() + hint->GetHint().GetBallToCam();
if ((hint->GetHint().GetOverrideFlags() & 0x1) != 0)
{
float f30 = hint->GetHint().GetBallToCam().toVec2f().magnitude();
zeus::CVector3f x23c = -zeus::CVector3f(hint->GetHint().GetBallToCam().toVec2f()).normalized();
camPos = FindDesiredPosition(f30, hint->GetHint().GetBallToCam().z, x23c, mgr, false);
float distance = hint->GetHint().GetBallToCam().toVec2f().magnitude();
zeus::CVector3f camToBall = -zeus::CVector3f(hint->GetHint().GetBallToCam().toVec2f()).normalized();
camPos = FindDesiredPosition(distance, hint->GetHint().GetBallToCam().z, camToBall, mgr, false);
}
TeleportCamera(zeus::lookAt(camPos, x1d8_lookPos), mgr);
break;

View File

@ -53,6 +53,8 @@ public:
class CBooRenderer : public IRenderer
{
friend class CBooModel;
friend class CModel;
friend class CGameArea;
friend class CWorldTransManager;
friend class CMorphBallShadow;

View File

@ -73,6 +73,7 @@ struct CBooSurface
class CBooModel
{
friend class CModel;
friend class CGameArea;
friend class CBooRenderer;
friend class CMetroidModelInstance;
friend class CSkinnedModel;
@ -151,6 +152,8 @@ private:
void DrawNormalSurfaces(const CModelFlags& flags) const;
void DrawSurfaces(const CModelFlags& flags) const;
void DrawSurface(const CBooSurface& surf, const CModelFlags& flags) const;
void WarmupDrawSurfaces() const;
void WarmupDrawSurface(const CBooSurface& surf) const;
static zeus::CVector3f g_PlayerPosition;
static float g_ModSeconds;
@ -177,6 +180,7 @@ public:
void RemapMaterialData(SShader& shader);
bool TryLockTextures() const;
void UnlockTextures() const;
void SyncLoadTextures() const;
void Touch(int shaderIdx) const;
void VerifyCurrentShader(int shaderIdx);
boo::IGraphicsBufferD* UpdateUniformData(const CModelFlags& flags,
@ -214,15 +218,8 @@ public:
static boo::ITexture* g_shadowMap;
static zeus::CTransform g_shadowTexXf;
static void EnableShadowMaps(boo::ITexture* map, const zeus::CTransform& texXf)
{
g_shadowMap = map;
g_shadowTexXf = texXf;
}
static void DisableShadowMaps()
{
g_shadowMap = nullptr;
}
static void EnableShadowMaps(boo::ITexture* map, const zeus::CTransform& texXf);
static void DisableShadowMaps();
};
class CModel
@ -270,6 +267,9 @@ public:
zeus::CVector3f GetPoolNormal(size_t idx) const;
void ApplyVerticesCPU(boo::IGraphicsBufferD* vertBuf,
const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) const;
void _WarmupShaders();
static void WarmupShaders(const SObjectTag& cmdlTag);
};
CFactoryFnReturn FModelFactory(const urde::SObjectTag& tag,

View File

@ -126,6 +126,16 @@ void CBooModel::EnsureViewDepStateCached(const CBooModel& model, const CBooSurfa
boo::ITexture* CBooModel::g_shadowMap = nullptr;
zeus::CTransform CBooModel::g_shadowTexXf;
void CBooModel::EnableShadowMaps(boo::ITexture* map, const zeus::CTransform& texXf)
{
g_shadowMap = map;
g_shadowTexXf = texXf;
}
void CBooModel::DisableShadowMaps()
{
g_shadowMap = nullptr;
}
CBooModel::~CBooModel()
{
if (m_prev)
@ -488,6 +498,16 @@ void CBooModel::UnlockTextures() const
const_cast<CBooModel*>(this)->x40_24_texturesLoaded = false;
}
void CBooModel::SyncLoadTextures() const
{
if (!x40_24_texturesLoaded)
{
for (TCachedToken<CTexture>& tex : const_cast<std::vector<TCachedToken<CTexture>>&>(x1c_textures))
tex.GetObj();
const_cast<CBooModel*>(this)->x40_24_texturesLoaded = true;
}
}
void CBooModel::DrawFlat(ESurfaceSelection sel, EExtendedShader extendedIdx) const
{
const CBooSurface* surf;
@ -571,6 +591,39 @@ void CBooModel::DrawSurface(const CBooSurface& surf, const CModelFlags& flags) c
CGraphics::DrawArrayIndexed(surf.m_data.idxStart, surf.m_data.idxCount);
}
void CBooModel::WarmupDrawSurfaces() const
{
const CBooSurface* surf = x38_firstUnsortedSurface;
while (surf)
{
WarmupDrawSurface(*surf);
surf = surf->m_next;
}
surf = x3c_firstSortedSurface;
while (surf)
{
WarmupDrawSurface(*surf);
surf = surf->m_next;
}
}
void CBooModel::WarmupDrawSurface(const CBooSurface& surf) const
{
if (m_uniUpdateCount > m_instances.size())
return;
const ModelInstance& inst = m_instances[m_uniUpdateCount-1];
for (const std::vector<boo::IShaderDataBinding*>& extendeds : inst.m_shaderDataBindings)
{
for (boo::IShaderDataBinding* binding : extendeds)
{
CGraphics::SetShaderDataBinding(binding);
CGraphics::DrawArrayIndexed(surf.m_data.idxStart, std::min(u32(3), surf.m_data.idxCount));
}
}
}
void CBooModel::UVAnimationBuffer::ProcessAnimation(u8*& bufOut, const UVAnimation& anim)
{
zeus::CMatrix4f& texMtxOut = reinterpret_cast<zeus::CMatrix4f&>(*bufOut);
@ -1041,6 +1094,9 @@ CModel::CModel(std::unique_ptr<u8[]>&& in, u32 /* dataLen */, IObjectStore* stor
m_gfxToken = CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) -> bool
{
/* Index buffer is always static */
m_ibo = ctx.newStaticBuffer(boo::BufferUse::Index, iboData, 4, m_hmdlMeta.indexCount);
if (!m_hmdlMeta.bankCount)
{
/* Non-skinned models use static vertex buffers shared with CBooModel instances */
@ -1056,8 +1112,6 @@ CModel::CModel(std::unique_ptr<u8[]>&& in, u32 /* dataLen */, IObjectStore* stor
memmove(m_dynamicVertexData.get(), vboData, vboSz);
}
/* Index buffer is always static */
m_ibo = ctx.newStaticBuffer(boo::BufferUse::Index, iboData, 4, m_hmdlMeta.indexCount);
return true;
});
@ -1172,6 +1226,36 @@ void CModel::ApplyVerticesCPU(boo::IGraphicsBufferD* vertBuf,
vertBuf->unmap();
}
void CModel::_WarmupShaders()
{
CBooModel::EnableShadowMaps(g_Renderer->x220_sphereRamp, zeus::CTransform::Identity());
CGraphics::CProjectionState backupProj = CGraphics::GetProjectionState();
zeus::CTransform backupViewPoint = CGraphics::g_ViewMatrix;
zeus::CTransform backupModel = CGraphics::g_GXModelMatrix;
CGraphics::SetModelMatrix(zeus::CTransform::Translate(-m_aabb.center()));
CGraphics::SetViewPointMatrix(zeus::CTransform::Translate(0.f, -2048.f, 0.f));
CGraphics::SetOrtho(-2048.f, 2048.f, 2048.f, -2048.f, 0.f, 4096.f);
CModelFlags defaultFlags;
for (CBooModel::SShader& shader : x18_matSets)
{
GetInstance().RemapMaterialData(shader);
GetInstance().SyncLoadTextures();
GetInstance().UpdateUniformData(defaultFlags, nullptr, nullptr);
GetInstance().WarmupDrawSurfaces();
}
CGraphics::SetProjectionState(backupProj);
CGraphics::SetViewPointMatrix(backupViewPoint);
CGraphics::SetModelMatrix(backupModel);
CBooModel::DisableShadowMaps();
}
void CModel::WarmupShaders(const SObjectTag& cmdlTag)
{
TToken<CModel> model = g_SimplePool->GetObj(cmdlTag);
CModel* modelObj = model.GetObj();
modelObj->_WarmupShaders();
}
CFactoryFnReturn FModelFactory(const urde::SObjectTag& tag,
std::unique_ptr<u8[]>&& in, u32 len,
const urde::CVParamTransfer& vparms,

View File

@ -93,7 +93,7 @@ static const char* LightingShadowGLSL =
" lights[0].angAtt[1] * angDot +\n"
" lights[0].angAtt[0];\n"
" ret += lights[0].color * clamp(angAtt, 0.0, 1.0) * att * clamp(dot(normalize(-delta), mvNormIn.xyz), 0.0, 1.0) *\n"
" texture(extTex0, vtf.extTcgs[0]).r;\n"
" texture(extTex7, vtf.extTcgs[0]).r;\n"
" \n"
" for (int i=1 ; i<" _XSTR(URDE_MAX_LIGHTS) " ; ++i)\n"
" {\n"

View File

@ -92,7 +92,7 @@ static const char* LightingShadowHLSL =
" lights[0].angAtt[1] * angDot +\n"
" lights[0].angAtt[0];\n"
" ret += lights[0].color * saturate(angAtt) * att * saturate(dot(normalize(-delta), mvNormIn.xyz)) *\n"
" extTex0.Sample(clampSamp, vtf.extTcgs[0]).r;\n"
" extTex7.Sample(clampSamp, vtf.extTcgs[0]).r;\n"
" \n"
" for (int i=1 ; i<" _XSTR(URDE_MAX_LIGHTS) " ; ++i)\n"
" {\n"

View File

@ -79,7 +79,7 @@ static const char* LightingShadowMetal =
"};\n"
"\n"
"static float4 EXTLightingShadowFunc(constant LightingUniform& lu, float4 mvPosIn, float4 mvNormIn,\n"
" thread VertToFrag& vtf, texture2d<float> extTex0)\n"
" thread VertToFrag& vtf, texture2d<float> extTex7)\n"
"{\n"
" float4 ret = lu.ambient;\n"
" \n"
@ -93,7 +93,7 @@ static const char* LightingShadowMetal =
" lu.lights[0].angAtt[1] * angDot +\n"
" lu.lights[0].angAtt[0];\n"
" ret += lu.lights[0].color * saturate(angAtt) * att * saturate(dot(normalize(-delta), mvNormIn.xyz)) *\n"
" extTex0.sample(clampSamp, vtf.extTcgs0);\n"
" extTex7.sample(clampSamp, vtf.extTcgs0);\n"
" \n"
" for (int i=1 ; i<" _XSTR(URDE_MAX_LIGHTS) " ; ++i)\n"
" {\n"

View File

@ -27,7 +27,7 @@ BOO_GLSL_BINDING_HEAD
"void main()\n"
"{\n"
" vtf.color = colorIn;\n"
" vtf.uv = uvIn;\n"
" vtf.uv = uvIn.xy;\n"
" gl_Position = mvp * vec4(posIn.xyz, 1.0);\n"
"}\n";

View File

@ -29,7 +29,7 @@ static const char* VS =
"{\n"
" VertToFrag vtf;\n"
" vtf.color = v.colorIn;\n"
" vtf.uv = v.uvIn;\n"
" vtf.uv = v.uvIn.xy;\n"
" vtf.pos = mul(mvp, float4(v.posIn.xyz, 1.0));\n"
" return vtf;\n"
"}\n";

View File

@ -31,7 +31,7 @@ static const char* VS =
"{\n"
" VertToFrag vtf;\n"
" vtf.color = v.colorIn;\n"
" vtf.uv = v.uvIn;\n"
" vtf.uv = v.uvIn.xy;\n"
" vtf.pos = su.mvp * float4(v.posIn.xyz, 1.0);\n"
" return vtf;\n"
"}\n";

View File

@ -40,9 +40,10 @@ public:
virtual void Draw()=0;
virtual bool Proc()=0;
virtual void Shutdown()=0;
virtual boo::IWindow* GetMainWindow() const=0;
virtual boo::IWindow* GetMainWindow() const= 0;
virtual void SetFlowState(EFlowState) = 0;
virtual size_t GetExpectedIdSize() const = 0;
virtual void WarmupShaders() = 0;
};
}

View File

@ -17,14 +17,14 @@
#include "Graphics/Shaders/CFluidPlaneShader.hpp"
#include "Graphics/Shaders/CAABoxShader.hpp"
#include "Graphics/Shaders/CWorldShadowShader.hpp"
#include "Character/CCharLayoutInfo.hpp"
#include "Graphics/Shaders/CParticleSwooshShaders.hpp"
#include "Audio/CStreamAudioManager.hpp"
#include "CGBASupport.hpp"
#include "CBasics.hpp"
#include "Audio/CAudioGroupSet.hpp"
namespace urde
{
URDE_DECL_SPECIALIZE_SHADER(CParticleSwooshShaders)
URDE_DECL_SPECIALIZE_SHADER(CThermalColdFilter)
URDE_DECL_SPECIALIZE_SHADER(CThermalHotFilter)
URDE_DECL_SPECIALIZE_SHADER(CSpaceWarpFilter)
@ -223,6 +223,7 @@ CMain::BooSetter::BooSetter(boo::IGraphicsDataFactory* factory,
boo::ITextureR* spareTex)
{
CGraphics::InitializeBoo(factory, cmdQ, spareTex);
TShader<CParticleSwooshShaders>::Initialize();
TShader<CThermalColdFilter>::Initialize();
TShader<CThermalHotFilter>::Initialize();
TShader<CSpaceWarpFilter>::Initialize();
@ -318,8 +319,40 @@ void CMain::Init(const hecl::Runtime::FileStoreManager& storeMgr,
//CStreamAudioManager::Start(false, "Audio/rui_samusL.dsp|Audio/rui_samusR.dsp", 0x7f, true, 1.f, 1.f);
}
static logvisor::Module WarmupLog("Shader Warmup");
void CMain::WarmupShaders()
{
if (m_warmupTags.size())
return;
size_t modelCount = 0;
g_ResFactory->EnumerateResources([&](const SObjectTag& tag)
{
if (tag.type == FOURCC('CMDL') || tag.type == FOURCC('MREA'))
++modelCount;
return true;
});
m_warmupTags.reserve(modelCount);
g_ResFactory->EnumerateResources([&](const SObjectTag& tag)
{
if (tag.type == FOURCC('CMDL') || tag.type == FOURCC('MREA'))
m_warmupTags.push_back(tag);
return true;
});
m_warmupIt = m_warmupTags.begin();
WarmupLog.report(logvisor::Info, "Began warmup of %" PRISize " objects", modelCount);
}
bool CMain::Proc()
{
// Warmup cycle overrides update
if (m_warmupTags.size())
return false;
CGBASupport::GlobalPoll();
x164_archSupport->UpdateTicks();
x164_archSupport->Update();
@ -340,6 +373,33 @@ bool CMain::Proc()
void CMain::Draw()
{
// Warmup cycle overrides draw
if (m_warmupTags.size())
{
auto startTime = std::chrono::steady_clock::now();
while (m_warmupIt != m_warmupTags.end())
{
WarmupLog.report(logvisor::Info, "Warming %.4s %08X", m_warmupIt->type.getChars(), m_warmupIt->id.Value());
if (m_warmupIt->type == FOURCC('CMDL'))
CModel::WarmupShaders(*m_warmupIt);
else if (m_warmupIt->type == FOURCC('MREA'))
CGameArea::WarmupShaders(*m_warmupIt);
++m_warmupIt;
// Approximately 3/4 frame of warmups
auto curTime = std::chrono::steady_clock::now();
if (std::chrono::duration_cast<std::chrono::milliseconds>(curTime - startTime).count() > 12)
break;
}
if (m_warmupIt == m_warmupTags.end())
{
m_warmupTags = std::vector<SObjectTag>();
WarmupLog.report(logvisor::Info, "Finished warmup");
}
return;
}
x164_archSupport->Draw();
}
@ -359,6 +419,7 @@ void CMain::Shutdown()
{
x164_archSupport.reset();
ShutdownSubsystems();
TShader<CParticleSwooshShaders>::Shutdown();
TShader<CThermalColdFilter>::Shutdown();
TShader<CThermalHotFilter>::Shutdown();
TShader<CSpaceWarpFilter>::Shutdown();

View File

@ -240,6 +240,10 @@ private:
boo::IWindow* m_mainWindow = nullptr;
// Warmup state
std::vector<SObjectTag> m_warmupTags;
std::vector<SObjectTag>::iterator m_warmupIt;
void InitializeSubsystems(const hecl::Runtime::FileStoreManager& storeMgr);
public:
@ -259,6 +263,7 @@ public:
boo::IWindow* window,
boo::IAudioVoiceEngine* voiceEngine,
amuse::IBackendVoiceAllocator& backend);
void WarmupShaders();
bool Proc();
void Draw();
void Shutdown();

View File

@ -411,6 +411,39 @@ CGameArea::CGameArea(CInputStream& in, int idx, int mlvlVersion)
xec_totalResourcesSize += g_ResFactory->ResourceSize(SObjectTag{FOURCC('MREA'), x84_mrea});
}
CGameArea::CGameArea(CAssetId mreaId)
: x84_mrea(mreaId)
{
while (StartStreamingMainArea()) {}
for (auto& req : xf8_loadTransactions)
req->WaitForComplete();
MREAHeader header = VerifyHeader();
x12c_postConstructed->x4c_insts.reserve(header.modelCount);
FillInStaticGeometry();
CBooModel::EnableShadowMaps(g_Renderer->x220_sphereRamp, zeus::CTransform::Identity());
CGraphics::CProjectionState backupProj = CGraphics::GetProjectionState();
zeus::CTransform backupViewPoint = CGraphics::g_ViewMatrix;
zeus::CTransform backupModel = CGraphics::g_GXModelMatrix;
CGraphics::SetViewPointMatrix(zeus::CTransform::Translate(0.f, -2048.f, 0.f));
CGraphics::SetOrtho(-2048.f, 2048.f, 2048.f, -2048.f, 0.f, 4096.f);
CModelFlags defaultFlags;
for (CMetroidModelInstance& inst : x12c_postConstructed->x4c_insts)
{
CGraphics::SetModelMatrix(zeus::CTransform::Translate(-inst.x34_aabb.center()));
inst.m_instance->SyncLoadTextures();
inst.m_instance->UpdateUniformData(defaultFlags, nullptr, nullptr);
inst.m_instance->WarmupDrawSurfaces();
}
CGraphics::SetProjectionState(backupProj);
CGraphics::SetViewPointMatrix(backupViewPoint);
CGraphics::SetModelMatrix(backupModel);
CBooModel::DisableShadowMaps();
}
bool CGameArea::IGetScriptingMemoryAlways() const
{
return false;
@ -1192,5 +1225,10 @@ bool CGameArea::CAreaObjectList::IsQualified(const CEntity& ent)
{
return (ent.GetAreaIdAlways() == x200c_areaIdx);
}
void CGameArea::WarmupShaders(const SObjectTag& mreaTag)
{
// Calling this version of the constructor performs warmup implicitly
CGameArea area(mreaTag.id);
}
}

View File

@ -289,6 +289,7 @@ private:
public:
CGameArea(CInputStream& in, int idx, int mlvlVersion);
CGameArea(CAssetId mreaId); // Warmup constructor
bool IsFinishedOccluding() const;
void ReadDependencyList();
@ -372,6 +373,8 @@ public:
CObjectList& GetAreaObjects() const { return *GetPostConstructed()->x10c0_areaObjs.get(); }
CGameArea* GetNext() const { return x130_next; }
static void WarmupShaders(const SObjectTag& mreaTag);
};
}

54
gmm/gmm.h Normal file
View File

@ -0,0 +1,54 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date October 13, 2002.
@brief Include common gmm files.
*/
#ifndef GMM_H__
#define GMM_H__
#include "gmm_kernel.h"
#include "gmm_dense_lu.h"
#include "gmm_dense_qr.h"
#include "gmm_iter_solvers.h"
#include "gmm_condition_number.h"
#include "gmm_inoutput.h"
#include "gmm_lapack_interface.h"
#include "gmm_superlu_interface.h"
#include "gmm_range_basis.h"
#include "gmm_domain_decomp.h"
#endif // GMM_H__

355
gmm/gmm_MUMPS_interface.h Normal file
View File

@ -0,0 +1,355 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2003-2017 Yves Renard, Julien Pommier
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_MUMPS_interface.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>,
@author Julien Pommier <Julien.Pommier@insa-toulouse.fr>
@date December 8, 2005.
@brief Interface with MUMPS (LU direct solver for sparse matrices).
*/
#if defined(GMM_USES_MUMPS) || defined(HAVE_DMUMPS_C_H)
#ifndef GMM_MUMPS_INTERFACE_H
#define GMM_MUMPS_INTERFACE_H
#include "gmm_kernel.h"
extern "C" {
#include <smumps_c.h>
#undef F_INT
#undef F_DOUBLE
#undef F_DOUBLE2
#include <dmumps_c.h>
#undef F_INT
#undef F_DOUBLE
#undef F_DOUBLE2
#include <cmumps_c.h>
#undef F_INT
#undef F_DOUBLE
#undef F_DOUBLE2
#include <zmumps_c.h>
#undef F_INT
#undef F_DOUBLE
#undef F_DOUBLE2
}
namespace gmm {
#define ICNTL(I) icntl[(I)-1]
#define INFO(I) info[(I)-1]
#define INFOG(I) infog[(I)-1]
#define RINFOG(I) rinfog[(I)-1]
template <typename T> struct ij_sparse_matrix {
std::vector<int> irn;
std::vector<int> jcn;
std::vector<T> a;
bool sym;
template <typename L> void store(const L& l, size_type i) {
typename linalg_traits<L>::const_iterator it = vect_const_begin(l),
ite = vect_const_end(l);
for (; it != ite; ++it) {
int ir = (int)i + 1, jc = (int)it.index() + 1;
if (*it != T(0) && (!sym || ir >= jc))
{ irn.push_back(ir); jcn.push_back(jc); a.push_back(*it); }
}
}
template <typename L> void build_from(const L& l, row_major) {
for (size_type i = 0; i < mat_nrows(l); ++i)
store(mat_const_row(l, i), i);
}
template <typename L> void build_from(const L& l, col_major) {
for (size_type i = 0; i < mat_ncols(l); ++i)
store(mat_const_col(l, i), i);
irn.swap(jcn);
}
template <typename L> ij_sparse_matrix(const L& A, bool sym_) {
size_type nz = nnz(A);
sym = sym_;
irn.reserve(nz); jcn.reserve(nz); a.reserve(nz);
build_from(A, typename principal_orientation_type<typename
linalg_traits<L>::sub_orientation>::potype());
}
};
/* ********************************************************************* */
/* MUMPS solve interface */
/* ********************************************************************* */
template <typename T> struct mumps_interf {};
template <> struct mumps_interf<float> {
typedef SMUMPS_STRUC_C MUMPS_STRUC_C;
typedef float value_type;
static void mumps_c(MUMPS_STRUC_C &id) { smumps_c(&id); }
};
template <> struct mumps_interf<double> {
typedef DMUMPS_STRUC_C MUMPS_STRUC_C;
typedef double value_type;
static void mumps_c(MUMPS_STRUC_C &id) { dmumps_c(&id); }
};
template <> struct mumps_interf<std::complex<float> > {
typedef CMUMPS_STRUC_C MUMPS_STRUC_C;
typedef mumps_complex value_type;
static void mumps_c(MUMPS_STRUC_C &id) { cmumps_c(&id); }
};
template <> struct mumps_interf<std::complex<double> > {
typedef ZMUMPS_STRUC_C MUMPS_STRUC_C;
typedef mumps_double_complex value_type;
static void mumps_c(MUMPS_STRUC_C &id) { zmumps_c(&id); }
};
template <typename MUMPS_STRUCT>
static inline bool mumps_error_check(MUMPS_STRUCT &id) {
if (id.INFO(1) < 0) {
switch (id.INFO(1)) {
case -2:
GMM_ASSERT1(false, "Solve with MUMPS failed: NZ = " << id.INFO(2)
<< " is out of range");
case -6 : case -10 :
GMM_WARNING1("Solve with MUMPS failed: matrix is singular");
return false;
case -9:
GMM_ASSERT1(false, "Solve with MUMPS failed: error "
<< id.INFO(1) << ", increase ICNTL(14)");
case -13 :
GMM_ASSERT1(false, "Solve with MUMPS failed: not enough memory");
default :
GMM_ASSERT1(false, "Solve with MUMPS failed with error "
<< id.INFO(1));
}
}
return true;
}
/** MUMPS solve interface
* Works only with sparse or skyline matrices
*/
template <typename MAT, typename VECTX, typename VECTB>
bool MUMPS_solve(const MAT &A, const VECTX &X_, const VECTB &B,
bool sym = false, bool distributed = false) {
VECTX &X = const_cast<VECTX &>(X_);
typedef typename linalg_traits<MAT>::value_type T;
typedef typename mumps_interf<T>::value_type MUMPS_T;
GMM_ASSERT2(gmm::mat_nrows(A) == gmm::mat_ncols(A), "Non-square matrix");
std::vector<T> rhs(gmm::vect_size(B)); gmm::copy(B, rhs);
ij_sparse_matrix<T> AA(A, sym);
const int JOB_INIT = -1;
const int JOB_END = -2;
const int USE_COMM_WORLD = -987654;
typename mumps_interf<T>::MUMPS_STRUC_C id;
int rank(0);
#ifdef GMM_USES_MPI
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
#endif
id.job = JOB_INIT;
id.par = 1;
id.sym = sym ? 2 : 0;
id.comm_fortran = USE_COMM_WORLD;
mumps_interf<T>::mumps_c(id);
if (rank == 0 || distributed) {
id.n = int(gmm::mat_nrows(A));
if (distributed) {
id.nz_loc = int(AA.irn.size());
id.irn_loc = &(AA.irn[0]);
id.jcn_loc = &(AA.jcn[0]);
id.a_loc = (MUMPS_T*)(&(AA.a[0]));
} else {
id.nz = int(AA.irn.size());
id.irn = &(AA.irn[0]);
id.jcn = &(AA.jcn[0]);
id.a = (MUMPS_T*)(&(AA.a[0]));
}
if (rank == 0)
id.rhs = (MUMPS_T*)(&(rhs[0]));
}
id.ICNTL(1) = -1; // output stream for error messages
id.ICNTL(2) = -1; // output stream for other messages
id.ICNTL(3) = -1; // output stream for global information
id.ICNTL(4) = 0; // verbosity level
if (distributed)
id.ICNTL(5) = 0; // assembled input matrix (default)
id.ICNTL(14) += 80; /* small boost to the workspace size as we have encountered some problem
who did not fit in the default settings of mumps..
by default, ICNTL(14) = 15 or 20
*/
//cout << "ICNTL(14): " << id.ICNTL(14) << "\n";
if (distributed)
id.ICNTL(18) = 3; // strategy for distributed input matrix
// id.ICNTL(22) = 1; /* enables out-of-core support */
id.job = 6;
mumps_interf<T>::mumps_c(id);
bool ok = mumps_error_check(id);
id.job = JOB_END;
mumps_interf<T>::mumps_c(id);
#ifdef GMM_USES_MPI
MPI_Bcast(&(rhs[0]),id.n,gmm::mpi_type(T()),0,MPI_COMM_WORLD);
#endif
gmm::copy(rhs, X);
return ok;
}
/** MUMPS solve interface for distributed matrices
* Works only with sparse or skyline matrices
*/
template <typename MAT, typename VECTX, typename VECTB>
bool MUMPS_distributed_matrix_solve(const MAT &A, const VECTX &X_,
const VECTB &B, bool sym = false) {
return MUMPS_solve(A, X_, B, sym, true);
}
template<typename T>
inline T real_or_complex(std::complex<T> a) { return a.real(); }
template<typename T>
inline T real_or_complex(T &a) { return a; }
/** Evaluate matrix determinant with MUMPS
* Works only with sparse or skyline matrices
*/
template <typename MAT, typename T = typename linalg_traits<MAT>::value_type>
T MUMPS_determinant(const MAT &A, int &exponent,
bool sym = false, bool distributed = false) {
exponent = 0;
typedef typename mumps_interf<T>::value_type MUMPS_T;
typedef typename number_traits<T>::magnitude_type R;
GMM_ASSERT2(gmm::mat_nrows(A) == gmm::mat_ncols(A), "Non-square matrix");
ij_sparse_matrix<T> AA(A, sym);
const int JOB_INIT = -1;
const int JOB_END = -2;
const int USE_COMM_WORLD = -987654;
typename mumps_interf<T>::MUMPS_STRUC_C id;
int rank(0);
#ifdef GMM_USES_MPI
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
#endif
id.job = JOB_INIT;
id.par = 1;
id.sym = sym ? 2 : 0;
id.comm_fortran = USE_COMM_WORLD;
mumps_interf<T>::mumps_c(id);
if (rank == 0 || distributed) {
id.n = int(gmm::mat_nrows(A));
if (distributed) {
id.nz_loc = int(AA.irn.size());
id.irn_loc = &(AA.irn[0]);
id.jcn_loc = &(AA.jcn[0]);
id.a_loc = (MUMPS_T*)(&(AA.a[0]));
} else {
id.nz = int(AA.irn.size());
id.irn = &(AA.irn[0]);
id.jcn = &(AA.jcn[0]);
id.a = (MUMPS_T*)(&(AA.a[0]));
}
}
id.ICNTL(1) = -1; // output stream for error messages
id.ICNTL(2) = -1; // output stream for other messages
id.ICNTL(3) = -1; // output stream for global information
id.ICNTL(4) = 0; // verbosity level
if (distributed)
id.ICNTL(5) = 0; // assembled input matrix (default)
// id.ICNTL(14) += 80; // small boost to the workspace size
if (distributed)
id.ICNTL(18) = 3; // strategy for distributed input matrix
id.ICNTL(31) = 1; // only factorization, no solution to follow
id.ICNTL(33) = 1; // request determinant calculation
id.job = 4; // abalysis (job=1) + factorization (job=2)
mumps_interf<T>::mumps_c(id);
mumps_error_check(id);
T det = real_or_complex(std::complex<R>(id.RINFOG(12),id.RINFOG(13)));
exponent = id.INFOG(34);
id.job = JOB_END;
mumps_interf<T>::mumps_c(id);
return det;
}
#undef ICNTL
#undef INFO
#undef INFOG
#undef RINFOG
}
#endif // GMM_MUMPS_INTERFACE_H
#endif // GMM_USES_MUMPS

228
gmm/gmm_algobase.h Normal file
View File

@ -0,0 +1,228 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2000-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/** @file gmm_algobase.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date September 28, 2000.
@brief Miscelleanous algorithms on containers.
*/
#ifndef GMM_ALGOBASE_H__
#define GMM_ALGOBASE_H__
#include "gmm_std.h"
#include "gmm_except.h"
#include <functional>
namespace gmm {
/* ********************************************************************* */
/* Definitition de classes de comparaison. */
/* retournant un int. */
/* ********************************************************************* */
template <class T>
struct less : public std::binary_function<T, T, int> {
inline int operator()(const T& x, const T& y) const
{ return (x < y) ? -1 : ((y < x) ? 1 : 0); }
};
template<> struct less<int> : public std::binary_function<int, int, int>
{ int operator()(int x, int y) const { return x-y; } };
template<> struct less<char> : public std::binary_function<char, char, int>
{ int operator()(char x, char y) const { return int(x-y); } };
template<> struct less<short> : public std::binary_function<short,short,int>
{ int operator()(short x, short y) const { return int(x-y); } };
template<> struct less<unsigned char>
: public std::binary_function<unsigned char, unsigned char, int> {
int operator()(unsigned char x, unsigned char y) const
{ return int(x)-int(y); }
};
template <class T>
struct greater : public std::binary_function<T, T, int> {
inline int operator()(const T& x, const T& y) const
{ return (y < x) ? -1 : ((x < y) ? 1 : 0); }
};
template<> struct greater<int> : public std::binary_function<int, int, int>
{ int operator()(int x, int y) const { return y-x; } };
template<> struct greater<char> : public std::binary_function<char,char,int>
{ int operator()(char x, char y) const { return int(y-x); } };
template<> struct greater<short>
: public std::binary_function<short, short, int>
{ int operator()(short x, short y) const { return int(y-x); } };
template<> struct greater<unsigned char>
: public std::binary_function<unsigned char, unsigned char, int> {
int operator()(unsigned char x, unsigned char y) const
{ return int(y)-int(x); }
};
template <typename T> inline T my_abs(T a) { return (a < T(0)) ? T(-a) : a; }
template <class T>
struct approx_less : public std::binary_function<T, T, int> {
double eps;
inline int operator()(const T &x, const T &y) const
{ if (my_abs(x - y) <= eps) return 0; if (x < y) return -1; return 1; }
approx_less(double e = 1E-13) { eps = e; }
};
template <class T>
struct approx_greater : public std::binary_function<T, T, int> {
double eps;
inline int operator()(const T &x, const T &y) const
{ if (my_abs(x - y) <= eps) return 0; if (x > y) return -1; return 1; }
approx_greater(double e = 1E-13) { eps = e; }
};
template<class ITER1, class ITER2, class COMP>
int lexicographical_compare(ITER1 b1, const ITER1 &e1,
ITER2 b2, const ITER2 &e2, const COMP &c) {
int i;
for ( ; b1 != e1 && b2 != e2; ++b1, ++b2)
if ((i = c(*b1, *b2)) != 0) return i;
if (b1 != e1) return 1;
if (b2 != e2) return -1;
return 0;
}
template<class CONT, class COMP = gmm::less<typename CONT::value_type> >
struct lexicographical_less : public std::binary_function<CONT, CONT, int>
{
COMP c;
int operator()(const CONT &x, const CONT &y) const {
return gmm::lexicographical_compare(x.begin(), x.end(),
y.begin(), y.end(), c);
}
lexicographical_less(const COMP &d = COMP()) { c = d; }
};
template<class CONT, class COMP = gmm::less<typename CONT::value_type> >
struct lexicographical_greater
: public std::binary_function<CONT, CONT, int> {
COMP c;
int operator()(const CONT &x, const CONT &y) const {
return -gmm::lexicographical_compare(x.begin(), x.end(),
y.begin(), y.end(), c);
}
lexicographical_greater(const COMP &d = COMP()) { c = d; }
};
/* ********************************************************************* */
/* "Virtual" iterators on sequences. */
/* The class T represent a class of sequence. */
/* ********************************************************************* */
template<class T> struct sequence_iterator {
typedef T value_type;
typedef value_type* pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef std::forward_iterator_tag iterator_category;
T Un;
sequence_iterator(T U0 = T(0)) { Un = U0; }
sequence_iterator &operator ++()
{ ++Un; return *this; }
sequence_iterator operator ++(int)
{ sequence_iterator tmp = *this; (*this)++; return tmp; }
const_reference operator *() const { return Un; }
reference operator *() { return Un; }
bool operator ==(const sequence_iterator &i) const { return (i.Un==Un);}
bool operator !=(const sequence_iterator &i) const { return (i.Un!=Un);}
};
/* ********************************************************************* */
/* generic algorithms. */
/* ********************************************************************* */
template <class ITER1, class SIZE, class ITER2>
ITER2 copy_n(ITER1 first, SIZE count, ITER2 result) {
for ( ; count > 0; --count, ++first, ++result) *result = *first;
return result;
}
template<class ITER>
typename std::iterator_traits<ITER>::value_type
mean_value(ITER first, const ITER &last) {
GMM_ASSERT2(first != last, "mean value of empty container");
size_t n = 1;
typename std::iterator_traits<ITER>::value_type res = *first++;
while (first != last) { res += *first; ++first; ++n; }
res /= float(n);
return res;
}
template<class CONT>
typename CONT::value_type
mean_value(const CONT &c) { return mean_value(c.begin(), c.end()); }
template<class ITER> /* hum ... */
void minmax_box(typename std::iterator_traits<ITER>::value_type &pmin,
typename std::iterator_traits<ITER>::value_type &pmax,
ITER first, const ITER &last) {
typedef typename std::iterator_traits<ITER>::value_type PT;
if (first != last) { pmin = pmax = *first; ++first; }
while (first != last) {
typename PT::const_iterator b = (*first).begin(), e = (*first).end();
typename PT::iterator b1 = pmin.begin(), b2 = pmax.begin();
while (b != e)
{ *b1 = std::min(*b1, *b); *b2 = std::max(*b2, *b); ++b; ++b1; ++b2; }
}
}
template<typename VEC> struct sorted_indexes_aux {
const VEC &v;
public:
sorted_indexes_aux(const VEC& v_) : v(v_) {}
template <typename IDX>
bool operator()(const IDX &ia, const IDX &ib) const
{ return v[ia] < v[ib]; }
};
template<typename VEC, typename IVEC>
void sorted_indexes(const VEC &v, IVEC &iv) {
iv.clear(); iv.resize(v.size());
for (size_t i=0; i < v.size(); ++i) iv[i] = i;
std::sort(iv.begin(), iv.end(), sorted_indexes_aux<VEC>(v));
}
}
#endif /* GMM_ALGOBASE_H__ */

2221
gmm/gmm_blas.h Normal file

File diff suppressed because it is too large Load Diff

948
gmm/gmm_blas_interface.h Normal file
View File

@ -0,0 +1,948 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2003-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_blas_interface.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date October 7, 2003.
@brief gmm interface for fortran BLAS.
*/
#if defined(GETFEM_USES_BLAS) || defined(GMM_USES_BLAS) \
|| defined(GMM_USES_LAPACK) || defined(GMM_USES_ATLAS)
#ifndef GMM_BLAS_INTERFACE_H
#define GMM_BLAS_INTERFACE_H
#include "gmm_blas.h"
#include "gmm_interface.h"
#include "gmm_matrix.h"
namespace gmm {
// Use ./configure --enable-blas-interface to activate this interface.
#define GMMLAPACK_TRACE(f)
// #define GMMLAPACK_TRACE(f) cout << "function " << f << " called" << endl;
/* ********************************************************************* */
/* Operations interfaced for T = float, double, std::complex<float> */
/* or std::complex<double> : */
/* */
/* vect_norm2(std::vector<T>) */
/* */
/* vect_sp(std::vector<T>, std::vector<T>) */
/* vect_sp(scaled(std::vector<T>), std::vector<T>) */
/* vect_sp(std::vector<T>, scaled(std::vector<T>)) */
/* vect_sp(scaled(std::vector<T>), scaled(std::vector<T>)) */
/* */
/* vect_hp(std::vector<T>, std::vector<T>) */
/* vect_hp(scaled(std::vector<T>), std::vector<T>) */
/* vect_hp(std::vector<T>, scaled(std::vector<T>)) */
/* vect_hp(scaled(std::vector<T>), scaled(std::vector<T>)) */
/* */
/* add(std::vector<T>, std::vector<T>) */
/* add(scaled(std::vector<T>, a), std::vector<T>) */
/* */
/* mult(dense_matrix<T>, dense_matrix<T>, dense_matrix<T>) */
/* mult(transposed(dense_matrix<T>), dense_matrix<T>, dense_matrix<T>) */
/* mult(dense_matrix<T>, transposed(dense_matrix<T>), dense_matrix<T>) */
/* mult(transposed(dense_matrix<T>), transposed(dense_matrix<T>), */
/* dense_matrix<T>) */
/* mult(conjugated(dense_matrix<T>), dense_matrix<T>, dense_matrix<T>) */
/* mult(dense_matrix<T>, conjugated(dense_matrix<T>), dense_matrix<T>) */
/* mult(conjugated(dense_matrix<T>), conjugated(dense_matrix<T>), */
/* dense_matrix<T>) */
/* */
/* mult(dense_matrix<T>, std::vector<T>, std::vector<T>) */
/* mult(transposed(dense_matrix<T>), std::vector<T>, std::vector<T>) */
/* mult(conjugated(dense_matrix<T>), std::vector<T>, std::vector<T>) */
/* mult(dense_matrix<T>, scaled(std::vector<T>), std::vector<T>) */
/* mult(transposed(dense_matrix<T>), scaled(std::vector<T>), */
/* std::vector<T>) */
/* mult(conjugated(dense_matrix<T>), scaled(std::vector<T>), */
/* std::vector<T>) */
/* */
/* mult_add(dense_matrix<T>, std::vector<T>, std::vector<T>) */
/* mult_add(transposed(dense_matrix<T>), std::vector<T>, std::vector<T>) */
/* mult_add(conjugated(dense_matrix<T>), std::vector<T>, std::vector<T>) */
/* mult_add(dense_matrix<T>, scaled(std::vector<T>), std::vector<T>) */
/* mult_add(transposed(dense_matrix<T>), scaled(std::vector<T>), */
/* std::vector<T>) */
/* mult_add(conjugated(dense_matrix<T>), scaled(std::vector<T>), */
/* std::vector<T>) */
/* */
/* mult(dense_matrix<T>, std::vector<T>, std::vector<T>, std::vector<T>) */
/* mult(transposed(dense_matrix<T>), std::vector<T>, std::vector<T>, */
/* std::vector<T>) */
/* mult(conjugated(dense_matrix<T>), std::vector<T>, std::vector<T>, */
/* std::vector<T>) */
/* mult(dense_matrix<T>, scaled(std::vector<T>), std::vector<T>, */
/* std::vector<T>) */
/* mult(transposed(dense_matrix<T>), scaled(std::vector<T>), */
/* std::vector<T>, std::vector<T>) */
/* mult(conjugated(dense_matrix<T>), scaled(std::vector<T>), */
/* std::vector<T>, std::vector<T>) */
/* mult(dense_matrix<T>, std::vector<T>, scaled(std::vector<T>), */
/* std::vector<T>) */
/* mult(transposed(dense_matrix<T>), std::vector<T>, */
/* scaled(std::vector<T>), std::vector<T>) */
/* mult(conjugated(dense_matrix<T>), std::vector<T>, */
/* scaled(std::vector<T>), std::vector<T>) */
/* mult(dense_matrix<T>, scaled(std::vector<T>), scaled(std::vector<T>), */
/* std::vector<T>) */
/* mult(transposed(dense_matrix<T>), scaled(std::vector<T>), */
/* scaled(std::vector<T>), std::vector<T>) */
/* mult(conjugated(dense_matrix<T>), scaled(std::vector<T>), */
/* scaled(std::vector<T>), std::vector<T>) */
/* */
/* lower_tri_solve(dense_matrix<T>, std::vector<T>, k, b) */
/* upper_tri_solve(dense_matrix<T>, std::vector<T>, k, b) */
/* lower_tri_solve(transposed(dense_matrix<T>), std::vector<T>, k, b) */
/* upper_tri_solve(transposed(dense_matrix<T>), std::vector<T>, k, b) */
/* lower_tri_solve(conjugated(dense_matrix<T>), std::vector<T>, k, b) */
/* upper_tri_solve(conjugated(dense_matrix<T>), std::vector<T>, k, b) */
/* */
/* rank_one_update(dense_matrix<T>, std::vector<T>, std::vector<T>) */
/* rank_one_update(dense_matrix<T>, scaled(std::vector<T>), */
/* std::vector<T>) */
/* rank_one_update(dense_matrix<T>, std::vector<T>, */
/* scaled(std::vector<T>)) */
/* */
/* ********************************************************************* */
/* ********************************************************************* */
/* Basic defines. */
/* ********************************************************************* */
# define BLAS_S float
# define BLAS_D double
# define BLAS_C std::complex<float>
# define BLAS_Z std::complex<double>
/* ********************************************************************* */
/* BLAS functions used. */
/* ********************************************************************* */
extern "C" {
void daxpy_(const int *n, const double *alpha, const double *x,
const int *incx, double *y, const int *incy);
void dgemm_(const char *tA, const char *tB, const int *m,
const int *n, const int *k, const double *alpha,
const double *A, const int *ldA, const double *B,
const int *ldB, const double *beta, double *C,
const int *ldC);
void sgemm_(...); void cgemm_(...); void zgemm_(...);
void sgemv_(...); void dgemv_(...); void cgemv_(...); void zgemv_(...);
void strsv_(...); void dtrsv_(...); void ctrsv_(...); void ztrsv_(...);
void saxpy_(...); /*void daxpy_(...); */void caxpy_(...); void zaxpy_(...);
BLAS_S sdot_ (...); BLAS_D ddot_ (...);
BLAS_C cdotu_(...); BLAS_Z zdotu_(...);
BLAS_C cdotc_(...); BLAS_Z zdotc_(...);
BLAS_S snrm2_(...); BLAS_D dnrm2_(...);
BLAS_S scnrm2_(...); BLAS_D dznrm2_(...);
void sger_(...); void dger_(...); void cgerc_(...); void zgerc_(...);
}
#if 1
/* ********************************************************************* */
/* vect_norm2(x). */
/* ********************************************************************* */
# define nrm2_interface(param1, trans1, blas_name, base_type) \
inline number_traits<base_type >::magnitude_type \
vect_norm2(param1(base_type)) { \
GMMLAPACK_TRACE("nrm2_interface"); \
int inc(1), n(int(vect_size(x))); trans1(base_type); \
return blas_name(&n, &x[0], &inc); \
}
# define nrm2_p1(base_type) const std::vector<base_type > &x
# define nrm2_trans1(base_type)
nrm2_interface(nrm2_p1, nrm2_trans1, snrm2_ , BLAS_S)
nrm2_interface(nrm2_p1, nrm2_trans1, dnrm2_ , BLAS_D)
nrm2_interface(nrm2_p1, nrm2_trans1, scnrm2_, BLAS_C)
nrm2_interface(nrm2_p1, nrm2_trans1, dznrm2_, BLAS_Z)
/* ********************************************************************* */
/* vect_sp(x, y). */
/* ********************************************************************* */
# define dot_interface(param1, trans1, mult1, param2, trans2, mult2, \
blas_name, base_type) \
inline base_type vect_sp(param1(base_type), param2(base_type)) { \
GMMLAPACK_TRACE("dot_interface"); \
trans1(base_type); trans2(base_type); int inc(1), n(int(vect_size(y)));\
return mult1 mult2 blas_name(&n, &x[0], &inc, &y[0], &inc); \
}
# define dot_p1(base_type) const std::vector<base_type > &x
# define dot_trans1(base_type)
# define dot_p1_s(base_type) \
const scaled_vector_const_ref<std::vector<base_type >, base_type > &x_
# define dot_trans1_s(base_type) \
std::vector<base_type > &x = \
const_cast<std::vector<base_type > &>(*(linalg_origin(x_))); \
base_type a(x_.r)
# define dot_p2(base_type) const std::vector<base_type > &y
# define dot_trans2(base_type)
# define dot_p2_s(base_type) \
const scaled_vector_const_ref<std::vector<base_type >, base_type > &y_
# define dot_trans2_s(base_type) \
std::vector<base_type > &y = \
const_cast<std::vector<base_type > &>(*(linalg_origin(y_))); \
base_type b(y_.r)
dot_interface(dot_p1, dot_trans1, (BLAS_S), dot_p2, dot_trans2, (BLAS_S),
sdot_ , BLAS_S)
dot_interface(dot_p1, dot_trans1, (BLAS_D), dot_p2, dot_trans2, (BLAS_D),
ddot_ , BLAS_D)
dot_interface(dot_p1, dot_trans1, (BLAS_C), dot_p2, dot_trans2, (BLAS_C),
cdotu_, BLAS_C)
dot_interface(dot_p1, dot_trans1, (BLAS_Z), dot_p2, dot_trans2, (BLAS_Z),
zdotu_, BLAS_Z)
dot_interface(dot_p1_s, dot_trans1_s, a*, dot_p2, dot_trans2, (BLAS_S),
sdot_ ,BLAS_S)
dot_interface(dot_p1_s, dot_trans1_s, a*, dot_p2, dot_trans2, (BLAS_D),
ddot_ ,BLAS_D)
dot_interface(dot_p1_s, dot_trans1_s, a*, dot_p2, dot_trans2, (BLAS_C),
cdotu_,BLAS_C)
dot_interface(dot_p1_s, dot_trans1_s, a*, dot_p2, dot_trans2, (BLAS_Z),
zdotu_,BLAS_Z)
dot_interface(dot_p1, dot_trans1, (BLAS_S), dot_p2_s, dot_trans2_s, b*,
sdot_ ,BLAS_S)
dot_interface(dot_p1, dot_trans1, (BLAS_D), dot_p2_s, dot_trans2_s, b*,
ddot_ ,BLAS_D)
dot_interface(dot_p1, dot_trans1, (BLAS_C), dot_p2_s, dot_trans2_s, b*,
cdotu_,BLAS_C)
dot_interface(dot_p1, dot_trans1, (BLAS_Z), dot_p2_s, dot_trans2_s, b*,
zdotu_,BLAS_Z)
dot_interface(dot_p1_s,dot_trans1_s,a*,dot_p2_s,dot_trans2_s,b*,sdot_ ,
BLAS_S)
dot_interface(dot_p1_s,dot_trans1_s,a*,dot_p2_s,dot_trans2_s,b*,ddot_ ,
BLAS_D)
dot_interface(dot_p1_s,dot_trans1_s,a*,dot_p2_s,dot_trans2_s,b*,cdotu_,
BLAS_C)
dot_interface(dot_p1_s,dot_trans1_s,a*,dot_p2_s,dot_trans2_s,b*,zdotu_,
BLAS_Z)
/* ********************************************************************* */
/* vect_hp(x, y). */
/* ********************************************************************* */
# define dotc_interface(param1, trans1, mult1, param2, trans2, mult2, \
blas_name, base_type) \
inline base_type vect_hp(param1(base_type), param2(base_type)) { \
GMMLAPACK_TRACE("dotc_interface"); \
trans1(base_type); trans2(base_type); int inc(1), n(int(vect_size(y)));\
return mult1 mult2 blas_name(&n, &x[0], &inc, &y[0], &inc); \
}
# define dotc_p1(base_type) const std::vector<base_type > &x
# define dotc_trans1(base_type)
# define dotc_p1_s(base_type) \
const scaled_vector_const_ref<std::vector<base_type >, base_type > &x_
# define dotc_trans1_s(base_type) \
std::vector<base_type > &x = \
const_cast<std::vector<base_type > &>(*(linalg_origin(x_))); \
base_type a(x_.r)
# define dotc_p2(base_type) const std::vector<base_type > &y
# define dotc_trans2(base_type)
# define dotc_p2_s(base_type) \
const scaled_vector_const_ref<std::vector<base_type >, base_type > &y_
# define dotc_trans2_s(base_type) \
std::vector<base_type > &y = \
const_cast<std::vector<base_type > &>(*(linalg_origin(y_))); \
base_type b(gmm::conj(y_.r))
dotc_interface(dotc_p1, dotc_trans1, (BLAS_S), dotc_p2, dotc_trans2,
(BLAS_S),sdot_ ,BLAS_S)
dotc_interface(dotc_p1, dotc_trans1, (BLAS_D), dotc_p2, dotc_trans2,
(BLAS_D),ddot_ ,BLAS_D)
dotc_interface(dotc_p1, dotc_trans1, (BLAS_C), dotc_p2, dotc_trans2,
(BLAS_C),cdotc_,BLAS_C)
dotc_interface(dotc_p1, dotc_trans1, (BLAS_Z), dotc_p2, dotc_trans2,
(BLAS_Z),zdotc_,BLAS_Z)
dotc_interface(dotc_p1_s, dotc_trans1_s, a*, dotc_p2, dotc_trans2,
(BLAS_S),sdot_, BLAS_S)
dotc_interface(dotc_p1_s, dotc_trans1_s, a*, dotc_p2, dotc_trans2,
(BLAS_D),ddot_ , BLAS_D)
dotc_interface(dotc_p1_s, dotc_trans1_s, a*, dotc_p2, dotc_trans2,
(BLAS_C),cdotc_, BLAS_C)
dotc_interface(dotc_p1_s, dotc_trans1_s, a*, dotc_p2, dotc_trans2,
(BLAS_Z),zdotc_, BLAS_Z)
dotc_interface(dotc_p1, dotc_trans1, (BLAS_S), dotc_p2_s, dotc_trans2_s,
b*,sdot_ , BLAS_S)
dotc_interface(dotc_p1, dotc_trans1, (BLAS_D), dotc_p2_s, dotc_trans2_s,
b*,ddot_ , BLAS_D)
dotc_interface(dotc_p1, dotc_trans1, (BLAS_C), dotc_p2_s, dotc_trans2_s,
b*,cdotc_, BLAS_C)
dotc_interface(dotc_p1, dotc_trans1, (BLAS_Z), dotc_p2_s, dotc_trans2_s,
b*,zdotc_, BLAS_Z)
dotc_interface(dotc_p1_s,dotc_trans1_s,a*,dotc_p2_s,dotc_trans2_s,b*,sdot_ ,
BLAS_S)
dotc_interface(dotc_p1_s,dotc_trans1_s,a*,dotc_p2_s,dotc_trans2_s,b*,ddot_ ,
BLAS_D)
dotc_interface(dotc_p1_s,dotc_trans1_s,a*,dotc_p2_s,dotc_trans2_s,b*,cdotc_,
BLAS_C)
dotc_interface(dotc_p1_s,dotc_trans1_s,a*,dotc_p2_s,dotc_trans2_s,b*,zdotc_,
BLAS_Z)
/* ********************************************************************* */
/* add(x, y). */
/* ********************************************************************* */
# define axpy_interface(param1, trans1, blas_name, base_type) \
inline void add(param1(base_type), std::vector<base_type > &y) { \
GMMLAPACK_TRACE("axpy_interface"); \
int inc(1), n(int(vect_size(y))); trans1(base_type); \
if (n == 0) return; \
blas_name(&n, &a, &x[0], &inc, &y[0], &inc); \
}
# define axpy_p1(base_type) const std::vector<base_type > &x
# define axpy_trans1(base_type) base_type a(1)
# define axpy_p1_s(base_type) \
const scaled_vector_const_ref<std::vector<base_type >, base_type > &x_
# define axpy_trans1_s(base_type) \
std::vector<base_type > &x = \
const_cast<std::vector<base_type > &>(*(linalg_origin(x_))); \
base_type a(x_.r)
axpy_interface(axpy_p1, axpy_trans1, saxpy_, BLAS_S)
axpy_interface(axpy_p1, axpy_trans1, daxpy_, BLAS_D)
axpy_interface(axpy_p1, axpy_trans1, caxpy_, BLAS_C)
axpy_interface(axpy_p1, axpy_trans1, zaxpy_, BLAS_Z)
axpy_interface(axpy_p1_s, axpy_trans1_s, saxpy_, BLAS_S)
axpy_interface(axpy_p1_s, axpy_trans1_s, daxpy_, BLAS_D)
axpy_interface(axpy_p1_s, axpy_trans1_s, caxpy_, BLAS_C)
axpy_interface(axpy_p1_s, axpy_trans1_s, zaxpy_, BLAS_Z)
/* ********************************************************************* */
/* mult_add(A, x, z). */
/* ********************************************************************* */
# define gemv_interface(param1, trans1, param2, trans2, blas_name, \
base_type, orien) \
inline void mult_add_spec(param1(base_type), param2(base_type), \
std::vector<base_type > &z, orien) { \
GMMLAPACK_TRACE("gemv_interface"); \
trans1(base_type); trans2(base_type); base_type beta(1); \
int m(int(mat_nrows(A))), lda(m), n(int(mat_ncols(A))), inc(1); \
if (m && n) blas_name(&t, &m, &n, &alpha, &A(0,0), &lda, &x[0], &inc, \
&beta, &z[0], &inc); \
else gmm::clear(z); \
}
// First parameter
# define gem_p1_n(base_type) const dense_matrix<base_type > &A
# define gem_trans1_n(base_type) const char t = 'N'
# define gem_p1_t(base_type) \
const transposed_col_ref<dense_matrix<base_type > *> &A_
# define gem_trans1_t(base_type) dense_matrix<base_type > &A = \
const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_))); \
const char t = 'T'
# define gem_p1_tc(base_type) \
const transposed_col_ref<const dense_matrix<base_type > *> &A_
# define gem_p1_c(base_type) \
const conjugated_col_matrix_const_ref<dense_matrix<base_type > > &A_
# define gem_trans1_c(base_type) dense_matrix<base_type > &A = \
const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_))); \
const char t = 'C'
// second parameter
# define gemv_p2_n(base_type) const std::vector<base_type > &x
# define gemv_trans2_n(base_type) base_type alpha(1)
# define gemv_p2_s(base_type) \
const scaled_vector_const_ref<std::vector<base_type >, base_type > &x_
# define gemv_trans2_s(base_type) std::vector<base_type > &x = \
const_cast<std::vector<base_type > &>(*(linalg_origin(x_))); \
base_type alpha(x_.r)
// Z <- AX + Z.
gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, sgemv_,
BLAS_S, col_major)
gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, dgemv_,
BLAS_D, col_major)
gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, cgemv_,
BLAS_C, col_major)
gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, zgemv_,
BLAS_Z, col_major)
// Z <- transposed(A)X + Z.
gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, sgemv_,
BLAS_S, row_major)
gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, dgemv_,
BLAS_D, row_major)
gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, cgemv_,
BLAS_C, row_major)
gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, zgemv_,
BLAS_Z, row_major)
// Z <- transposed(const A)X + Z.
gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, sgemv_,
BLAS_S, row_major)
gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, dgemv_,
BLAS_D, row_major)
gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, cgemv_,
BLAS_C, row_major)
gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, zgemv_,
BLAS_Z, row_major)
// Z <- conjugated(A)X + Z.
gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, sgemv_,
BLAS_S, row_major)
gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, dgemv_,
BLAS_D, row_major)
gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, cgemv_,
BLAS_C, row_major)
gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, zgemv_,
BLAS_Z, row_major)
// Z <- A scaled(X) + Z.
gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, sgemv_,
BLAS_S, col_major)
gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, dgemv_,
BLAS_D, col_major)
gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, cgemv_,
BLAS_C, col_major)
gemv_interface(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, zgemv_,
BLAS_Z, col_major)
// Z <- transposed(A) scaled(X) + Z.
gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, sgemv_,
BLAS_S, row_major)
gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, dgemv_,
BLAS_D, row_major)
gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, cgemv_,
BLAS_C, row_major)
gemv_interface(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, zgemv_,
BLAS_Z, row_major)
// Z <- transposed(const A) scaled(X) + Z.
gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, sgemv_,
BLAS_S, row_major)
gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, dgemv_,
BLAS_D, row_major)
gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, cgemv_,
BLAS_C, row_major)
gemv_interface(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, zgemv_,
BLAS_Z, row_major)
// Z <- conjugated(A) scaled(X) + Z.
gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, sgemv_,
BLAS_S, row_major)
gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, dgemv_,
BLAS_D, row_major)
gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, cgemv_,
BLAS_C, row_major)
gemv_interface(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, zgemv_,
BLAS_Z, row_major)
/* ********************************************************************* */
/* mult(A, x, y). */
/* ********************************************************************* */
# define gemv_interface2(param1, trans1, param2, trans2, blas_name, \
base_type, orien) \
inline void mult_spec(param1(base_type), param2(base_type), \
std::vector<base_type > &z, orien) { \
GMMLAPACK_TRACE("gemv_interface2"); \
trans1(base_type); trans2(base_type); base_type beta(0); \
int m(int(mat_nrows(A))), lda(m), n(int(mat_ncols(A))), inc(1); \
if (m && n) \
blas_name(&t, &m, &n, &alpha, &A(0,0), &lda, &x[0], &inc, &beta, \
&z[0], &inc); \
else gmm::clear(z); \
}
// Y <- AX.
gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, sgemv_,
BLAS_S, col_major)
gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, dgemv_,
BLAS_D, col_major)
gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, cgemv_,
BLAS_C, col_major)
gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_n, gemv_trans2_n, zgemv_,
BLAS_Z, col_major)
// Y <- transposed(A)X.
gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, sgemv_,
BLAS_S, row_major)
gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, dgemv_,
BLAS_D, row_major)
gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, cgemv_,
BLAS_C, row_major)
gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_n, gemv_trans2_n, zgemv_,
BLAS_Z, row_major)
// Y <- transposed(const A)X.
gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, sgemv_,
BLAS_S, row_major)
gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, dgemv_,
BLAS_D, row_major)
gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, cgemv_,
BLAS_C, row_major)
gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_n, gemv_trans2_n, zgemv_,
BLAS_Z, row_major)
// Y <- conjugated(A)X.
gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, sgemv_,
BLAS_S, row_major)
gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, dgemv_,
BLAS_D, row_major)
gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, cgemv_,
BLAS_C, row_major)
gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_n, gemv_trans2_n, zgemv_,
BLAS_Z, row_major)
// Y <- A scaled(X).
gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, sgemv_,
BLAS_S, col_major)
gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, dgemv_,
BLAS_D, col_major)
gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, cgemv_,
BLAS_C, col_major)
gemv_interface2(gem_p1_n, gem_trans1_n, gemv_p2_s, gemv_trans2_s, zgemv_,
BLAS_Z, col_major)
// Y <- transposed(A) scaled(X).
gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, sgemv_,
BLAS_S, row_major)
gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, dgemv_,
BLAS_D, row_major)
gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, cgemv_,
BLAS_C, row_major)
gemv_interface2(gem_p1_t, gem_trans1_t, gemv_p2_s, gemv_trans2_s, zgemv_,
BLAS_Z, row_major)
// Y <- transposed(const A) scaled(X).
gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, sgemv_,
BLAS_S, row_major)
gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, dgemv_,
BLAS_D, row_major)
gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, cgemv_,
BLAS_C, row_major)
gemv_interface2(gem_p1_tc, gem_trans1_t, gemv_p2_s, gemv_trans2_s, zgemv_,
BLAS_Z, row_major)
// Y <- conjugated(A) scaled(X).
gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, sgemv_,
BLAS_S, row_major)
gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, dgemv_,
BLAS_D, row_major)
gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, cgemv_,
BLAS_C, row_major)
gemv_interface2(gem_p1_c, gem_trans1_c, gemv_p2_s, gemv_trans2_s, zgemv_,
BLAS_Z, row_major)
/* ********************************************************************* */
/* Rank one update. */
/* ********************************************************************* */
# define ger_interface(blas_name, base_type) \
inline void rank_one_update(const dense_matrix<base_type > &A, \
const std::vector<base_type > &V, \
const std::vector<base_type > &W) { \
GMMLAPACK_TRACE("ger_interface"); \
int m(int(mat_nrows(A))), lda = m, n(int(mat_ncols(A))); \
int incx = 1, incy = 1; \
base_type alpha(1); \
if (m && n) \
blas_name(&m, &n, &alpha, &V[0], &incx, &W[0], &incy, &A(0,0), &lda);\
}
ger_interface(sger_, BLAS_S)
ger_interface(dger_, BLAS_D)
ger_interface(cgerc_, BLAS_C)
ger_interface(zgerc_, BLAS_Z)
# define ger_interface_sn(blas_name, base_type) \
inline void rank_one_update(const dense_matrix<base_type > &A, \
gemv_p2_s(base_type), \
const std::vector<base_type > &W) { \
GMMLAPACK_TRACE("ger_interface"); \
gemv_trans2_s(base_type); \
int m(int(mat_nrows(A))), lda = m, n(int(mat_ncols(A))); \
int incx = 1, incy = 1; \
if (m && n) \
blas_name(&m, &n, &alpha, &x[0], &incx, &W[0], &incy, &A(0,0), &lda);\
}
ger_interface_sn(sger_, BLAS_S)
ger_interface_sn(dger_, BLAS_D)
ger_interface_sn(cgerc_, BLAS_C)
ger_interface_sn(zgerc_, BLAS_Z)
# define ger_interface_ns(blas_name, base_type) \
inline void rank_one_update(const dense_matrix<base_type > &A, \
const std::vector<base_type > &V, \
gemv_p2_s(base_type)) { \
GMMLAPACK_TRACE("ger_interface"); \
gemv_trans2_s(base_type); \
int m(int(mat_nrows(A))), lda = m, n(int(mat_ncols(A))); \
int incx = 1, incy = 1; \
base_type al2 = gmm::conj(alpha); \
if (m && n) \
blas_name(&m, &n, &al2, &V[0], &incx, &x[0], &incy, &A(0,0), &lda); \
}
ger_interface_ns(sger_, BLAS_S)
ger_interface_ns(dger_, BLAS_D)
ger_interface_ns(cgerc_, BLAS_C)
ger_interface_ns(zgerc_, BLAS_Z)
/* ********************************************************************* */
/* dense matrix x dense matrix multiplication. */
/* ********************************************************************* */
# define gemm_interface_nn(blas_name, base_type) \
inline void mult_spec(const dense_matrix<base_type > &A, \
const dense_matrix<base_type > &B, \
dense_matrix<base_type > &C, c_mult) { \
GMMLAPACK_TRACE("gemm_interface_nn"); \
const char t = 'N'; \
int m(int(mat_nrows(A))), lda = m, k(int(mat_ncols(A))); \
int n(int(mat_ncols(B))); \
int ldb = k, ldc = m; \
base_type alpha(1), beta(0); \
if (m && k && n) \
blas_name(&t, &t, &m, &n, &k, &alpha, \
&A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc); \
else gmm::clear(C); \
}
gemm_interface_nn(sgemm_, BLAS_S)
gemm_interface_nn(dgemm_, BLAS_D)
gemm_interface_nn(cgemm_, BLAS_C)
gemm_interface_nn(zgemm_, BLAS_Z)
/* ********************************************************************* */
/* transposed(dense matrix) x dense matrix multiplication. */
/* ********************************************************************* */
# define gemm_interface_tn(blas_name, base_type, is_const) \
inline void mult_spec( \
const transposed_col_ref<is_const<base_type > *> &A_,\
const dense_matrix<base_type > &B, \
dense_matrix<base_type > &C, rcmult) { \
GMMLAPACK_TRACE("gemm_interface_tn"); \
dense_matrix<base_type > &A \
= const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_))); \
const char t = 'T', u = 'N'; \
int m(int(mat_ncols(A))), k(int(mat_nrows(A))), n(int(mat_ncols(B))); \
int lda = k, ldb = k, ldc = m; \
base_type alpha(1), beta(0); \
if (m && k && n) \
blas_name(&t, &u, &m, &n, &k, &alpha, \
&A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc); \
else gmm::clear(C); \
}
gemm_interface_tn(sgemm_, BLAS_S, dense_matrix)
gemm_interface_tn(dgemm_, BLAS_D, dense_matrix)
gemm_interface_tn(cgemm_, BLAS_C, dense_matrix)
gemm_interface_tn(zgemm_, BLAS_Z, dense_matrix)
gemm_interface_tn(sgemm_, BLAS_S, const dense_matrix)
gemm_interface_tn(dgemm_, BLAS_D, const dense_matrix)
gemm_interface_tn(cgemm_, BLAS_C, const dense_matrix)
gemm_interface_tn(zgemm_, BLAS_Z, const dense_matrix)
/* ********************************************************************* */
/* dense matrix x transposed(dense matrix) multiplication. */
/* ********************************************************************* */
# define gemm_interface_nt(blas_name, base_type, is_const) \
inline void mult_spec(const dense_matrix<base_type > &A, \
const transposed_col_ref<is_const<base_type > *> &B_, \
dense_matrix<base_type > &C, r_mult) { \
GMMLAPACK_TRACE("gemm_interface_nt"); \
dense_matrix<base_type > &B \
= const_cast<dense_matrix<base_type > &>(*(linalg_origin(B_))); \
const char t = 'N', u = 'T'; \
int m(int(mat_nrows(A))), lda = m, k(int(mat_ncols(A))); \
int n(int(mat_nrows(B))); \
int ldb = n, ldc = m; \
base_type alpha(1), beta(0); \
if (m && k && n) \
blas_name(&t, &u, &m, &n, &k, &alpha, \
&A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc); \
else gmm::clear(C); \
}
gemm_interface_nt(sgemm_, BLAS_S, dense_matrix)
gemm_interface_nt(dgemm_, BLAS_D, dense_matrix)
gemm_interface_nt(cgemm_, BLAS_C, dense_matrix)
gemm_interface_nt(zgemm_, BLAS_Z, dense_matrix)
gemm_interface_nt(sgemm_, BLAS_S, const dense_matrix)
gemm_interface_nt(dgemm_, BLAS_D, const dense_matrix)
gemm_interface_nt(cgemm_, BLAS_C, const dense_matrix)
gemm_interface_nt(zgemm_, BLAS_Z, const dense_matrix)
/* ********************************************************************* */
/* transposed(dense matrix) x transposed(dense matrix) multiplication. */
/* ********************************************************************* */
# define gemm_interface_tt(blas_name, base_type, isA_const, isB_const) \
inline void mult_spec( \
const transposed_col_ref<isA_const <base_type > *> &A_, \
const transposed_col_ref<isB_const <base_type > *> &B_, \
dense_matrix<base_type > &C, r_mult) { \
GMMLAPACK_TRACE("gemm_interface_tt"); \
dense_matrix<base_type > &A \
= const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_))); \
dense_matrix<base_type > &B \
= const_cast<dense_matrix<base_type > &>(*(linalg_origin(B_))); \
const char t = 'T', u = 'T'; \
int m(int(mat_ncols(A))), k(int(mat_nrows(A))), n(int(mat_nrows(B))); \
int lda = k, ldb = n, ldc = m; \
base_type alpha(1), beta(0); \
if (m && k && n) \
blas_name(&t, &u, &m, &n, &k, &alpha, \
&A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc); \
else gmm::clear(C); \
}
gemm_interface_tt(sgemm_, BLAS_S, dense_matrix, dense_matrix)
gemm_interface_tt(dgemm_, BLAS_D, dense_matrix, dense_matrix)
gemm_interface_tt(cgemm_, BLAS_C, dense_matrix, dense_matrix)
gemm_interface_tt(zgemm_, BLAS_Z, dense_matrix, dense_matrix)
gemm_interface_tt(sgemm_, BLAS_S, const dense_matrix, dense_matrix)
gemm_interface_tt(dgemm_, BLAS_D, const dense_matrix, dense_matrix)
gemm_interface_tt(cgemm_, BLAS_C, const dense_matrix, dense_matrix)
gemm_interface_tt(zgemm_, BLAS_Z, const dense_matrix, dense_matrix)
gemm_interface_tt(sgemm_, BLAS_S, dense_matrix, const dense_matrix)
gemm_interface_tt(dgemm_, BLAS_D, dense_matrix, const dense_matrix)
gemm_interface_tt(cgemm_, BLAS_C, dense_matrix, const dense_matrix)
gemm_interface_tt(zgemm_, BLAS_Z, dense_matrix, const dense_matrix)
gemm_interface_tt(sgemm_, BLAS_S, const dense_matrix, const dense_matrix)
gemm_interface_tt(dgemm_, BLAS_D, const dense_matrix, const dense_matrix)
gemm_interface_tt(cgemm_, BLAS_C, const dense_matrix, const dense_matrix)
gemm_interface_tt(zgemm_, BLAS_Z, const dense_matrix, const dense_matrix)
/* ********************************************************************* */
/* conjugated(dense matrix) x dense matrix multiplication. */
/* ********************************************************************* */
# define gemm_interface_cn(blas_name, base_type) \
inline void mult_spec( \
const conjugated_col_matrix_const_ref<dense_matrix<base_type > > &A_,\
const dense_matrix<base_type > &B, \
dense_matrix<base_type > &C, rcmult) { \
GMMLAPACK_TRACE("gemm_interface_cn"); \
dense_matrix<base_type > &A \
= const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_))); \
const char t = 'C', u = 'N'; \
int m(int(mat_ncols(A))), k(int(mat_nrows(A))), n(int(mat_ncols(B))); \
int lda = k, ldb = k, ldc = m; \
base_type alpha(1), beta(0); \
if (m && k && n) \
blas_name(&t, &u, &m, &n, &k, &alpha, \
&A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc); \
else gmm::clear(C); \
}
gemm_interface_cn(sgemm_, BLAS_S)
gemm_interface_cn(dgemm_, BLAS_D)
gemm_interface_cn(cgemm_, BLAS_C)
gemm_interface_cn(zgemm_, BLAS_Z)
/* ********************************************************************* */
/* dense matrix x conjugated(dense matrix) multiplication. */
/* ********************************************************************* */
# define gemm_interface_nc(blas_name, base_type) \
inline void mult_spec(const dense_matrix<base_type > &A, \
const conjugated_col_matrix_const_ref<dense_matrix<base_type > > &B_,\
dense_matrix<base_type > &C, c_mult, row_major) { \
GMMLAPACK_TRACE("gemm_interface_nc"); \
dense_matrix<base_type > &B \
= const_cast<dense_matrix<base_type > &>(*(linalg_origin(B_))); \
const char t = 'N', u = 'C'; \
int m(int(mat_nrows(A))), lda = m, k(int(mat_ncols(A))); \
int n(int(mat_nrows(B))), ldb = n, ldc = m; \
base_type alpha(1), beta(0); \
if (m && k && n) \
blas_name(&t, &u, &m, &n, &k, &alpha, \
&A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc); \
else gmm::clear(C); \
}
gemm_interface_nc(sgemm_, BLAS_S)
gemm_interface_nc(dgemm_, BLAS_D)
gemm_interface_nc(cgemm_, BLAS_C)
gemm_interface_nc(zgemm_, BLAS_Z)
/* ********************************************************************* */
/* conjugated(dense matrix) x conjugated(dense matrix) multiplication. */
/* ********************************************************************* */
# define gemm_interface_cc(blas_name, base_type) \
inline void mult_spec( \
const conjugated_col_matrix_const_ref<dense_matrix<base_type > > &A_,\
const conjugated_col_matrix_const_ref<dense_matrix<base_type > > &B_,\
dense_matrix<base_type > &C, r_mult) { \
GMMLAPACK_TRACE("gemm_interface_cc"); \
dense_matrix<base_type > &A \
= const_cast<dense_matrix<base_type > &>(*(linalg_origin(A_))); \
dense_matrix<base_type > &B \
= const_cast<dense_matrix<base_type > &>(*(linalg_origin(B_))); \
const char t = 'C', u = 'C'; \
int m(int(mat_ncols(A))), k(int(mat_nrows(A))), lda = k; \
int n(int(mat_nrows(B))), ldb = n, ldc = m; \
base_type alpha(1), beta(0); \
if (m && k && n) \
blas_name(&t, &u, &m, &n, &k, &alpha, \
&A(0,0), &lda, &B(0,0), &ldb, &beta, &C(0,0), &ldc); \
else gmm::clear(C); \
}
gemm_interface_cc(sgemm_, BLAS_S)
gemm_interface_cc(dgemm_, BLAS_D)
gemm_interface_cc(cgemm_, BLAS_C)
gemm_interface_cc(zgemm_, BLAS_Z)
/* ********************************************************************* */
/* Tri solve. */
/* ********************************************************************* */
# define trsv_interface(f_name, loru, param1, trans1, blas_name, base_type)\
inline void f_name(param1(base_type), std::vector<base_type > &x, \
size_type k, bool is_unit) { \
GMMLAPACK_TRACE("trsv_interface"); \
loru; trans1(base_type); char d = is_unit ? 'U' : 'N'; \
int lda(int(mat_nrows(A))), inc(1), n = int(k); \
if (lda) blas_name(&l, &t, &d, &n, &A(0,0), &lda, &x[0], &inc); \
}
# define trsv_upper const char l = 'U'
# define trsv_lower const char l = 'L'
// X <- LOWER(A)^{-1}X.
trsv_interface(lower_tri_solve, trsv_lower, gem_p1_n, gem_trans1_n,
strsv_, BLAS_S)
trsv_interface(lower_tri_solve, trsv_lower, gem_p1_n, gem_trans1_n,
dtrsv_, BLAS_D)
trsv_interface(lower_tri_solve, trsv_lower, gem_p1_n, gem_trans1_n,
ctrsv_, BLAS_C)
trsv_interface(lower_tri_solve, trsv_lower, gem_p1_n, gem_trans1_n,
ztrsv_, BLAS_Z)
// X <- UPPER(A)^{-1}X.
trsv_interface(upper_tri_solve, trsv_upper, gem_p1_n, gem_trans1_n,
strsv_, BLAS_S)
trsv_interface(upper_tri_solve, trsv_upper, gem_p1_n, gem_trans1_n,
dtrsv_, BLAS_D)
trsv_interface(upper_tri_solve, trsv_upper, gem_p1_n, gem_trans1_n,
ctrsv_, BLAS_C)
trsv_interface(upper_tri_solve, trsv_upper, gem_p1_n, gem_trans1_n,
ztrsv_, BLAS_Z)
// X <- LOWER(transposed(A))^{-1}X.
trsv_interface(lower_tri_solve, trsv_upper, gem_p1_t, gem_trans1_t,
strsv_, BLAS_S)
trsv_interface(lower_tri_solve, trsv_upper, gem_p1_t, gem_trans1_t,
dtrsv_, BLAS_D)
trsv_interface(lower_tri_solve, trsv_upper, gem_p1_t, gem_trans1_t,
ctrsv_, BLAS_C)
trsv_interface(lower_tri_solve, trsv_upper, gem_p1_t, gem_trans1_t,
ztrsv_, BLAS_Z)
// X <- UPPER(transposed(A))^{-1}X.
trsv_interface(upper_tri_solve, trsv_lower, gem_p1_t, gem_trans1_t,
strsv_, BLAS_S)
trsv_interface(upper_tri_solve, trsv_lower, gem_p1_t, gem_trans1_t,
dtrsv_, BLAS_D)
trsv_interface(upper_tri_solve, trsv_lower, gem_p1_t, gem_trans1_t,
ctrsv_, BLAS_C)
trsv_interface(upper_tri_solve, trsv_lower, gem_p1_t, gem_trans1_t,
ztrsv_, BLAS_Z)
// X <- LOWER(transposed(const A))^{-1}X.
trsv_interface(lower_tri_solve, trsv_upper, gem_p1_tc, gem_trans1_t,
strsv_, BLAS_S)
trsv_interface(lower_tri_solve, trsv_upper, gem_p1_tc, gem_trans1_t,
dtrsv_, BLAS_D)
trsv_interface(lower_tri_solve, trsv_upper, gem_p1_tc, gem_trans1_t,
ctrsv_, BLAS_C)
trsv_interface(lower_tri_solve, trsv_upper, gem_p1_tc, gem_trans1_t,
ztrsv_, BLAS_Z)
// X <- UPPER(transposed(const A))^{-1}X.
trsv_interface(upper_tri_solve, trsv_lower, gem_p1_tc, gem_trans1_t,
strsv_, BLAS_S)
trsv_interface(upper_tri_solve, trsv_lower, gem_p1_tc, gem_trans1_t,
dtrsv_, BLAS_D)
trsv_interface(upper_tri_solve, trsv_lower, gem_p1_tc, gem_trans1_t,
ctrsv_, BLAS_C)
trsv_interface(upper_tri_solve, trsv_lower, gem_p1_tc, gem_trans1_t,
ztrsv_, BLAS_Z)
// X <- LOWER(conjugated(A))^{-1}X.
trsv_interface(lower_tri_solve, trsv_upper, gem_p1_c, gem_trans1_c,
strsv_, BLAS_S)
trsv_interface(lower_tri_solve, trsv_upper, gem_p1_c, gem_trans1_c,
dtrsv_, BLAS_D)
trsv_interface(lower_tri_solve, trsv_upper, gem_p1_c, gem_trans1_c,
ctrsv_, BLAS_C)
trsv_interface(lower_tri_solve, trsv_upper, gem_p1_c, gem_trans1_c,
ztrsv_, BLAS_Z)
// X <- UPPER(conjugated(A))^{-1}X.
trsv_interface(upper_tri_solve, trsv_lower, gem_p1_c, gem_trans1_c,
strsv_, BLAS_S)
trsv_interface(upper_tri_solve, trsv_lower, gem_p1_c, gem_trans1_c,
dtrsv_, BLAS_D)
trsv_interface(upper_tri_solve, trsv_lower, gem_p1_c, gem_trans1_c,
ctrsv_, BLAS_C)
trsv_interface(upper_tri_solve, trsv_lower, gem_p1_c, gem_trans1_c,
ztrsv_, BLAS_Z)
#endif
}
#endif // GMM_BLAS_INTERFACE_H
#endif // GMM_USES_BLAS

147
gmm/gmm_condition_number.h Normal file
View File

@ -0,0 +1,147 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2003-2017 Yves Renard, Julien Pommier
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_condition_number.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>, Julien Pommier <Julien.Pommier@insa-toulouse.fr>
@date August 27, 2003.
@brief computation of the condition number of dense matrices.
*/
#ifndef GMM_CONDITION_NUMBER_H__
#define GMM_CONDITION_NUMBER_H__
#include "gmm_dense_qr.h"
namespace gmm {
/** computation of the condition number of dense matrices using SVD.
Uses symmetric_qr_algorithm => dense matrices only.
@param M a matrix.
@param emin smallest (in magnitude) eigenvalue
@param emax largest eigenvalue.
*/
template <typename MAT>
typename number_traits<typename
linalg_traits<MAT>::value_type>::magnitude_type
condition_number(const MAT& M,
typename number_traits<typename
linalg_traits<MAT>::value_type>::magnitude_type& emin,
typename number_traits<typename
linalg_traits<MAT>::value_type>::magnitude_type& emax) {
typedef typename linalg_traits<MAT>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
// Added because of errors in complex with zero det
if (sizeof(T) != sizeof(R) && gmm::abs(gmm::lu_det(M)) == R(0))
return gmm::default_max(R());
size_type m = mat_nrows(M), n = mat_ncols(M);
emax = emin = R(0);
std::vector<R> eig(m+n);
if (m+n == 0) return R(0);
if (is_hermitian(M)) {
eig.resize(m);
gmm::symmetric_qr_algorithm(M, eig);
}
else {
dense_matrix<T> B(m+n, m+n); // not very efficient ??
gmm::copy(conjugated(M), sub_matrix(B, sub_interval(m, n), sub_interval(0, m)));
gmm::copy(M, sub_matrix(B, sub_interval(0, m),
sub_interval(m, n)));
gmm::symmetric_qr_algorithm(B, eig);
}
emin = emax = gmm::abs(eig[0]);
for (size_type i = 1; i < eig.size(); ++i) {
R e = gmm::abs(eig[i]);
emin = std::min(emin, e);
emax = std::max(emax, e);
}
// cout << "emin = " << emin << " emax = " << emax << endl;
if (emin == R(0)) return gmm::default_max(R());
return emax / emin;
}
template <typename MAT>
typename number_traits<typename
linalg_traits<MAT>::value_type>::magnitude_type
condition_number(const MAT& M) {
typename number_traits<typename
linalg_traits<MAT>::value_type>::magnitude_type emax, emin;
return condition_number(M, emin, emax);
}
template <typename MAT>
typename number_traits<typename
linalg_traits<MAT>::value_type>::magnitude_type
Frobenius_condition_number_sqr(const MAT& M) {
typedef typename linalg_traits<MAT>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type m = mat_nrows(M), n = mat_ncols(M);
dense_matrix<T> B(std::min(m,n), std::min(m,n));
if (m < n) mult(M,gmm::conjugated(M),B);
else mult(gmm::conjugated(M),M,B);
R trB = abs(mat_trace(B));
lu_inverse(B);
return trB*abs(mat_trace(B));
}
template <typename MAT>
typename number_traits<typename
linalg_traits<MAT>::value_type>::magnitude_type
Frobenius_condition_number(const MAT& M)
{ return sqrt(Frobenius_condition_number_sqr(M)); }
/** estimation of the condition number (TO BE DONE...)
*/
template <typename MAT>
typename number_traits<typename
linalg_traits<MAT>::value_type>::magnitude_type
condest(const MAT& M,
typename number_traits<typename
linalg_traits<MAT>::value_type>::magnitude_type& emin,
typename number_traits<typename
linalg_traits<MAT>::value_type>::magnitude_type& emax) {
return condition_number(M, emin, emax);
}
template <typename MAT>
typename number_traits<typename
linalg_traits<MAT>::value_type>::magnitude_type
condest(const MAT& M) {
typename number_traits<typename
linalg_traits<MAT>::value_type>::magnitude_type emax, emin;
return condest(M, emin, emax);
}
}
#endif

398
gmm/gmm_conjugated.h Normal file
View File

@ -0,0 +1,398 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2003-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_conjugated.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date September 18, 2003.
@brief handle conjugation of complex matrices/vectors.
*/
#ifndef GMM_CONJUGATED_H__
#define GMM_CONJUGATED_H__
#include "gmm_def.h"
namespace gmm {
///@cond DOXY_SHOW_ALL_FUNCTIONS
/* ********************************************************************* */
/* Conjugated references on vectors */
/* ********************************************************************* */
template <typename IT> struct conjugated_const_iterator {
typedef typename std::iterator_traits<IT>::value_type value_type;
typedef typename std::iterator_traits<IT>::pointer pointer;
typedef typename std::iterator_traits<IT>::reference reference;
typedef typename std::iterator_traits<IT>::difference_type difference_type;
typedef typename std::iterator_traits<IT>::iterator_category
iterator_category;
IT it;
conjugated_const_iterator(void) {}
conjugated_const_iterator(const IT &i) : it(i) {}
inline size_type index(void) const { return it.index(); }
conjugated_const_iterator operator ++(int)
{ conjugated_const_iterator tmp = *this; ++it; return tmp; }
conjugated_const_iterator operator --(int)
{ conjugated_const_iterator tmp = *this; --it; return tmp; }
conjugated_const_iterator &operator ++() { ++it; return *this; }
conjugated_const_iterator &operator --() { --it; return *this; }
conjugated_const_iterator &operator +=(difference_type i)
{ it += i; return *this; }
conjugated_const_iterator &operator -=(difference_type i)
{ it -= i; return *this; }
conjugated_const_iterator operator +(difference_type i) const
{ conjugated_const_iterator itb = *this; return (itb += i); }
conjugated_const_iterator operator -(difference_type i) const
{ conjugated_const_iterator itb = *this; return (itb -= i); }
difference_type operator -(const conjugated_const_iterator &i) const
{ return difference_type(it - i.it); }
value_type operator *() const { return gmm::conj(*it); }
value_type operator [](size_type ii) const { return gmm::conj(it[ii]); }
bool operator ==(const conjugated_const_iterator &i) const
{ return (i.it == it); }
bool operator !=(const conjugated_const_iterator &i) const
{ return (i.it != it); }
bool operator < (const conjugated_const_iterator &i) const
{ return (it < i.it); }
};
template <typename V> struct conjugated_vector_const_ref {
typedef conjugated_vector_const_ref<V> this_type;
typedef typename linalg_traits<V>::value_type value_type;
typedef typename linalg_traits<V>::const_iterator iterator;
typedef typename linalg_traits<this_type>::reference reference;
typedef typename linalg_traits<this_type>::origin_type origin_type;
iterator begin_, end_;
const origin_type *origin;
size_type size_;
conjugated_vector_const_ref(const V &v)
: begin_(vect_const_begin(v)), end_(vect_const_end(v)),
origin(linalg_origin(v)),
size_(vect_size(v)) {}
reference operator[](size_type i) const
{ return gmm::conj(linalg_traits<V>::access(origin, begin_, end_, i)); }
};
template <typename V> struct linalg_traits<conjugated_vector_const_ref<V> > {
typedef conjugated_vector_const_ref<V> this_type;
typedef typename linalg_traits<V>::origin_type origin_type;
typedef linalg_const is_reference;
typedef abstract_vector linalg_type;
typedef typename linalg_traits<V>::value_type value_type;
typedef value_type reference;
typedef abstract_null_type iterator;
typedef conjugated_const_iterator<typename
linalg_traits<V>::const_iterator> const_iterator;
typedef typename linalg_traits<V>::storage_type storage_type;
typedef typename linalg_traits<V>::index_sorted index_sorted;
static size_type size(const this_type &v) { return v.size_; }
static iterator begin(this_type &v) { return iterator(v.begin_); }
static const_iterator begin(const this_type &v)
{ return const_iterator(v.begin_); }
static iterator end(this_type &v)
{ return iterator(v.end_); }
static const_iterator end(const this_type &v)
{ return const_iterator(v.end_); }
static value_type access(const origin_type *o, const const_iterator &it,
const const_iterator &ite, size_type i)
{ return gmm::conj(linalg_traits<V>::access(o, it.it, ite.it, i)); }
static const origin_type* origin(const this_type &v) { return v.origin; }
};
template<typename V> std::ostream &operator <<
(std::ostream &o, const conjugated_vector_const_ref<V>& m)
{ gmm::write(o,m); return o; }
/* ********************************************************************* */
/* Conjugated references on matrices */
/* ********************************************************************* */
template <typename M> struct conjugated_row_const_iterator {
typedef conjugated_row_const_iterator<M> iterator;
typedef typename linalg_traits<M>::const_row_iterator ITER;
typedef typename linalg_traits<M>::value_type value_type;
typedef ptrdiff_t difference_type;
typedef size_t size_type;
ITER it;
iterator operator ++(int) { iterator tmp = *this; it++; return tmp; }
iterator operator --(int) { iterator tmp = *this; it--; return tmp; }
iterator &operator ++() { it++; return *this; }
iterator &operator --() { it--; return *this; }
iterator &operator +=(difference_type i) { it += i; return *this; }
iterator &operator -=(difference_type i) { it -= i; return *this; }
iterator operator +(difference_type i) const
{ iterator itt = *this; return (itt += i); }
iterator operator -(difference_type i) const
{ iterator itt = *this; return (itt -= i); }
difference_type operator -(const iterator &i) const
{ return it - i.it; }
ITER operator *() const { return it; }
ITER operator [](int i) { return it + i; }
bool operator ==(const iterator &i) const { return (it == i.it); }
bool operator !=(const iterator &i) const { return !(i == *this); }
bool operator < (const iterator &i) const { return (it < i.it); }
conjugated_row_const_iterator(void) {}
conjugated_row_const_iterator(const ITER &i) : it(i) { }
};
template <typename M> struct conjugated_row_matrix_const_ref {
typedef conjugated_row_matrix_const_ref<M> this_type;
typedef typename linalg_traits<M>::const_row_iterator iterator;
typedef typename linalg_traits<M>::value_type value_type;
typedef typename linalg_traits<this_type>::origin_type origin_type;
iterator begin_, end_;
const origin_type *origin;
size_type nr, nc;
conjugated_row_matrix_const_ref(const M &m)
: begin_(mat_row_begin(m)), end_(mat_row_end(m)),
origin(linalg_origin(m)), nr(mat_ncols(m)), nc(mat_nrows(m)) {}
value_type operator()(size_type i, size_type j) const
{ return gmm::conj(linalg_traits<M>::access(begin_+j, i)); }
};
template<typename M> std::ostream &operator <<
(std::ostream &o, const conjugated_row_matrix_const_ref<M>& m)
{ gmm::write(o,m); return o; }
template <typename M> struct conjugated_col_const_iterator {
typedef conjugated_col_const_iterator<M> iterator;
typedef typename linalg_traits<M>::const_col_iterator ITER;
typedef typename linalg_traits<M>::value_type value_type;
typedef ptrdiff_t difference_type;
typedef size_t size_type;
ITER it;
iterator operator ++(int) { iterator tmp = *this; it++; return tmp; }
iterator operator --(int) { iterator tmp = *this; it--; return tmp; }
iterator &operator ++() { it++; return *this; }
iterator &operator --() { it--; return *this; }
iterator &operator +=(difference_type i) { it += i; return *this; }
iterator &operator -=(difference_type i) { it -= i; return *this; }
iterator operator +(difference_type i) const
{ iterator itt = *this; return (itt += i); }
iterator operator -(difference_type i) const
{ iterator itt = *this; return (itt -= i); }
difference_type operator -(const iterator &i) const
{ return it - i.it; }
ITER operator *() const { return it; }
ITER operator [](int i) { return it + i; }
bool operator ==(const iterator &i) const { return (it == i.it); }
bool operator !=(const iterator &i) const { return !(i == *this); }
bool operator < (const iterator &i) const { return (it < i.it); }
conjugated_col_const_iterator(void) {}
conjugated_col_const_iterator(const ITER &i) : it(i) { }
};
template <typename M> struct conjugated_col_matrix_const_ref {
typedef conjugated_col_matrix_const_ref<M> this_type;
typedef typename linalg_traits<M>::const_col_iterator iterator;
typedef typename linalg_traits<M>::value_type value_type;
typedef typename linalg_traits<this_type>::origin_type origin_type;
iterator begin_, end_;
const origin_type *origin;
size_type nr, nc;
conjugated_col_matrix_const_ref(const M &m)
: begin_(mat_col_begin(m)), end_(mat_col_end(m)),
origin(linalg_origin(m)), nr(mat_ncols(m)), nc(mat_nrows(m)) {}
value_type operator()(size_type i, size_type j) const
{ return gmm::conj(linalg_traits<M>::access(begin_+i, j)); }
};
template<typename M> std::ostream &operator <<
(std::ostream &o, const conjugated_col_matrix_const_ref<M>& m)
{ gmm::write(o,m); return o; }
template <typename L, typename SO> struct conjugated_return__ {
typedef conjugated_row_matrix_const_ref<L> return_type;
};
template <typename L> struct conjugated_return__<L, col_major> {
typedef conjugated_col_matrix_const_ref<L> return_type;
};
template <typename L, typename T, typename LT> struct conjugated_return_ {
typedef const L & return_type;
};
template <typename L, typename T>
struct conjugated_return_<L, std::complex<T>, abstract_vector> {
typedef conjugated_vector_const_ref<L> return_type;
};
template <typename L, typename T>
struct conjugated_return_<L, T, abstract_matrix> {
typedef typename conjugated_return__<L,
typename principal_orientation_type<typename
linalg_traits<L>::sub_orientation>::potype
>::return_type return_type;
};
template <typename L> struct conjugated_return {
typedef typename
conjugated_return_<L, typename linalg_traits<L>::value_type,
typename linalg_traits<L>::linalg_type
>::return_type return_type;
};
///@endcond
/** return a conjugated view of the input matrix or vector. */
template <typename L> inline
typename conjugated_return<L>::return_type
conjugated(const L &v) {
return conjugated(v, typename linalg_traits<L>::value_type(),
typename linalg_traits<L>::linalg_type());
}
///@cond DOXY_SHOW_ALL_FUNCTIONS
template <typename L, typename T, typename LT> inline
const L & conjugated(const L &v, T, LT) { return v; }
template <typename L, typename T> inline
conjugated_vector_const_ref<L> conjugated(const L &v, std::complex<T>,
abstract_vector)
{ return conjugated_vector_const_ref<L>(v); }
template <typename L, typename T> inline
typename conjugated_return__<L,
typename principal_orientation_type<typename
linalg_traits<L>::sub_orientation>::potype>::return_type
conjugated(const L &v, T, abstract_matrix) {
return conjugated(v, typename principal_orientation_type<typename
linalg_traits<L>::sub_orientation>::potype());
}
template <typename L> inline
conjugated_row_matrix_const_ref<L> conjugated(const L &v, row_major)
{ return conjugated_row_matrix_const_ref<L>(v); }
template <typename L> inline
conjugated_col_matrix_const_ref<L> conjugated(const L &v, col_major)
{ return conjugated_col_matrix_const_ref<L>(v); }
template <typename M>
struct linalg_traits<conjugated_row_matrix_const_ref<M> > {
typedef conjugated_row_matrix_const_ref<M> this_type;
typedef typename linalg_traits<M>::origin_type origin_type;
typedef linalg_const is_reference;
typedef abstract_matrix linalg_type;
typedef typename linalg_traits<M>::value_type value_type;
typedef value_type reference;
typedef typename linalg_traits<M>::storage_type storage_type;
typedef typename org_type<typename linalg_traits<M>::const_sub_row_type>::t vector_type;
typedef conjugated_vector_const_ref<vector_type> sub_col_type;
typedef conjugated_vector_const_ref<vector_type> const_sub_col_type;
typedef conjugated_row_const_iterator<M> col_iterator;
typedef conjugated_row_const_iterator<M> const_col_iterator;
typedef abstract_null_type const_sub_row_type;
typedef abstract_null_type sub_row_type;
typedef abstract_null_type const_row_iterator;
typedef abstract_null_type row_iterator;
typedef col_major sub_orientation;
typedef typename linalg_traits<M>::index_sorted index_sorted;
static inline size_type ncols(const this_type &m) { return m.nc; }
static inline size_type nrows(const this_type &m) { return m.nr; }
static inline const_sub_col_type col(const const_col_iterator &it)
{ return conjugated(linalg_traits<M>::row(it.it)); }
static inline const_col_iterator col_begin(const this_type &m)
{ return const_col_iterator(m.begin_); }
static inline const_col_iterator col_end(const this_type &m)
{ return const_col_iterator(m.end_); }
static inline const origin_type* origin(const this_type &m)
{ return m.origin; }
static value_type access(const const_col_iterator &it, size_type i)
{ return gmm::conj(linalg_traits<M>::access(it.it, i)); }
};
template <typename M>
struct linalg_traits<conjugated_col_matrix_const_ref<M> > {
typedef conjugated_col_matrix_const_ref<M> this_type;
typedef typename linalg_traits<M>::origin_type origin_type;
typedef linalg_const is_reference;
typedef abstract_matrix linalg_type;
typedef typename linalg_traits<M>::value_type value_type;
typedef value_type reference;
typedef typename linalg_traits<M>::storage_type storage_type;
typedef typename org_type<typename linalg_traits<M>::const_sub_col_type>::t vector_type;
typedef conjugated_vector_const_ref<vector_type> sub_row_type;
typedef conjugated_vector_const_ref<vector_type> const_sub_row_type;
typedef conjugated_col_const_iterator<M> row_iterator;
typedef conjugated_col_const_iterator<M> const_row_iterator;
typedef abstract_null_type const_sub_col_type;
typedef abstract_null_type sub_col_type;
typedef abstract_null_type const_col_iterator;
typedef abstract_null_type col_iterator;
typedef row_major sub_orientation;
typedef typename linalg_traits<M>::index_sorted index_sorted;
static inline size_type nrows(const this_type &m) { return m.nr; }
static inline size_type ncols(const this_type &m) { return m.nc; }
static inline const_sub_row_type row(const const_row_iterator &it)
{ return conjugated(linalg_traits<M>::col(it.it)); }
static inline const_row_iterator row_begin(const this_type &m)
{ return const_row_iterator(m.begin_); }
static inline const_row_iterator row_end(const this_type &m)
{ return const_row_iterator(m.end_); }
static inline const origin_type* origin(const this_type &m)
{ return m.origin; }
static value_type access(const const_row_iterator &it, size_type i)
{ return gmm::conj(linalg_traits<M>::access(it.it, i)); }
};
///@endcond
}
#endif // GMM_CONJUGATED_H__

1123
gmm/gmm_def.h Normal file

File diff suppressed because it is too large Load Diff

317
gmm/gmm_dense_Householder.h Normal file
View File

@ -0,0 +1,317 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2003-2017 Yves Renard, Caroline Lecalvez
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_dense_Householder.h
@author Caroline Lecalvez <Caroline.Lecalvez@gmm.insa-toulouse.fr>
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date June 5, 2003.
@brief Householder for dense matrices.
*/
#ifndef GMM_DENSE_HOUSEHOLDER_H
#define GMM_DENSE_HOUSEHOLDER_H
#include "gmm_kernel.h"
namespace gmm {
///@cond DOXY_SHOW_ALL_FUNCTIONS
/* ********************************************************************* */
/* Rank one update (complex and real version) */
/* ********************************************************************* */
template <typename Matrix, typename VecX, typename VecY>
inline void rank_one_update(Matrix &A, const VecX& x,
const VecY& y, row_major) {
typedef typename linalg_traits<Matrix>::value_type T;
size_type N = mat_nrows(A);
GMM_ASSERT2(N <= vect_size(x) && mat_ncols(A) <= vect_size(y),
"dimensions mismatch");
typename linalg_traits<VecX>::const_iterator itx = vect_const_begin(x);
for (size_type i = 0; i < N; ++i, ++itx) {
typedef typename linalg_traits<Matrix>::sub_row_type row_type;
row_type row = mat_row(A, i);
typename linalg_traits<typename org_type<row_type>::t>::iterator
it = vect_begin(row), ite = vect_end(row);
typename linalg_traits<VecY>::const_iterator ity = vect_const_begin(y);
T tx = *itx;
for (; it != ite; ++it, ++ity) *it += conj_product(*ity, tx);
}
}
template <typename Matrix, typename VecX, typename VecY>
inline void rank_one_update(Matrix &A, const VecX& x,
const VecY& y, col_major) {
typedef typename linalg_traits<Matrix>::value_type T;
size_type M = mat_ncols(A);
GMM_ASSERT2(mat_nrows(A) <= vect_size(x) && M <= vect_size(y),
"dimensions mismatch");
typename linalg_traits<VecY>::const_iterator ity = vect_const_begin(y);
for (size_type i = 0; i < M; ++i, ++ity) {
typedef typename linalg_traits<Matrix>::sub_col_type col_type;
col_type col = mat_col(A, i);
typename linalg_traits<typename org_type<col_type>::t>::iterator
it = vect_begin(col), ite = vect_end(col);
typename linalg_traits<VecX>::const_iterator itx = vect_const_begin(x);
T ty = *ity;
for (; it != ite; ++it, ++itx) *it += conj_product(ty, *itx);
}
}
///@endcond
template <typename Matrix, typename VecX, typename VecY>
inline void rank_one_update(const Matrix &AA, const VecX& x,
const VecY& y) {
Matrix& A = const_cast<Matrix&>(AA);
rank_one_update(A, x, y, typename principal_orientation_type<typename
linalg_traits<Matrix>::sub_orientation>::potype());
}
///@cond DOXY_SHOW_ALL_FUNCTIONS
/* ********************************************************************* */
/* Rank two update (complex and real version) */
/* ********************************************************************* */
template <typename Matrix, typename VecX, typename VecY>
inline void rank_two_update(Matrix &A, const VecX& x,
const VecY& y, row_major) {
typedef typename linalg_traits<Matrix>::value_type value_type;
size_type N = mat_nrows(A);
GMM_ASSERT2(N <= vect_size(x) && mat_ncols(A) <= vect_size(y),
"dimensions mismatch");
typename linalg_traits<VecX>::const_iterator itx1 = vect_const_begin(x);
typename linalg_traits<VecY>::const_iterator ity2 = vect_const_begin(y);
for (size_type i = 0; i < N; ++i, ++itx1, ++ity2) {
typedef typename linalg_traits<Matrix>::sub_row_type row_type;
row_type row = mat_row(A, i);
typename linalg_traits<typename org_type<row_type>::t>::iterator
it = vect_begin(row), ite = vect_end(row);
typename linalg_traits<VecX>::const_iterator itx2 = vect_const_begin(x);
typename linalg_traits<VecY>::const_iterator ity1 = vect_const_begin(y);
value_type tx = *itx1, ty = *ity2;
for (; it != ite; ++it, ++ity1, ++itx2)
*it += conj_product(*ity1, tx) + conj_product(*itx2, ty);
}
}
template <typename Matrix, typename VecX, typename VecY>
inline void rank_two_update(Matrix &A, const VecX& x,
const VecY& y, col_major) {
typedef typename linalg_traits<Matrix>::value_type value_type;
size_type M = mat_ncols(A);
GMM_ASSERT2(mat_nrows(A) <= vect_size(x) && M <= vect_size(y),
"dimensions mismatch");
typename linalg_traits<VecX>::const_iterator itx2 = vect_const_begin(x);
typename linalg_traits<VecY>::const_iterator ity1 = vect_const_begin(y);
for (size_type i = 0; i < M; ++i, ++ity1, ++itx2) {
typedef typename linalg_traits<Matrix>::sub_col_type col_type;
col_type col = mat_col(A, i);
typename linalg_traits<typename org_type<col_type>::t>::iterator
it = vect_begin(col), ite = vect_end(col);
typename linalg_traits<VecX>::const_iterator itx1 = vect_const_begin(x);
typename linalg_traits<VecY>::const_iterator ity2 = vect_const_begin(y);
value_type ty = *ity1, tx = *itx2;
for (; it != ite; ++it, ++itx1, ++ity2)
*it += conj_product(ty, *itx1) + conj_product(tx, *ity2);
}
}
///@endcond
template <typename Matrix, typename VecX, typename VecY>
inline void rank_two_update(const Matrix &AA, const VecX& x,
const VecY& y) {
Matrix& A = const_cast<Matrix&>(AA);
rank_two_update(A, x, y, typename principal_orientation_type<typename
linalg_traits<Matrix>::sub_orientation>::potype());
}
///@cond DOXY_SHOW_ALL_FUNCTIONS
/* ********************************************************************* */
/* Householder vector computation (complex and real version) */
/* ********************************************************************* */
template <typename VECT> void house_vector(const VECT &VV) {
VECT &V = const_cast<VECT &>(VV);
typedef typename linalg_traits<VECT>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
R mu = vect_norm2(V), abs_v0 = gmm::abs(V[0]);
if (mu != R(0))
gmm::scale(V, (abs_v0 == R(0)) ? T(R(1) / mu)
: (safe_divide(T(abs_v0), V[0]) / (abs_v0 + mu)));
if (gmm::real(V[vect_size(V)-1]) * R(0) != R(0)) gmm::clear(V);
V[0] = T(1);
}
template <typename VECT> void house_vector_last(const VECT &VV) {
VECT &V = const_cast<VECT &>(VV);
typedef typename linalg_traits<VECT>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type m = vect_size(V);
R mu = vect_norm2(V), abs_v0 = gmm::abs(V[m-1]);
if (mu != R(0))
gmm::scale(V, (abs_v0 == R(0)) ? T(R(1) / mu)
: ((abs_v0 / V[m-1]) / (abs_v0 + mu)));
if (gmm::real(V[0]) * R(0) != R(0)) gmm::clear(V);
V[m-1] = T(1);
}
/* ********************************************************************* */
/* Householder updates (complex and real version) */
/* ********************************************************************* */
// multiply A to the left by the reflector stored in V. W is a temporary.
template <typename MAT, typename VECT1, typename VECT2> inline
void row_house_update(const MAT &AA, const VECT1 &V, const VECT2 &WW) {
VECT2 &W = const_cast<VECT2 &>(WW); MAT &A = const_cast<MAT &>(AA);
typedef typename linalg_traits<MAT>::value_type value_type;
typedef typename number_traits<value_type>::magnitude_type magnitude_type;
gmm::mult(conjugated(A),
scaled(V, value_type(magnitude_type(-2)/vect_norm2_sqr(V))), W);
rank_one_update(A, V, W);
}
// multiply A to the right by the reflector stored in V. W is a temporary.
template <typename MAT, typename VECT1, typename VECT2> inline
void col_house_update(const MAT &AA, const VECT1 &V, const VECT2 &WW) {
VECT2 &W = const_cast<VECT2 &>(WW); MAT &A = const_cast<MAT &>(AA);
typedef typename linalg_traits<MAT>::value_type value_type;
typedef typename number_traits<value_type>::magnitude_type magnitude_type;
gmm::mult(A,
scaled(V, value_type(magnitude_type(-2)/vect_norm2_sqr(V))), W);
rank_one_update(A, W, V);
}
///@endcond
/* ********************************************************************* */
/* Hessenberg reduction with Householder. */
/* ********************************************************************* */
template <typename MAT1, typename MAT2>
void Hessenberg_reduction(const MAT1& AA, const MAT2 &QQ, bool compute_Q){
MAT1& A = const_cast<MAT1&>(AA); MAT2& Q = const_cast<MAT2&>(QQ);
typedef typename linalg_traits<MAT1>::value_type value_type;
if (compute_Q) gmm::copy(identity_matrix(), Q);
size_type n = mat_nrows(A); if (n < 2) return;
std::vector<value_type> v(n), w(n);
sub_interval SUBK(0,n);
for (size_type k = 1; k+1 < n; ++k) {
sub_interval SUBI(k, n-k), SUBJ(k-1,n-k+1);
v.resize(n-k);
for (size_type j = k; j < n; ++j) v[j-k] = A(j, k-1);
house_vector(v);
row_house_update(sub_matrix(A, SUBI, SUBJ), v, sub_vector(w, SUBJ));
col_house_update(sub_matrix(A, SUBK, SUBI), v, w);
// is it possible to "unify" the two on the common part of the matrix?
if (compute_Q) col_house_update(sub_matrix(Q, SUBK, SUBI), v, w);
}
}
/* ********************************************************************* */
/* Householder tridiagonalization for symmetric matrices */
/* ********************************************************************* */
template <typename MAT1, typename MAT2>
void Householder_tridiagonalization(const MAT1 &AA, const MAT2 &QQ,
bool compute_q) {
MAT1 &A = const_cast<MAT1 &>(AA); MAT2 &Q = const_cast<MAT2 &>(QQ);
typedef typename linalg_traits<MAT1>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type n = mat_nrows(A); if (n < 2) return;
std::vector<T> v(n), p(n), w(n), ww(n);
sub_interval SUBK(0,n);
for (size_type k = 1; k+1 < n; ++k) { // not optimized ...
sub_interval SUBI(k, n-k);
v.resize(n-k); p.resize(n-k); w.resize(n-k);
for (size_type l = k; l < n; ++l)
{ v[l-k] = w[l-k] = A(l, k-1); A(l, k-1) = A(k-1, l) = T(0); }
house_vector(v);
R norm = vect_norm2_sqr(v);
A(k-1, k) = gmm::conj(A(k, k-1) = w[0] - T(2)*v[0]*vect_hp(w, v)/norm);
gmm::mult(sub_matrix(A, SUBI), gmm::scaled(v, T(-2) / norm), p);
gmm::add(p, gmm::scaled(v, -vect_hp(v, p) / norm), w);
rank_two_update(sub_matrix(A, SUBI), v, w);
// it should be possible to compute only the upper or lower part
if (compute_q) col_house_update(sub_matrix(Q, SUBK, SUBI), v, ww);
}
}
/* ********************************************************************* */
/* Real and complex Givens rotations */
/* ********************************************************************* */
template <typename T> void Givens_rotation(T a, T b, T &c, T &s) {
typedef typename number_traits<T>::magnitude_type R;
R aa = gmm::abs(a), bb = gmm::abs(b);
if (bb == R(0)) { c = T(1); s = T(0); return; }
if (aa == R(0)) { c = T(0); s = b / bb; return; }
if (bb > aa)
{ T t = -safe_divide(a,b); s = T(R(1) / (sqrt(R(1)+gmm::abs_sqr(t)))); c = s * t; }
else
{ T t = -safe_divide(b,a); c = T(R(1) / (sqrt(R(1)+gmm::abs_sqr(t)))); s = c * t; }
}
// Apply Q* v
template <typename T> inline
void Apply_Givens_rotation_left(T &x, T &y, T c, T s)
{ T t1=x, t2=y; x = gmm::conj(c)*t1 - gmm::conj(s)*t2; y = c*t2 + s*t1; }
// Apply v^T Q
template <typename T> inline
void Apply_Givens_rotation_right(T &x, T &y, T c, T s)
{ T t1=x, t2=y; x = c*t1 - s*t2; y = gmm::conj(c)*t2 + gmm::conj(s)*t1; }
template <typename MAT, typename T>
void row_rot(const MAT &AA, T c, T s, size_type i, size_type k) {
MAT &A = const_cast<MAT &>(AA); // can be specialized for row matrices
for (size_type j = 0; j < mat_ncols(A); ++j)
Apply_Givens_rotation_left(A(i,j), A(k,j), c, s);
}
template <typename MAT, typename T>
void col_rot(const MAT &AA, T c, T s, size_type i, size_type k) {
MAT &A = const_cast<MAT &>(AA); // can be specialized for column matrices
for (size_type j = 0; j < mat_nrows(A); ++j)
Apply_Givens_rotation_right(A(j,i), A(j,k), c, s);
}
}
#endif

250
gmm/gmm_dense_lu.h Normal file
View File

@ -0,0 +1,250 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2003-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
// This file is a modified version of lu.h from MTL.
// See http://osl.iu.edu/research/mtl/
// Following the corresponding Copyright notice.
//===========================================================================
//
// Copyright (c) 1998-2001, University of Notre Dame. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the University of Notre Dame nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//===========================================================================
/**@file gmm_dense_lu.h
@author Andrew Lumsdaine, Jeremy G. Siek, Lie-Quan Lee, Y. Renard
@date June 5, 2003.
@brief LU factorizations and determinant computation for dense matrices.
*/
#ifndef GMM_DENSE_LU_H
#define GMM_DENSE_LU_H
#include "gmm_dense_Householder.h"
#include "gmm_opt.h"
namespace gmm {
/** LU Factorization of a general (dense) matrix (real or complex).
This is the outer product (a level-2 operation) form of the LU
Factorization with pivoting algorithm . This is equivalent to
LAPACK's dgetf2. Also see "Matrix Computations" 3rd Ed. by Golub
and Van Loan section 3.2.5 and especially page 115.
The pivot indices in ipvt are indexed starting from 1
so that this is compatible with LAPACK (Fortran).
*/
template <typename DenseMatrix, typename Pvector>
size_type lu_factor(DenseMatrix& A, Pvector& ipvt) {
typedef typename linalg_traits<DenseMatrix>::value_type T;
typedef typename linalg_traits<Pvector>::value_type int_T;
typedef typename number_traits<T>::magnitude_type R;
size_type info(0), i, j, jp, M(mat_nrows(A)), N(mat_ncols(A));
size_type NN = std::min(M, N);
std::vector<T> c(M), r(N);
GMM_ASSERT2(ipvt.size()+1 >= NN, "IPVT too small");
for (i = 0; i+1 < NN; ++i) ipvt[i] = int_T(i);
if (M || N) {
for (j = 0; j+1 < NN; ++j) {
R max = gmm::abs(A(j,j)); jp = j;
for (i = j+1; i < M; ++i) /* find pivot. */
if (gmm::abs(A(i,j)) > max) { jp = i; max = gmm::abs(A(i,j)); }
ipvt[j] = int_T(jp + 1);
if (max == R(0)) { info = j + 1; break; }
if (jp != j) for (i = 0; i < N; ++i) std::swap(A(jp, i), A(j, i));
for (i = j+1; i < M; ++i) { A(i, j) /= A(j,j); c[i-j-1] = -A(i, j); }
for (i = j+1; i < N; ++i) r[i-j-1] = A(j, i); // avoid the copy ?
rank_one_update(sub_matrix(A, sub_interval(j+1, M-j-1),
sub_interval(j+1, N-j-1)), c, conjugated(r));
}
ipvt[NN-1] = int_T(NN);
}
return info;
}
/** LU Solve : Solve equation Ax=b, given an LU factored matrix.*/
// Thanks to Valient Gough for this routine!
template <typename DenseMatrix, typename VectorB, typename VectorX,
typename Pvector>
void lu_solve(const DenseMatrix &LU, const Pvector& pvector,
VectorX &x, const VectorB &b) {
typedef typename linalg_traits<DenseMatrix>::value_type T;
copy(b, x);
for(size_type i = 0; i < pvector.size(); ++i) {
size_type perm = pvector[i]-1; // permutations stored in 1's offset
if(i != perm) { T aux = x[i]; x[i] = x[perm]; x[perm] = aux; }
}
/* solve Ax = b -> LUx = b -> Ux = L^-1 b. */
lower_tri_solve(LU, x, true);
upper_tri_solve(LU, x, false);
}
template <typename DenseMatrix, typename VectorB, typename VectorX>
void lu_solve(const DenseMatrix &A, VectorX &x, const VectorB &b) {
typedef typename linalg_traits<DenseMatrix>::value_type T;
dense_matrix<T> B(mat_nrows(A), mat_ncols(A));
std::vector<int> ipvt(mat_nrows(A));
gmm::copy(A, B);
size_type info = lu_factor(B, ipvt);
GMM_ASSERT1(!info, "Singular system, pivot = " << info);
lu_solve(B, ipvt, x, b);
}
template <typename DenseMatrix, typename VectorB, typename VectorX,
typename Pvector>
void lu_solve_transposed(const DenseMatrix &LU, const Pvector& pvector,
VectorX &x, const VectorB &b) {
typedef typename linalg_traits<DenseMatrix>::value_type T;
copy(b, x);
lower_tri_solve(transposed(LU), x, false);
upper_tri_solve(transposed(LU), x, true);
for(size_type i = pvector.size(); i > 0; --i) {
size_type perm = pvector[i-1]-1; // permutations stored in 1's offset
if(i-1 != perm) { T aux = x[i-1]; x[i-1] = x[perm]; x[perm] = aux; }
}
}
///@cond DOXY_SHOW_ALL_FUNCTIONS
template <typename DenseMatrixLU, typename DenseMatrix, typename Pvector>
void lu_inverse(const DenseMatrixLU& LU, const Pvector& pvector,
DenseMatrix& AInv, col_major) {
typedef typename linalg_traits<DenseMatrixLU>::value_type T;
std::vector<T> tmp(pvector.size(), T(0));
std::vector<T> result(pvector.size());
for(size_type i = 0; i < pvector.size(); ++i) {
tmp[i] = T(1);
lu_solve(LU, pvector, result, tmp);
copy(result, mat_col(AInv, i));
tmp[i] = T(0);
}
}
template <typename DenseMatrixLU, typename DenseMatrix, typename Pvector>
void lu_inverse(const DenseMatrixLU& LU, const Pvector& pvector,
DenseMatrix& AInv, row_major) {
typedef typename linalg_traits<DenseMatrixLU>::value_type T;
std::vector<T> tmp(pvector.size(), T(0));
std::vector<T> result(pvector.size());
for(size_type i = 0; i < pvector.size(); ++i) {
tmp[i] = T(1); // to be optimized !!
// on peut sur le premier tri solve reduire le systeme
// et peut etre faire un solve sur une serie de vecteurs au lieu
// de vecteur a vecteur (accumulation directe de l'inverse dans la
// matrice au fur et a mesure du calcul ... -> evite la copie finale
lu_solve_transposed(LU, pvector, result, tmp);
copy(result, mat_row(AInv, i));
tmp[i] = T(0);
}
}
///@endcond
/** Given an LU factored matrix, build the inverse of the matrix. */
template <typename DenseMatrixLU, typename DenseMatrix, typename Pvector>
void lu_inverse(const DenseMatrixLU& LU, const Pvector& pvector,
const DenseMatrix& AInv_) {
DenseMatrix& AInv = const_cast<DenseMatrix&>(AInv_);
lu_inverse(LU, pvector, AInv, typename principal_orientation_type<typename
linalg_traits<DenseMatrix>::sub_orientation>::potype());
}
/** Given a dense matrix, build the inverse of the matrix, and
return the determinant */
template <typename DenseMatrix>
typename linalg_traits<DenseMatrix>::value_type
lu_inverse(const DenseMatrix& A_, bool doassert = true) {
typedef typename linalg_traits<DenseMatrix>::value_type T;
DenseMatrix& A = const_cast<DenseMatrix&>(A_);
dense_matrix<T> B(mat_nrows(A), mat_ncols(A));
std::vector<int> ipvt(mat_nrows(A));
gmm::copy(A, B);
size_type info = lu_factor(B, ipvt);
if (doassert) GMM_ASSERT1(!info, "Non invertible matrix, pivot = "<<info);
if (!info) lu_inverse(B, ipvt, A);
return lu_det(B, ipvt);
}
/** Compute the matrix determinant (via a LU factorization) */
template <typename DenseMatrixLU, typename Pvector>
typename linalg_traits<DenseMatrixLU>::value_type
lu_det(const DenseMatrixLU& LU, const Pvector &pvector) {
typedef typename linalg_traits<DenseMatrixLU>::value_type T;
T det(1);
for (size_type j = 0; j < std::min(mat_nrows(LU), mat_ncols(LU)); ++j)
det *= LU(j,j);
for(size_type i = 0; i < pvector.size(); ++i)
if (i != size_type(pvector[i]-1)) { det = -det; }
return det;
}
template <typename DenseMatrix>
typename linalg_traits<DenseMatrix>::value_type
lu_det(const DenseMatrix& A) {
typedef typename linalg_traits<DenseMatrix>::value_type T;
dense_matrix<T> B(mat_nrows(A), mat_ncols(A));
std::vector<int> ipvt(mat_nrows(A));
gmm::copy(A, B);
lu_factor(B, ipvt);
return lu_det(B, ipvt);
}
}
#endif

View File

@ -0,0 +1,302 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2014-2017 Konstantinos Poulios
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_dense_matrix_functions.h
@author Konstantinos Poulios <poulios.konstantinos@gmail.com>
@date December 10, 2014.
@brief Common matrix functions for dense matrices.
*/
#ifndef GMM_DENSE_MATRIX_FUNCTIONS_H
#define GMM_DENSE_MATRIX_FUNCTIONS_H
namespace gmm {
/**
Matrix square root for upper triangular matrices (from GNU Octave).
*/
template <typename T>
void sqrtm_utri_inplace(dense_matrix<T>& A)
{
typedef typename number_traits<T>::magnitude_type R;
bool singular = false;
// The following code is equivalent to this triple loop:
//
// n = rows (A);
// for j = 1:n
// A(j,j) = sqrt (A(j,j));
// for i = j-1:-1:1
// A(i,j) /= (A(i,i) + A(j,j));
// k = 1:i-1;
// t storing a A(k,j) -= A(k,i) * A(i,j);
// endfor
// endfor
R tol = R(0); // default_tol(R()) * gmm::mat_maxnorm(A);
const size_type n = mat_nrows(A);
for (int j=0; j < int(n); j++) {
typename dense_matrix<T>::iterator colj = A.begin() + j*n;
if (gmm::abs(colj[j]) > tol)
colj[j] = gmm::sqrt(colj[j]);
else
singular = true;
for (int i=j-1; i >= 0; i--) {
typename dense_matrix<T>::const_iterator coli = A.begin() + i*n;
T colji = colj[i] = safe_divide(colj[i], (coli[i] + colj[j]));
for (int k = 0; k < i; k++)
colj[k] -= coli[k] * colji;
}
}
if (singular)
GMM_WARNING1("Matrix is singular, may not have a square root");
}
template <typename T>
void sqrtm(const dense_matrix<std::complex<T> >& A,
dense_matrix<std::complex<T> >& SQRTMA)
{
GMM_ASSERT1(gmm::mat_nrows(A) == gmm::mat_ncols(A),
"Matrix square root requires a square matrix");
gmm::resize(SQRTMA, gmm::mat_nrows(A), gmm::mat_ncols(A));
dense_matrix<std::complex<T> > S(A), Q(A), TMP(A);
#if defined(GMM_USES_LAPACK)
schur(TMP, S, Q);
#else
GMM_ASSERT1(false, "Please recompile with lapack and blas librairies "
"to use sqrtm matrix function.");
#endif
sqrtm_utri_inplace(S);
gmm::mult(Q, S, TMP);
gmm::mult(TMP, gmm::transposed(Q), SQRTMA);
}
template <typename T>
void sqrtm(const dense_matrix<T>& A,
dense_matrix<std::complex<T> >& SQRTMA)
{
dense_matrix<std::complex<T> > cA(mat_nrows(A), mat_ncols(A));
gmm::copy(A, gmm::real_part(cA));
sqrtm(cA, SQRTMA);
}
template <typename T>
void sqrtm(const dense_matrix<T>& A, dense_matrix<T>& SQRTMA)
{
dense_matrix<std::complex<T> > cA(mat_nrows(A), mat_ncols(A));
gmm::copy(A, gmm::real_part(cA));
dense_matrix<std::complex<T> > cSQRTMA(cA);
sqrtm(cA, cSQRTMA);
gmm::resize(SQRTMA, gmm::mat_nrows(A), gmm::mat_ncols(A));
gmm::copy(gmm::real_part(cSQRTMA), SQRTMA);
// dense_matrix<std::complex<T1> >::const_reference
// it = cSQRTMA.begin(), ite = cSQRTMA.end();
// dense_matrix<std::complex<T1> >::reference
// rit = SQRTMA.begin();
// for (; it != ite; ++it, ++rit) *rit = it->real();
}
/**
Matrix logarithm for upper triangular matrices (from GNU/Octave)
*/
template <typename T>
void logm_utri_inplace(dense_matrix<T>& S)
{
typedef typename number_traits<T>::magnitude_type R;
size_type n = gmm::mat_nrows(S);
GMM_ASSERT1(n == gmm::mat_ncols(S),
"Matrix logarithm is not defined for non-square matrices");
for (size_type i=0; i < n-1; ++i)
if (gmm::abs(S(i+1,i)) > default_tol(T())) {
GMM_ASSERT1(false, "An upper triangular matrix is expected");
break;
}
for (size_type i=0; i < n-1; ++i)
if (gmm::real(S(i,i)) <= -default_tol(R()) &&
gmm::abs(gmm::imag(S(i,i))) <= default_tol(R())) {
GMM_ASSERT1(false, "Principal matrix logarithm is not defined "
"for matrices with negative eigenvalues");
break;
}
// Algorithm 11.9 in "Function of matrices", by N. Higham
R theta[] = { R(0),R(0),R(1.61e-2),R(5.38e-2),R(1.13e-1),R(1.86e-1),R(2.6429608311114350e-1) };
R scaling(1);
size_type p(0), m(6), opt_iters(100);
for (size_type k=0; k < opt_iters; ++k, scaling *= R(2)) {
dense_matrix<T> auxS(S);
for (size_type i = 0; i < n; ++i) auxS(i,i) -= R(1);
R tau = gmm::mat_norm1(auxS);
if (tau <= theta[6]) {
++p;
size_type j1(6), j2(6);
for (size_type j=0; j < 6; ++j)
if (tau <= theta[j]) { j1 = j; break; }
for (size_type j=0; j < j1; ++j)
if (tau <= 2*theta[j]) { j2 = j; break; }
if (j1 - j2 <= 1 || p == 2) { m = j1; break; }
}
sqrtm_utri_inplace(S);
if (k == opt_iters-1)
GMM_WARNING1 ("Maximum number of square roots exceeded; "
"the calculated matrix logarithm may still be accurate");
}
for (size_type i = 0; i < n; ++i) S(i,i) -= R(1);
if (m > 0) {
std::vector<R> nodes, wts;
switch(m) {
case 0: {
R nodes_[] = { R(0.5) };
R wts_[] = { R(1) };
nodes.assign(nodes_, nodes_+m+1);
wts.assign(wts_, wts_+m+1);
} break;
case 1: {
R nodes_[] = { R(0.211324865405187),R(0.788675134594813) };
R wts_[] = { R(0.5),R(0.5) };
nodes.assign(nodes_, nodes_+m+1);
wts.assign(wts_, wts_+m+1);
} break;
case 2: {
R nodes_[] = { R(0.112701665379258),R(0.500000000000000),R(0.887298334620742) };
R wts_[] = { R(0.277777777777778),R(0.444444444444444),R(0.277777777777778) };
nodes.assign(nodes_, nodes_+m+1);
wts.assign(wts_, wts_+m+1);
} break;
case 3: {
R nodes_[] = { R(0.0694318442029737),R(0.3300094782075718),R(0.6699905217924281),R(0.9305681557970263) };
R wts_[] = { R(0.173927422568727),R(0.326072577431273),R(0.326072577431273),R(0.173927422568727) };
nodes.assign(nodes_, nodes_+m+1);
wts.assign(wts_, wts_+m+1);
} break;
case 4: {
R nodes_[] = { R(0.0469100770306681),R(0.2307653449471584),R(0.5000000000000000),R(0.7692346550528415),R(0.9530899229693319) };
R wts_[] = { R(0.118463442528095),R(0.239314335249683),R(0.284444444444444),R(0.239314335249683),R(0.118463442528094) };
nodes.assign(nodes_, nodes_+m+1);
wts.assign(wts_, wts_+m+1);
} break;
case 5: {
R nodes_[] = { R(0.0337652428984240),R(0.1693953067668678),R(0.3806904069584015),R(0.6193095930415985),R(0.8306046932331322),R(0.9662347571015761) };
R wts_[] = { R(0.0856622461895853),R(0.1803807865240693),R(0.2339569672863452),R(0.2339569672863459),R(0.1803807865240693),R(0.0856622461895852) };
nodes.assign(nodes_, nodes_+m+1);
wts.assign(wts_, wts_+m+1);
} break;
case 6: {
R nodes_[] = { R(0.0254460438286208),R(0.1292344072003028),R(0.2970774243113015),R(0.4999999999999999),R(0.7029225756886985),R(0.8707655927996973),R(0.9745539561713792) };
R wts_[] = { R(0.0647424830844348),R(0.1398526957446384),R(0.1909150252525594),R(0.2089795918367343),R(0.1909150252525595),R(0.1398526957446383),R(0.0647424830844349) };
nodes.assign(nodes_, nodes_+m+1);
wts.assign(wts_, wts_+m+1);
} break;
}
dense_matrix<T> auxS1(S), auxS2(S);
std::vector<T> auxvec(n);
gmm::clear(S);
for (size_type j=0; j <= m; ++j) {
gmm::copy(gmm::scaled(auxS1, nodes[j]), auxS2);
gmm::add(gmm::identity_matrix(), auxS2);
// S += wts[i] * auxS1 * inv(auxS2)
for (size_type i=0; i < n; ++i) {
gmm::copy(gmm::mat_row(auxS1, i), auxvec);
gmm::lower_tri_solve(gmm::transposed(auxS2), auxvec, false);
gmm::add(gmm::scaled(auxvec, wts[j]), gmm::mat_row(S, i));
}
}
}
gmm::scale(S, scaling);
}
/**
Matrix logarithm (from GNU/Octave)
*/
template <typename T>
void logm(const dense_matrix<T>& A, dense_matrix<T>& LOGMA)
{
typedef typename number_traits<T>::magnitude_type R;
size_type n = gmm::mat_nrows(A);
GMM_ASSERT1(n == gmm::mat_ncols(A),
"Matrix logarithm is not defined for non-square matrices");
dense_matrix<T> S(A), Q(A);
#if defined(GMM_USES_LAPACK)
schur(A, S, Q); // A = Q * S * Q^T
#else
GMM_ASSERT1(false, "Please recompile with lapack and blas librairies "
"to use logm matrix function.");
#endif
bool convert_to_complex(false);
if (!is_complex(T()))
for (size_type i=0; i < n-1; ++i)
if (gmm::abs(S(i+1,i)) > default_tol(T())) {
convert_to_complex = true;
break;
}
gmm::resize(LOGMA, n, n);
if (convert_to_complex) {
dense_matrix<std::complex<R> > cS(n,n), cQ(n,n), auxmat(n,n);
gmm::copy(gmm::real_part(S), gmm::real_part(cS));
gmm::copy(gmm::real_part(Q), gmm::real_part(cQ));
block2x2_reduction(cS, cQ, default_tol(R())*R(3));
for (size_type j=0; j < n-1; ++j)
for (size_type i=j+1; i < n; ++i)
cS(i,j) = T(0);
logm_utri_inplace(cS);
gmm::mult(cQ, cS, auxmat);
gmm::mult(auxmat, gmm::transposed(cQ), cS);
// Remove small complex values which may have entered calculation
gmm::copy(gmm::real_part(cS), LOGMA);
// GMM_ASSERT1(gmm::mat_norm1(gmm::imag_part(cS)) < n*default_tol(T()),
// "Internal error, imag part should be zero");
} else {
dense_matrix<T> auxmat(n,n);
logm_utri_inplace(S);
gmm::mult(Q, S, auxmat);
gmm::mult(auxmat, gmm::transposed(Q), LOGMA);
}
}
}
#endif

789
gmm/gmm_dense_qr.h Normal file
View File

@ -0,0 +1,789 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2003-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_dense_qr.h
@author Caroline Lecalvez, Caroline.Lecalvez@gmm.insa-tlse.fr, Yves Renard <Yves.Renard@insa-lyon.fr>
@date September 12, 2003.
@brief Dense QR factorization.
*/
#ifndef GMM_DENSE_QR_H
#define GMM_DENSE_QR_H
#include "gmm_dense_Householder.h"
namespace gmm {
/**
QR factorization using Householder method (complex and real version).
*/
template <typename MAT1>
void qr_factor(const MAT1 &A_) {
MAT1 &A = const_cast<MAT1 &>(A_);
typedef typename linalg_traits<MAT1>::value_type value_type;
size_type m = mat_nrows(A), n = mat_ncols(A);
GMM_ASSERT2(m >= n, "dimensions mismatch");
std::vector<value_type> W(m), V(m);
for (size_type j = 0; j < n; ++j) {
sub_interval SUBI(j, m-j), SUBJ(j, n-j);
V.resize(m-j); W.resize(n-j);
for (size_type i = j; i < m; ++i) V[i-j] = A(i, j);
house_vector(V);
row_house_update(sub_matrix(A, SUBI, SUBJ), V, W);
for (size_type i = j+1; i < m; ++i) A(i, j) = V[i-j];
}
}
// QR comes from QR_factor(QR) where the upper triangular part stands for R
// and the lower part contains the Householder reflectors.
// A <- AQ
template <typename MAT1, typename MAT2>
void apply_house_right(const MAT1 &QR, const MAT2 &A_) {
MAT2 &A = const_cast<MAT2 &>(A_);
typedef typename linalg_traits<MAT1>::value_type T;
size_type m = mat_nrows(QR), n = mat_ncols(QR);
GMM_ASSERT2(m == mat_ncols(A), "dimensions mismatch");
if (m == 0) return;
std::vector<T> V(m), W(mat_nrows(A));
V[0] = T(1);
for (size_type j = 0; j < n; ++j) {
V.resize(m-j);
for (size_type i = j+1; i < m; ++i) V[i-j] = QR(i, j);
col_house_update(sub_matrix(A, sub_interval(0, mat_nrows(A)),
sub_interval(j, m-j)), V, W);
}
}
// QR comes from QR_factor(QR) where the upper triangular part stands for R
// and the lower part contains the Householder reflectors.
// A <- Q*A
template <typename MAT1, typename MAT2>
void apply_house_left(const MAT1 &QR, const MAT2 &A_) {
MAT2 &A = const_cast<MAT2 &>(A_);
typedef typename linalg_traits<MAT1>::value_type T;
size_type m = mat_nrows(QR), n = mat_ncols(QR);
GMM_ASSERT2(m == mat_nrows(A), "dimensions mismatch");
if (m == 0) return;
std::vector<T> V(m), W(mat_ncols(A));
V[0] = T(1);
for (size_type j = 0; j < n; ++j) {
V.resize(m-j);
for (size_type i = j+1; i < m; ++i) V[i-j] = QR(i, j);
row_house_update(sub_matrix(A, sub_interval(j, m-j),
sub_interval(0, mat_ncols(A))), V, W);
}
}
/** Compute the QR factorization, where Q is assembled. */
template <typename MAT1, typename MAT2, typename MAT3>
void qr_factor(const MAT1 &A, const MAT2 &QQ, const MAT3 &RR) {
MAT2 &Q = const_cast<MAT2 &>(QQ); MAT3 &R = const_cast<MAT3 &>(RR);
typedef typename linalg_traits<MAT1>::value_type value_type;
size_type m = mat_nrows(A), n = mat_ncols(A);
GMM_ASSERT2(m >= n, "dimensions mismatch");
gmm::copy(A, Q);
std::vector<value_type> W(m);
dense_matrix<value_type> VV(m, n);
for (size_type j = 0; j < n; ++j) {
sub_interval SUBI(j, m-j), SUBJ(j, n-j);
for (size_type i = j; i < m; ++i) VV(i,j) = Q(i, j);
house_vector(sub_vector(mat_col(VV,j), SUBI));
row_house_update(sub_matrix(Q, SUBI, SUBJ),
sub_vector(mat_col(VV,j), SUBI), sub_vector(W, SUBJ));
}
gmm::copy(sub_matrix(Q, sub_interval(0, n), sub_interval(0, n)), R);
gmm::copy(identity_matrix(), Q);
for (size_type j = n-1; j != size_type(-1); --j) {
sub_interval SUBI(j, m-j), SUBJ(j, n-j);
row_house_update(sub_matrix(Q, SUBI, SUBJ),
sub_vector(mat_col(VV,j), SUBI), sub_vector(W, SUBJ));
}
}
///@cond DOXY_SHOW_ALL_FUNCTIONS
template <typename TA, typename TV, typename Ttol,
typename MAT, typename VECT>
void extract_eig(const MAT &A, VECT &V, Ttol tol, TA, TV) {
size_type n = mat_nrows(A);
if (n == 0) return;
tol *= Ttol(2);
Ttol tol_i = tol * gmm::abs(A(0,0)), tol_cplx = tol_i;
for (size_type i = 0; i < n; ++i) {
if (i < n-1) {
tol_i = (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol;
tol_cplx = std::max(tol_cplx, tol_i);
}
if ((i < n-1) && gmm::abs(A(i+1,i)) >= tol_i) {
TA tr = A(i,i) + A(i+1, i+1);
TA det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
TA delta = tr*tr - TA(4) * det;
if (delta < -tol_cplx) {
GMM_WARNING1("A complex eigenvalue has been detected : "
<< std::complex<TA>(tr/TA(2), gmm::sqrt(-delta)/TA(2)));
V[i] = V[i+1] = tr / TA(2);
}
else {
delta = std::max(TA(0), delta);
V[i ] = TA(tr + gmm::sqrt(delta))/ TA(2);
V[i+1] = TA(tr - gmm::sqrt(delta))/ TA(2);
}
++i;
}
else
V[i] = TV(A(i,i));
}
}
template <typename TA, typename TV, typename Ttol,
typename MAT, typename VECT>
void extract_eig(const MAT &A, VECT &V, Ttol tol, TA, std::complex<TV>) {
size_type n = mat_nrows(A);
tol *= Ttol(2);
for (size_type i = 0; i < n; ++i)
if ((i == n-1) ||
gmm::abs(A(i+1,i)) < (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol)
V[i] = std::complex<TV>(A(i,i));
else {
TA tr = A(i,i) + A(i+1, i+1);
TA det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
TA delta = tr*tr - TA(4) * det;
if (delta < TA(0)) {
V[i] = std::complex<TV>(tr / TA(2), gmm::sqrt(-delta) / TA(2));
V[i+1] = std::complex<TV>(tr / TA(2), -gmm::sqrt(-delta)/ TA(2));
}
else {
V[i ] = TA(tr + gmm::sqrt(delta)) / TA(2);
V[i+1] = TA(tr - gmm::sqrt(delta)) / TA(2);
}
++i;
}
}
template <typename TA, typename TV, typename Ttol,
typename MAT, typename VECT>
void extract_eig(const MAT &A, VECT &V, Ttol tol, std::complex<TA>, TV) {
typedef std::complex<TA> T;
size_type n = mat_nrows(A);
if (n == 0) return;
tol *= Ttol(2);
Ttol tol_i = tol * gmm::abs(A(0,0)), tol_cplx = tol_i;
for (size_type i = 0; i < n; ++i) {
if (i < n-1) {
tol_i = (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol;
tol_cplx = std::max(tol_cplx, tol_i);
}
if ((i == n-1) || gmm::abs(A(i+1,i)) < tol_i) {
if (gmm::abs(std::imag(A(i,i))) > tol_cplx)
GMM_WARNING1("A complex eigenvalue has been detected : "
<< T(A(i,i)) << " : " << gmm::abs(std::imag(A(i,i)))
/ gmm::abs(std::real(A(i,i))) << " : " << tol_cplx);
V[i] = std::real(A(i,i));
}
else {
T tr = A(i,i) + A(i+1, i+1);
T det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
T delta = tr*tr - TA(4) * det;
T a1 = (tr + gmm::sqrt(delta)) / TA(2);
T a2 = (tr - gmm::sqrt(delta)) / TA(2);
if (gmm::abs(std::imag(a1)) > tol_cplx)
GMM_WARNING1("A complex eigenvalue has been detected : " << a1);
if (gmm::abs(std::imag(a2)) > tol_cplx)
GMM_WARNING1("A complex eigenvalue has been detected : " << a2);
V[i] = std::real(a1); V[i+1] = std::real(a2);
++i;
}
}
}
template <typename TA, typename TV, typename Ttol,
typename MAT, typename VECT>
void extract_eig(const MAT &A, VECT &V, Ttol tol,
std::complex<TA>, std::complex<TV>) {
size_type n = mat_nrows(A);
tol *= Ttol(2);
for (size_type i = 0; i < n; ++i)
if ((i == n-1) ||
gmm::abs(A(i+1,i)) < (gmm::abs(A(i,i))+gmm::abs(A(i+1,i+1)))*tol)
V[i] = std::complex<TV>(A(i,i));
else {
std::complex<TA> tr = A(i,i) + A(i+1, i+1);
std::complex<TA> det = A(i,i)*A(i+1, i+1) - A(i,i+1)*A(i+1, i);
std::complex<TA> delta = tr*tr - TA(4) * det;
V[i] = (tr + gmm::sqrt(delta)) / TA(2);
V[i+1] = (tr - gmm::sqrt(delta)) / TA(2);
++i;
}
}
///@endcond
/**
Compute eigenvalue vector.
*/
template <typename MAT, typename Ttol, typename VECT> inline
void extract_eig(const MAT &A, const VECT &V, Ttol tol) {
extract_eig(A, const_cast<VECT&>(V), tol,
typename linalg_traits<MAT>::value_type(),
typename linalg_traits<VECT>::value_type());
}
/* ********************************************************************* */
/* Stop criterion for QR algorithms */
/* ********************************************************************* */
template <typename MAT, typename Ttol>
void qr_stop_criterion(MAT &A, size_type &p, size_type &q, Ttol tol) {
typedef typename linalg_traits<MAT>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
R rmin = default_min(R()) * R(2);
size_type n = mat_nrows(A);
if (n <= 2) { q = n; p = 0; }
else {
for (size_type i = 1; i < n-q; ++i)
if (gmm::abs(A(i,i-1)) < (gmm::abs(A(i,i))+ gmm::abs(A(i-1,i-1)))*tol
|| gmm::abs(A(i,i-1)) < rmin)
A(i,i-1) = T(0);
while ((q < n-1 && A(n-1-q, n-2-q) == T(0)) ||
(q < n-2 && A(n-2-q, n-3-q) == T(0))) ++q;
if (q >= n-2) q = n;
p = n-q; if (p) --p; if (p) --p;
while (p > 0 && A(p,p-1) != T(0)) --p;
}
}
template <typename MAT, typename Ttol> inline
void symmetric_qr_stop_criterion(const MAT &AA, size_type &p, size_type &q,
Ttol tol) {
typedef typename linalg_traits<MAT>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
R rmin = default_min(R()) * R(2);
MAT& A = const_cast<MAT&>(AA);
size_type n = mat_nrows(A);
if (n <= 1) { q = n; p = 0; }
else {
for (size_type i = 1; i < n-q; ++i)
if (gmm::abs(A(i,i-1)) < (gmm::abs(A(i,i))+ gmm::abs(A(i-1,i-1)))*tol
|| gmm::abs(A(i,i-1)) < rmin)
A(i,i-1) = T(0);
while (q < n-1 && A(n-1-q, n-2-q) == T(0)) ++q;
if (q >= n-1) q = n;
p = n-q; if (p) --p; if (p) --p;
while (p > 0 && A(p,p-1) != T(0)) --p;
}
}
template <typename VECT1, typename VECT2, typename Ttol> inline
void symmetric_qr_stop_criterion(const VECT1 &diag, const VECT2 &sdiag_,
size_type &p, size_type &q, Ttol tol) {
typedef typename linalg_traits<VECT2>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
R rmin = default_min(R()) * R(2);
VECT2 &sdiag = const_cast<VECT2 &>(sdiag_);
size_type n = vect_size(diag);
if (n <= 1) { q = n; p = 0; return; }
for (size_type i = 1; i < n-q; ++i)
if (gmm::abs(sdiag[i-1]) < (gmm::abs(diag[i])+ gmm::abs(diag[i-1]))*tol
|| gmm::abs(sdiag[i-1]) < rmin)
sdiag[i-1] = T(0);
while (q < n-1 && sdiag[n-2-q] == T(0)) ++q;
if (q >= n-1) q = n;
p = n-q; if (p) --p; if (p) --p;
while (p > 0 && sdiag[p-1] != T(0)) --p;
}
/* ********************************************************************* */
/* 2x2 blocks reduction for Schur vectors */
/* ********************************************************************* */
template <typename MATH, typename MATQ, typename Ttol>
void block2x2_reduction(MATH &H, MATQ &Q, Ttol tol) {
typedef typename linalg_traits<MATH>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type n = mat_nrows(H), nq = mat_nrows(Q);
if (n < 2) return;
sub_interval SUBQ(0, nq), SUBL(0, 2);
std::vector<T> v(2), w(std::max(n, nq)); v[0] = T(1);
tol *= Ttol(2);
Ttol tol_i = tol * gmm::abs(H(0,0)), tol_cplx = tol_i;
for (size_type i = 0; i < n-1; ++i) {
tol_i = (gmm::abs(H(i,i))+gmm::abs(H(i+1,i+1)))*tol;
tol_cplx = std::max(tol_cplx, tol_i);
if (gmm::abs(H(i+1,i)) > tol_i) { // 2x2 block detected
T tr = (H(i+1, i+1) - H(i,i)) / T(2);
T delta = tr*tr + H(i,i+1)*H(i+1, i);
if (is_complex(T()) || gmm::real(delta) >= R(0)) {
sub_interval SUBI(i, 2);
T theta = (tr - gmm::sqrt(delta)) / H(i+1,i);
R a = gmm::abs(theta);
v[1] = (a == R(0)) ? T(-1)
: gmm::conj(theta) * (R(1) - gmm::sqrt(a*a + R(1)) / a);
row_house_update(sub_matrix(H, SUBI), v, sub_vector(w, SUBL));
col_house_update(sub_matrix(H, SUBI), v, sub_vector(w, SUBL));
col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
}
++i;
}
}
}
/* ********************************************************************* */
/* Basic qr algorithm. */
/* ********************************************************************* */
#define tol_type_for_qr typename number_traits<typename \
linalg_traits<MAT1>::value_type>::magnitude_type
#define default_tol_for_qr \
(gmm::default_tol(tol_type_for_qr()) * tol_type_for_qr(3))
// QR method for real or complex square matrices based on QR factorisation.
// eigval has to be a complex vector if A has complex eigeinvalues.
// Very slow method. Use implicit_qr_method instead.
template <typename MAT1, typename VECT, typename MAT2>
void rudimentary_qr_algorithm(const MAT1 &A, const VECT &eigval_,
const MAT2 &eigvect_,
tol_type_for_qr tol = default_tol_for_qr,
bool compvect = true) {
VECT &eigval = const_cast<VECT &>(eigval_);
MAT2 &eigvect = const_cast<MAT2 &>(eigvect_);
typedef typename linalg_traits<MAT1>::value_type value_type;
size_type n = mat_nrows(A), p, q = 0, ite = 0;
dense_matrix<value_type> Q(n, n), R(n,n), A1(n,n);
gmm::copy(A, A1);
Hessenberg_reduction(A1, eigvect, compvect);
qr_stop_criterion(A1, p, q, tol);
while (q < n) {
qr_factor(A1, Q, R);
gmm::mult(R, Q, A1);
if (compvect) { gmm::mult(eigvect, Q, R); gmm::copy(R, eigvect); }
qr_stop_criterion(A1, p, q, tol);
++ite;
GMM_ASSERT1(ite < n*1000, "QR algorithm failed");
}
if (compvect) block2x2_reduction(A1, Q, tol);
extract_eig(A1, eigval, tol);
}
template <typename MAT1, typename VECT>
void rudimentary_qr_algorithm(const MAT1 &a, VECT &eigval,
tol_type_for_qr tol = default_tol_for_qr) {
dense_matrix<typename linalg_traits<MAT1>::value_type> m(0,0);
rudimentary_qr_algorithm(a, eigval, m, tol, false);
}
/* ********************************************************************* */
/* Francis QR step. */
/* ********************************************************************* */
template <typename MAT1, typename MAT2>
void Francis_qr_step(const MAT1& HH, const MAT2 &QQ, bool compute_Q) {
MAT1& H = const_cast<MAT1&>(HH); MAT2& Q = const_cast<MAT2&>(QQ);
typedef typename linalg_traits<MAT1>::value_type value_type;
size_type n = mat_nrows(H), nq = mat_nrows(Q);
std::vector<value_type> v(3), w(std::max(n, nq));
value_type s = H(n-2, n-2) + H(n-1, n-1);
value_type t = H(n-2, n-2) * H(n-1, n-1) - H(n-2, n-1) * H(n-1, n-2);
value_type x = H(0, 0) * H(0, 0) + H(0,1) * H(1, 0) - s * H(0,0) + t;
value_type y = H(1, 0) * (H(0,0) + H(1,1) - s);
value_type z = H(1, 0) * H(2, 1);
sub_interval SUBQ(0, nq);
for (size_type k = 0; k < n - 2; ++k) {
v[0] = x; v[1] = y; v[2] = z;
house_vector(v);
size_type r = std::min(k+4, n), q = (k==0) ? 0 : k-1;
sub_interval SUBI(k, 3), SUBJ(0, r), SUBK(q, n-q);
row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBK));
col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
if (compute_Q)
col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
x = H(k+1, k); y = H(k+2, k);
if (k < n-3) z = H(k+3, k);
}
sub_interval SUBI(n-2,2), SUBJ(0, n), SUBK(n-3,3), SUBL(0, 3);
v.resize(2);
v[0] = x; v[1] = y;
house_vector(v);
row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBL));
col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
if (compute_Q)
col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
}
/* ********************************************************************* */
/* Wilkinson Double shift QR step (from Lapack). */
/* ********************************************************************* */
template <typename MAT1, typename MAT2, typename Ttol>
void Wilkinson_double_shift_qr_step(const MAT1& HH, const MAT2 &QQ,
Ttol tol, bool exc, bool compute_Q) {
MAT1& H = const_cast<MAT1&>(HH); MAT2& Q = const_cast<MAT2&>(QQ);
typedef typename linalg_traits<MAT1>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type n = mat_nrows(H), nq = mat_nrows(Q), m;
std::vector<T> v(3), w(std::max(n, nq));
const R dat1(0.75), dat2(-0.4375);
T h33, h44, h43h34, v1(0), v2(0), v3(0);
if (exc) { /* Exceptional shift. */
R s = gmm::abs(H(n-1, n-2)) + gmm::abs(H(n-2, n-3));
h33 = h44 = dat1 * s;
h43h34 = dat2*s*s;
}
else { /* Wilkinson double shift. */
h44 = H(n-1,n-1); h33 = H(n-2, n-2);
h43h34 = H(n-1, n-2) * H(n-2, n-1);
}
/* Look for two consecutive small subdiagonal elements. */
/* Determine the effect of starting the double-shift QR iteration at */
/* row m, and see if this would make H(m-1, m-2) negligible. */
for (m = n-2; m != 0; --m) {
T h11 = H(m-1, m-1), h22 = H(m, m);
T h21 = H(m, m-1), h12 = H(m-1, m);
T h44s = h44 - h11, h33s = h33 - h11;
v1 = (h33s*h44s-h43h34) / h21 + h12;
v2 = h22 - h11 - h33s - h44s;
v3 = H(m+1, m);
R s = gmm::abs(v1) + gmm::abs(v2) + gmm::abs(v3);
v1 /= s; v2 /= s; v3 /= s;
if (m == 1) break;
T h00 = H(m-2, m-2);
T h10 = H(m-1, m-2);
R tst1 = gmm::abs(v1)*(gmm::abs(h00)+gmm::abs(h11)+gmm::abs(h22));
if (gmm::abs(h10)*(gmm::abs(v2)+gmm::abs(v3)) <= tol * tst1) break;
}
/* Double shift QR step. */
sub_interval SUBQ(0, nq);
for (size_type k = (m == 0) ? 0 : m-1; k < n-2; ++k) {
v[0] = v1; v[1] = v2; v[2] = v3;
house_vector(v);
size_type r = std::min(k+4, n), q = (k==0) ? 0 : k-1;
sub_interval SUBI(k, 3), SUBJ(0, r), SUBK(q, n-q);
row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBK));
col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
if (k > m-1) { H(k+1, k-1) = T(0); if (k < n-3) H(k+2, k-1) = T(0); }
if (compute_Q)
col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
v1 = H(k+1, k); v2 = H(k+2, k);
if (k < n-3) v3 = H(k+3, k);
}
sub_interval SUBI(n-2,2), SUBJ(0, n), SUBK(n-3,3), SUBL(0, 3);
v.resize(2); v[0] = v1; v[1] = v2;
house_vector(v);
row_house_update(sub_matrix(H, SUBI, SUBK), v, sub_vector(w, SUBL));
col_house_update(sub_matrix(H, SUBJ, SUBI), v, sub_vector(w, SUBJ));
if (compute_Q)
col_house_update(sub_matrix(Q, SUBQ, SUBI), v, sub_vector(w, SUBQ));
}
/* ********************************************************************* */
/* Implicit QR algorithm. */
/* ********************************************************************* */
// QR method for real or complex square matrices based on an
// implicit QR factorisation. eigval has to be a complex vector
// if A has complex eigenvalues. Complexity about 10n^3, 25n^3 if
// eigenvectors are computed
template <typename MAT1, typename VECT, typename MAT2>
void implicit_qr_algorithm(const MAT1 &A, const VECT &eigval_,
const MAT2 &Q_,
tol_type_for_qr tol = default_tol_for_qr,
bool compvect = true) {
VECT &eigval = const_cast<VECT &>(eigval_);
MAT2 &Q = const_cast<MAT2 &>(Q_);
typedef typename linalg_traits<MAT1>::value_type value_type;
size_type n(mat_nrows(A)), q(0), q_old, p(0), ite(0), its(0);
dense_matrix<value_type> H(n,n);
sub_interval SUBK(0,0);
gmm::copy(A, H);
Hessenberg_reduction(H, Q, compvect);
qr_stop_criterion(H, p, q, tol);
while (q < n) {
sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(Q));
if (compvect) SUBK = SUBI;
// Francis_qr_step(sub_matrix(H, SUBI),
// sub_matrix(Q, SUBJ, SUBK), compvect);
Wilkinson_double_shift_qr_step(sub_matrix(H, SUBI),
sub_matrix(Q, SUBJ, SUBK),
tol, (its == 10 || its == 20), compvect);
q_old = q;
qr_stop_criterion(H, p, q, tol*2);
if (q != q_old) its = 0;
++its; ++ite;
GMM_ASSERT1(ite < n*100, "QR algorithm failed");
}
if (compvect) block2x2_reduction(H, Q, tol);
extract_eig(H, eigval, tol);
}
template <typename MAT1, typename VECT>
void implicit_qr_algorithm(const MAT1 &a, VECT &eigval,
tol_type_for_qr tol = default_tol_for_qr) {
dense_matrix<typename linalg_traits<MAT1>::value_type> m(1,1);
implicit_qr_algorithm(a, eigval, m, tol, false);
}
/* ********************************************************************* */
/* Implicit symmetric QR step with Wilkinson Shift. */
/* ********************************************************************* */
template <typename MAT1, typename MAT2>
void symmetric_Wilkinson_qr_step(const MAT1& MM, const MAT2 &ZZ,
bool compute_z) {
MAT1& M = const_cast<MAT1&>(MM); MAT2& Z = const_cast<MAT2&>(ZZ);
typedef typename linalg_traits<MAT1>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type n = mat_nrows(M);
for (size_type i = 0; i < n; ++i) {
M(i, i) = T(gmm::real(M(i, i)));
if (i > 0) {
T a = (M(i, i-1) + gmm::conj(M(i-1, i)))/R(2);
M(i, i-1) = a; M(i-1, i) = gmm::conj(a);
}
}
R d = gmm::real(M(n-2, n-2) - M(n-1, n-1)) / R(2);
R e = gmm::abs_sqr(M(n-1, n-2));
R nu = d + gmm::sgn(d)*gmm::sqrt(d*d+e);
if (nu == R(0)) { M(n-1, n-2) = T(0); return; }
R mu = gmm::real(M(n-1, n-1)) - e / nu;
T x = M(0,0) - T(mu), z = M(1, 0), c, s;
for (size_type k = 1; k < n; ++k) {
Givens_rotation(x, z, c, s);
if (k > 1) Apply_Givens_rotation_left(M(k-1,k-2), M(k,k-2), c, s);
Apply_Givens_rotation_left(M(k-1,k-1), M(k,k-1), c, s);
Apply_Givens_rotation_left(M(k-1,k ), M(k,k ), c, s);
if (k < n-1) Apply_Givens_rotation_left(M(k-1,k+1), M(k,k+1), c, s);
if (k > 1) Apply_Givens_rotation_right(M(k-2,k-1), M(k-2,k), c, s);
Apply_Givens_rotation_right(M(k-1,k-1), M(k-1,k), c, s);
Apply_Givens_rotation_right(M(k ,k-1), M(k,k) , c, s);
if (k < n-1) Apply_Givens_rotation_right(M(k+1,k-1), M(k+1,k), c, s);
if (compute_z) col_rot(Z, c, s, k-1, k);
if (k < n-1) { x = M(k, k-1); z = M(k+1, k-1); }
}
}
template <typename VECT1, typename VECT2, typename MAT>
void symmetric_Wilkinson_qr_step(const VECT1& diag_, const VECT2& sdiag_,
const MAT &ZZ, bool compute_z) {
VECT1& diag = const_cast<VECT1&>(diag_);
VECT2& sdiag = const_cast<VECT2&>(sdiag_);
MAT& Z = const_cast<MAT&>(ZZ);
typedef typename linalg_traits<VECT2>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type n = vect_size(diag);
R d = (diag[n-2] - diag[n-1]) / R(2);
R e = gmm::abs_sqr(sdiag[n-2]);
R nu = d + gmm::sgn(d)*gmm::sqrt(d*d+e);
if (nu == R(0)) { sdiag[n-2] = T(0); return; }
R mu = diag[n-1] - e / nu;
T x = diag[0] - T(mu), z = sdiag[0], c, s;
T a01(0), a02(0);
T a10(0), a11(diag[0]), a12(gmm::conj(sdiag[0])), a13(0);
T a20(0), a21(sdiag[0]), a22(diag[1]), a23(gmm::conj(sdiag[1]));
T a31(0), a32(sdiag[1]);
for (size_type k = 1; k < n; ++k) {
Givens_rotation(x, z, c, s);
if (k > 1) Apply_Givens_rotation_left(a10, a20, c, s);
Apply_Givens_rotation_left(a11, a21, c, s);
Apply_Givens_rotation_left(a12, a22, c, s);
if (k < n-1) Apply_Givens_rotation_left(a13, a23, c, s);
if (k > 1) Apply_Givens_rotation_right(a01, a02, c, s);
Apply_Givens_rotation_right(a11, a12, c, s);
Apply_Givens_rotation_right(a21, a22, c, s);
if (k < n-1) Apply_Givens_rotation_right(a31, a32, c, s);
if (compute_z) col_rot(Z, c, s, k-1, k);
diag[k-1] = gmm::real(a11);
diag[k] = gmm::real(a22);
if (k > 1) sdiag[k-2] = (gmm::conj(a01) + a10) / R(2);
sdiag[k-1] = (gmm::conj(a12) + a21) / R(2);
x = sdiag[k-1]; z = (gmm::conj(a13) + a31) / R(2);
a01 = a12; a02 = a13;
a10 = a21; a11 = a22; a12 = a23; a13 = T(0);
a20 = a31; a21 = a32; a31 = T(0);
if (k < n-1) {
sdiag[k] = (gmm::conj(a23) + a32) / R(2);
a22 = T(diag[k+1]); a32 = sdiag[k+1]; a23 = gmm::conj(a32);
}
}
}
/* ********************************************************************* */
/* Implicit QR algorithm for symmetric or hermitian matrices. */
/* ********************************************************************* */
// implicit QR method for real square symmetric matrices or complex
// hermitian matrices.
// eigval has to be a complex vector if A has complex eigeinvalues.
// complexity about 4n^3/3, 9n^3 if eigenvectors are computed
template <typename MAT1, typename VECT, typename MAT2>
void symmetric_qr_algorithm_old(const MAT1 &A, const VECT &eigval_,
const MAT2 &eigvect_,
tol_type_for_qr tol = default_tol_for_qr,
bool compvect = true) {
VECT &eigval = const_cast<VECT &>(eigval_);
MAT2 &eigvect = const_cast<MAT2 &>(eigvect_);
typedef typename linalg_traits<MAT1>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
if (compvect) gmm::copy(identity_matrix(), eigvect);
size_type n = mat_nrows(A), q = 0, p, ite = 0;
dense_matrix<T> Tri(n, n);
gmm::copy(A, Tri);
Householder_tridiagonalization(Tri, eigvect, compvect);
symmetric_qr_stop_criterion(Tri, p, q, tol);
while (q < n) {
sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(eigvect)), SUBK(p, n-p-q);
if (!compvect) SUBK = sub_interval(0,0);
symmetric_Wilkinson_qr_step(sub_matrix(Tri, SUBI),
sub_matrix(eigvect, SUBJ, SUBK), compvect);
symmetric_qr_stop_criterion(Tri, p, q, tol*R(2));
++ite;
GMM_ASSERT1(ite < n*100, "QR algorithm failed. Probably, your matrix"
" is not real symmetric or complex hermitian");
}
extract_eig(Tri, eigval, tol);
}
template <typename MAT1, typename VECT, typename MAT2>
void symmetric_qr_algorithm(const MAT1 &A, const VECT &eigval_,
const MAT2 &eigvect_,
tol_type_for_qr tol = default_tol_for_qr,
bool compvect = true) {
VECT &eigval = const_cast<VECT &>(eigval_);
MAT2 &eigvect = const_cast<MAT2 &>(eigvect_);
typedef typename linalg_traits<MAT1>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type n = mat_nrows(A), q = 0, p, ite = 0;
if (compvect) gmm::copy(identity_matrix(), eigvect);
if (n == 0) return;
if (n == 1) { eigval[0]=gmm::real(A(0,0)); return; }
dense_matrix<T> Tri(n, n);
gmm::copy(A, Tri);
Householder_tridiagonalization(Tri, eigvect, compvect);
std::vector<R> diag(n);
std::vector<T> sdiag(n);
for (size_type i = 0; i < n; ++i)
{ diag[i] = gmm::real(Tri(i, i)); if (i+1 < n) sdiag[i] = Tri(i+1, i); }
symmetric_qr_stop_criterion(diag, sdiag, p, q, tol);
while (q < n) {
sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(eigvect)), SUBK(p, n-p-q);
if (!compvect) SUBK = sub_interval(0,0);
symmetric_Wilkinson_qr_step(sub_vector(diag, SUBI),
sub_vector(sdiag, SUBI),
sub_matrix(eigvect, SUBJ, SUBK), compvect);
symmetric_qr_stop_criterion(diag, sdiag, p, q, tol*R(3));
++ite;
GMM_ASSERT1(ite < n*100, "QR algorithm failed.");
}
gmm::copy(diag, eigval);
}
template <typename MAT1, typename VECT>
void symmetric_qr_algorithm(const MAT1 &a, VECT &eigval,
tol_type_for_qr tol = default_tol_for_qr) {
dense_matrix<typename linalg_traits<MAT1>::value_type> m(0,0);
symmetric_qr_algorithm(a, eigval, m, tol, false);
}
}
#endif

174
gmm/gmm_dense_sylvester.h Normal file
View File

@ -0,0 +1,174 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2003-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/** @file gmm_dense_sylvester.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date June 5, 2003.
@brief Sylvester equation solver.
*/
#ifndef GMM_DENSE_SYLVESTER_H
#define GMM_DENSE_SYLVESTER_H
#include "gmm_kernel.h"
namespace gmm {
/* ********************************************************************* */
/* Kronecker system matrix. */
/* ********************************************************************* */
template <typename MAT1, typename MAT2, typename MAT3>
void kron(const MAT1 &m1, const MAT2 &m2, const MAT3 &m3_,
bool init = true) {
MAT3 &m3 = const_cast<MAT3 &>(m3_);
size_type m = mat_nrows(m1), n = mat_ncols(m1);
size_type l = mat_nrows(m2), k = mat_ncols(m2);
GMM_ASSERT2(mat_nrows(m3) == m*l && mat_ncols(m3) == n*k,
"dimensions mismatch");
for (size_type i = 0; i < m; ++i)
for (size_type j = 0; j < m; ++j)
if (init)
gmm::copy(gmm::scaled(m2, m1(i,j)),
gmm::sub_matrix(m3, sub_interval(l*i, l),
sub_interval(k*j, k)));
else
gmm::add(gmm::scaled(m2, m1(i,j)),
gmm::sub_matrix(m3, sub_interval(l*i, l),
sub_interval(k*j, k)));
}
/* ********************************************************************* */
/* Copy a matrix into a vector. */
/* ********************************************************************* */
template <typename MAT, typename VECT>
colmatrix_to_vector(const MAT &A, VECT &v, col_major) {
size_type m = mat_nrows(A), n = mat_ncols(A);
GMM_ASSERT2(m*n == vect_size(v), "dimensions mismatch");
for (size_type i = 0; i < n; ++i)
gmm::copy(mat_col(A, i), sub_vector(v, sub_interval(i*m, m)));
}
template <typename MAT, typename VECT>
colmatrix_to_vector(const MAT &A, VECT &v, row_and_col)
{ colmatrix_to_vector(A, v, col_major()); }
template <typename MAT, typename VECT>
colmatrix_to_vector(const MAT &A, VECT &v, col_and_row)
{ colmatrix_to_vector(A, v, col_major()); }
template <typename MAT, typename VECT>
colmatrix_to_vector(const MAT &A, VECT &v, row_major) {
size_type m = mat_nrows(mat), n = mat_ncols(A);
GMM_ASSERT2(m*n == vect_size(v), "dimensions mismatch");
for (size_type i = 0; i < m; ++i)
gmm::copy(mat_row(A, i), sub_vector(v, sub_slice(i, n, m)));
}
template <typename MAT, typename VECT> inline
colmatrix_to_vector(const MAT &A, const VECT &v_) {
VECT &v = const_cast<VECT &>(v_);
colmatrix_to_vector(A, v, typename linalg_traits<MAT>::sub_orientation());
}
/* ********************************************************************* */
/* Copy a vector into a matrix. */
/* ********************************************************************* */
template <typename MAT, typename VECT>
vector_to_colmatrix(const VECT &v, MAT &A, col_major) {
size_type m = mat_nrows(A), n = mat_ncols(A);
GMM_ASSERT2(m*n == vect_size(v), "dimensions mismatch");
for (size_type i = 0; i < n; ++i)
gmm::copy(sub_vector(v, sub_interval(i*m, m)), mat_col(A, i));
}
template <typename MAT, typename VECT>
vector_to_colmatrix(const VECT &v, MAT &A, row_and_col)
{ vector_to_colmatrix(v, A, col_major()); }
template <typename MAT, typename VECT>
vector_to_colmatrix(const VECT &v, MAT &A, col_and_row)
{ vector_to_colmatrix(v, A, col_major()); }
template <typename MAT, typename VECT>
vector_to_colmatrix(const VECT &v, MAT &A, row_major) {
size_type m = mat_nrows(mat), n = mat_ncols(A);
GMM_ASSERT2(m*n == vect_size(v), "dimensions mismatch");
for (size_type i = 0; i < m; ++i)
gmm::copy(sub_vector(v, sub_slice(i, n, m)), mat_row(A, i));
}
template <typename MAT, typename VECT> inline
vector_to_colmatrix(const VECT &v, const MAT &A_) {
MAT &A = const_cast<MAT &>(A_);
vector_to_colmatrix(v, A, typename linalg_traits<MAT>::sub_orientation());
}
/* ********************************************************************* */
/* Solve sylvester equation. */
/* ********************************************************************* */
// very prohibitive solver, to be replaced ...
template <typename MAT1, typename MAT2, typename MAT3, typename MAT4 >
void sylvester(const MAT1 &m1, const MAT2 &m2, const MAT3 &m3,
const MAT4 &m4_) {
typedef typename linalg_traits<Mat>::value_type T;
MAT3 &m4 = const_cast<MAT4 &>(m4_);
size_type m = mat_nrows(m1), n = mat_ncols(m1);
size_type l = mat_nrows(m2), k = mat_ncols(m2);
GMM_ASSERT2(m == n && l == k && m == mat_nrows(m3) &&
l == mat_ncols(m3) && m == mat_nrows(m4) && l == mat_ncols(m4),
"dimensions mismatch");
gmm::dense_matrix<T> akronb(m*l, m*l);
gmm::dense_matrix<T> idm(m, m), idl(l,l);
gmm::copy(identity_matrix(), idm);
gmm::copy(identity_matrix(), idl);
std::vector<T> x(m*l), c(m*l);
kron(idl, m1, akronb);
kron(gmm::transposed(m2), idm, akronb, false);
colmatrix_to_vector(m3, c);
lu_solve(akronb, c, x);
vector_to_colmatrix(x, m4);
}
}
#endif

165
gmm/gmm_domain_decomp.h Normal file
View File

@ -0,0 +1,165 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2004-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/** @file gmm_domain_decomp.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date May 21, 2004.
@brief Domain decomposition.
*/
#ifndef GMM_DOMAIN_DECOMP_H__
#define GMM_DOMAIN_DECOMP_H__
#include "gmm_kernel.h"
#include <map>
namespace gmm {
/** This function separates into small boxes of size msize with a ratio
* of overlap (in [0,1[) a set of points. The result is given into a
* vector of sparse matrices vB.
*/
template <typename Matrix, typename Point>
void rudimentary_regular_decomposition(std::vector<Point> pts,
double msize,
double overlap,
std::vector<Matrix> &vB) {
typedef typename linalg_traits<Matrix>::value_type value_type;
typedef abstract_null_type void_type;
typedef std::map<size_type, void_type> map_type;
size_type nbpts = pts.size();
if (!nbpts || pts[0].size() == 0) { vB.resize(0); return; }
int dim = int(pts[0].size());
// computation of the global box and the number of sub-domains
Point pmin = pts[0], pmax = pts[0];
for (size_type i = 1; i < nbpts; ++i)
for (int k = 0; k < dim; ++k) {
pmin[k] = std::min(pmin[k], pts[i][k]);
pmax[k] = std::max(pmax[k], pts[i][k]);
}
std::vector<size_type> nbsub(dim), mult(dim);
std::vector<int> pts1(dim), pts2(dim);
size_type nbtotsub = 1;
for (int k = 0; k < dim; ++k) {
nbsub[k] = size_type((pmax[k] - pmin[k]) / msize)+1;
mult[k] = nbtotsub; nbtotsub *= nbsub[k];
}
std::vector<map_type> subs(nbtotsub);
// points ventilation
std::vector<size_type> ns(dim), na(dim), nu(dim);
for (size_type i = 0; i < nbpts; ++i) {
for (int k = 0; k < dim; ++k) {
double a = (pts[i][k] - pmin[k]) / msize;
ns[k] = size_type(a) - 1; na[k] = 0;
pts1[k] = int(a + overlap); pts2[k] = int(ceil(a-1.0-overlap));
}
size_type sum = 0;
do {
bool ok = 1;
for (int k = 0; k < dim; ++k)
if ((ns[k] >= nbsub[k]) || (pts1[k] < int(ns[k]))
|| (pts2[k] > int(ns[k]))) { ok = false; break; }
if (ok) {
size_type ind = ns[0];
for (int k=1; k < dim; ++k) ind += ns[k]*mult[k];
subs[ind][i] = void_type();
}
for (int k = 0; k < dim; ++k) {
if (na[k] < 2) { na[k]++; ns[k]++; ++sum; break; }
na[k] = 0; ns[k] -= 2; sum -= 2;
}
} while (sum);
}
// delete too small domains.
size_type nbmaxinsub = 0;
for (size_type i = 0; i < nbtotsub; ++i)
nbmaxinsub = std::max(nbmaxinsub, subs[i].size());
std::fill(ns.begin(), ns.end(), size_type(0));
for (size_type i = 0; i < nbtotsub; ++i) {
if (subs[i].size() > 0 && subs[i].size() < nbmaxinsub / 10) {
for (int k = 0; k < dim; ++k) nu[k] = ns[k];
size_type nbmax = 0, imax = 0;
for (int l = 0; l < dim; ++l) {
nu[l]--;
for (int m = 0; m < 2; ++m, nu[l]+=2) {
bool ok = true;
for (int k = 0; k < dim && ok; ++k)
if (nu[k] >= nbsub[k]) ok = false;
if (ok) {
size_type ind = ns[0];
for (int k=1; k < dim; ++k) ind += ns[k]*mult[k];
if (subs[ind].size() > nbmax)
{ nbmax = subs[ind].size(); imax = ind; }
}
}
nu[l]--;
}
if (nbmax > subs[i].size()) {
for (map_type::iterator it=subs[i].begin(); it!=subs[i].end(); ++it)
subs[imax][it->first] = void_type();
subs[i].clear();
}
}
for (int k = 0; k < dim; ++k)
{ ns[k]++; if (ns[k] < nbsub[k]) break; ns[k] = 0; }
}
// delete empty domains.
size_type effnb = 0;
for (size_type i = 0; i < nbtotsub; ++i) {
if (subs[i].size() > 0)
{ if (i != effnb) std::swap(subs[i], subs[effnb]); ++effnb; }
}
// build matrices
subs.resize(effnb);
vB.resize(effnb);
for (size_type i = 0; i < effnb; ++i) {
clear(vB[i]); resize(vB[i], nbpts, subs[i].size());
size_type j = 0;
for (map_type::iterator it=subs[i].begin(); it!=subs[i].end(); ++it, ++j)
vB[i](it->first, j) = value_type(1);
}
}
}
#endif

328
gmm/gmm_except.h Normal file
View File

@ -0,0 +1,328 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/** @file gmm_except.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@author Julien Pommier <Julien.Pommier@insa-toulouse.fr>
@date September 01, 2002.
@brief Definition of basic exceptions.
*/
#ifndef GMM_EXCEPT_H__
#define GMM_EXCEPT_H__
#include "gmm_std.h"
//provides external implementation of gmm_exception and logging.
#ifndef EXTERNAL_EXCEPT_
namespace gmm {
/* *********************************************************************** */
/* GetFEM++ generic errors. */
/* *********************************************************************** */
class gmm_error: public std::logic_error {
public:
gmm_error(const std::string& what_arg): std::logic_error (what_arg) {}
};
#ifdef GETFEM_HAVE_PRETTY_FUNCTION
# define GMM_PRETTY_FUNCTION __PRETTY_FUNCTION__
#else
# define GMM_PRETTY_FUNCTION ""
#endif
// Errors : GMM_THROW should not be used on its own.
// GMM_ASSERT1 : Non-maskable errors. Typically for in/ouput and
// when the test do not significantly reduces the performance.
// GMM_ASSERT2 : All tests which are potentially performance
// consuming. Not hidden by default. Hidden when NDEBUG is
// defined.
// GMM_ASSERT3 : For internal checks. Hidden by default. Active
// only when DEBUG_MODE is defined.
// __EXCEPTIONS is defined by gcc, _CPPUNWIND is defined by visual c++
#if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
inline void short_error_throw(const char *file, int line, const char *func,
const char *errormsg) {
std::stringstream msg__;
msg__ << "Error in " << file << ", line " << line << " " << func
<< ": \n" << errormsg << std::ends;
throw gmm::gmm_error(msg__.str());
}
# define GMM_THROW_(type, errormsg) { \
std::stringstream msg__; \
msg__ << "Error in " << __FILE__ << ", line " \
<< __LINE__ << " " << GMM_PRETTY_FUNCTION << ": \n" \
<< errormsg << std::ends; \
throw (type)(msg__.str()); \
}
#else
#ifndef _MSC_VER
# define abort_no_return() ::abort()
#else
// apparently ::abort() on windows is not declared with __declspec(noreturn) so the compiler spits a lot of warnings when abort is used.
# define abort_no_return() { assert("GMM ABORT"==0); throw "GMM ABORT"; }
#endif
inline void short_error_throw(const char *file, int line, const char *func,
const char *errormsg) {
std::stringstream msg__;
msg__ << "Error in " << file << ", line " << line << " " << func
<< ": \n" << errormsg << std::ends;
std::cerr << msg__.str() << std::endl;
abort_no_return();
}
# define GMM_THROW_(type, errormsg) { \
std::stringstream msg__; \
msg__ << "Error in " << __FILE__ << ", line " \
<< __LINE__ << " " << GMM_PRETTY_FUNCTION << ": \n" \
<< errormsg; \
std::cerr << msg__.str() << std::endl; \
abort_no_return(); \
}
#endif
# define GMM_ASSERT1(test, errormsg) \
{ if (!(test)) GMM_THROW_(gmm::gmm_error, errormsg); }
inline void GMM_THROW() {}
#define GMM_THROW(a, b) { GMM_THROW_(a,b); gmm::GMM_THROW(); }
#if defined(NDEBUG)
# define GMM_ASSERT2(test, errormsg) {}
# define GMM_ASSERT3(test, errormsg) {}
#elif !defined(GMM_FULL_NDEBUG)
# define GMM_ASSERT2(test, errormsg) \
{ if (!(test)) GMM_THROW_(gmm::gmm_error, errormsg); }
# define GMM_ASSERT3(test, errormsg) \
{ if (!(test)) GMM_THROW_(gmm::gmm_error, errormsg); }
#else
# define GMM_ASSERT2(test, errormsg) \
{ if (!(test)) GMM_THROW_(gmm::gmm_error, errormsg); }
# define GMM_ASSERT3(test, errormsg)
#endif
/* *********************************************************************** */
/* GetFEM++ warnings. */
/* *********************************************************************** */
// This allows to dynamically hide warnings
struct warning_level {
static int level(int l = -2)
{ static int level_ = 3; return (l != -2) ? (level_ = l) : level_; }
};
inline void set_warning_level(int l) { warning_level::level(std::max(0,l)); }
inline int get_warning_level(void) { return warning_level::level(-2); }
// This allows not to compile some Warnings
#ifndef GMM_WARNING_LEVEL
# define GMM_WARNING_LEVEL 4
#endif
// Warning levels : 0 always printed
// 1 very important : specify a possible error in the code.
// 2 important : specify a default of optimization for inst.
// 3 remark
// 4 ignored by default.
#define GMM_WARNING_MSG(level_, thestr) { \
std::stringstream msg__; \
msg__ << "Level " << level_ << " Warning in " << __FILE__ << ", line " \
<< __LINE__ << ": " << thestr; \
std::cerr << msg__.str() << std::endl; \
}
#define GMM_WARNING0(thestr) GMM_WARNING_MSG(0, thestr)
#if GMM_WARNING_LEVEL > 0
# define GMM_WARNING1(thestr) \
{ if (1 <= gmm::warning_level::level()) GMM_WARNING_MSG(1, thestr) }
#else
# define GMM_WARNING1(thestr) {}
#endif
#if GMM_WARNING_LEVEL > 1
# define GMM_WARNING2(thestr) \
{ if (2 <= gmm::warning_level::level()) GMM_WARNING_MSG(2, thestr) }
#else
# define GMM_WARNING2(thestr) {}
#endif
#if GMM_WARNING_LEVEL > 2
# define GMM_WARNING3(thestr) \
{ if (3 <= gmm::warning_level::level()) GMM_WARNING_MSG(3, thestr) }
#else
# define GMM_WARNING3(thestr) {}
#endif
#if GMM_WARNING_LEVEL > 3
# define GMM_WARNING4(thestr) \
{ if (4 <= gmm::warning_level::level()) GMM_WARNING_MSG(4, thestr) }
#else
# define GMM_WARNING4(thestr) {}
#endif
/* *********************************************************************** */
/* GetFEM++ traces. */
/* *********************************************************************** */
// This allows to dynamically hide traces
struct traces_level {
static int level(int l = -2)
{ static int level_ = 3; return (l != -2) ? (level_ = l) : level_; }
};
inline void set_traces_level(int l) { traces_level::level(std::max(0,l)); }
// This allow not too compile some Warnings
#ifndef GMM_TRACES_LEVEL
# define GMM_TRACES_LEVEL 4
#endif
// Traces levels : 0 always printed
// 1 Susceptible to occur once in a program.
// 2 Susceptible to occur occasionnaly in a program (10).
// 3 Susceptible to occur often (100).
// 4 Susceptible to occur very often (>1000).
#define GMM_TRACE_MSG_MPI // for Parallelized version
#define GMM_TRACE_MSG(level_, thestr) { \
GMM_TRACE_MSG_MPI { \
std::stringstream msg__; \
msg__ << "Trace " << level_ << " in " << __FILE__ << ", line " \
<< __LINE__ << ": " << thestr; \
std::cout << msg__.str() << std::endl; \
} \
}
#define GMM_TRACE0(thestr) GMM_TRACE_MSG(0, thestr)
#if GMM_TRACES_LEVEL > 0
# define GMM_TRACE1(thestr) \
{ if (1 <= gmm::traces_level::level()) GMM_TRACE_MSG(1, thestr) }
#else
# define GMM_TRACE1(thestr) {}
#endif
#if GMM_TRACES_LEVEL > 1
# define GMM_TRACE2(thestr) \
{ if (2 <= gmm::traces_level::level()) GMM_TRACE_MSG(2, thestr) }
#else
# define GMM_TRACE2(thestr) {}
#endif
#if GMM_TRACES_LEVEL > 2
# define GMM_TRACE3(thestr) \
{ if (3 <= gmm::traces_level::level()) GMM_TRACE_MSG(3, thestr) }
#else
# define GMM_TRACE3(thestr) {}
#endif
#if GMM_TRACES_LEVEL > 3
# define GMM_TRACE4(thestr) \
{ if (4 <= gmm::traces_level::level()) GMM_TRACE_MSG(4, thestr) }
#else
# define GMM_TRACE4(thestr) {}
#endif
/* ********************************************************************* */
/* Definitions for compatibility with old versions. */
/* ********************************************************************* */
#define GMM_STANDARD_CATCH_ERROR catch(std::logic_error e) \
{ \
std::cerr << "============================================\n"; \
std::cerr << "| An error has been detected !!! |\n"; \
std::cerr << "============================================\n"; \
std::cerr << e.what() << std::endl << std::endl; \
exit(1); \
} \
catch(const std::runtime_error &e) \
{ \
std::cerr << "============================================\n"; \
std::cerr << "| An error has been detected !!! |\n"; \
std::cerr << "============================================\n"; \
std::cerr << e.what() << std::endl << std::endl; \
exit(1); \
} \
catch(const std::bad_alloc &) { \
std::cerr << "============================================\n"; \
std::cerr << "| A bad allocation has been detected !!! |\n"; \
std::cerr << "============================================\n"; \
exit(1); \
} \
catch(const std::bad_typeid &) { \
std::cerr << "============================================\n"; \
std::cerr << "| A bad typeid has been detected !!! |\n"; \
std::cerr << "============================================\n"; \
exit(1); \
} \
catch(const std::bad_exception &) { \
std::cerr << "============================================\n"; \
std::cerr << "| A bad exception has been detected !!! |\n"; \
std::cerr << "============================================\n"; \
exit(1); \
} \
catch(const std::bad_cast &) { \
std::cerr << "============================================\n"; \
std::cerr << "| A bad cast has been detected !!! |\n"; \
std::cerr << "============================================\n"; \
exit(1); \
} \
catch(...) { \
std::cerr << "============================================\n"; \
std::cerr << "| An unknown error has been detected !!! |\n"; \
std::cerr << "============================================\n"; \
exit(1); \
}
// catch(ios_base::failure) {
// std::cerr << "============================================\n";
// std::cerr << "| A ios_base::failure has been detected !!!|\n";
// std::cerr << "============================================\n";
// exit(1);
// }
#if defined(__GNUC__) && (__GNUC__ > 3)
# define GMM_SET_EXCEPTION_DEBUG \
std::set_terminate(__gnu_cxx::__verbose_terminate_handler);
#else
# define GMM_SET_EXCEPTION_DEBUG
#endif
}
#else
#include <external_except.h>
#endif /* EXTERNAL_EXCEPT_*/
#endif /* GMM_EXCEPT_H__ */

1176
gmm/gmm_inoutput.h Normal file

File diff suppressed because it is too large Load Diff

1068
gmm/gmm_interface.h Normal file

File diff suppressed because it is too large Load Diff

83
gmm/gmm_interface_bgeot.h Normal file
View File

@ -0,0 +1,83 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_interface_bgeot.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date October 13, 2002.
@brief interface for bgeot::small_vector
*/
#ifndef GMM_INTERFACE_BGEOT_H__
#define GMM_INTERFACE_BGEOT_H__
namespace gmm {
/* ********************************************************************* */
/* */
/* Traits for bgeot objects */
/* */
/* ********************************************************************* */
template <typename T> struct linalg_traits<bgeot::small_vector<T> > {
typedef bgeot::small_vector<T> this_type;
typedef this_type origin_type;
typedef linalg_false is_reference;
typedef abstract_vector linalg_type;
typedef T value_type;
typedef T& reference;
typedef typename this_type::iterator iterator;
typedef typename this_type::const_iterator const_iterator;
typedef abstract_dense storage_type;
typedef linalg_true index_sorted;
static size_type size(const this_type &v) { return v.size(); }
static iterator begin(this_type &v) { return v.begin(); }
static const_iterator begin(const this_type &v) { return v.begin(); }
static iterator end(this_type &v) { return v.end(); }
static const_iterator end(const this_type &v) { return v.end(); }
static origin_type* origin(this_type &v) { return &v; }
static const origin_type* origin(const this_type &v) { return &v; }
static void clear(origin_type* o, const iterator &it, const iterator &ite)
{ std::fill(it, ite, value_type(0)); }
static void do_clear(this_type &v)
{ std::fill(v.begin(), v.end(), value_type(0)); }
static value_type access(const origin_type *, const const_iterator &it,
const const_iterator &, size_type i)
{ return it[i]; }
static reference access(origin_type *, const iterator &it,
const iterator &, size_type i)
{ return it[i]; }
static void resize(this_type &v, size_type n) { v.resize(n); }
};
}
#endif // GMM_INTERFACE_BGEOT_H__

162
gmm/gmm_iter.h Normal file
View File

@ -0,0 +1,162 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_iter.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date February 10, 2003.
@brief Iteration object.
*/
#ifndef GMM_ITER_H__
#define GMM_ITER_H__
#include "gmm_kernel.h"
#include <iomanip>
namespace gmm {
/** The Iteration object calculates whether the solution has reached the
desired accuracy, or whether the maximum number of iterations has
been reached.
The method finished() checks the convergence. The first()
method is used to determine the first iteration of the loop.
*/
class iteration {
protected :
double rhsn; /* Right hand side norm. */
size_type maxiter; /* Max. number of iterations. */
int noise; /* if noise > 0 iterations are printed. */
double resmax; /* maximum residu. */
double resminreach, resadd;
double diverged_res; /* Threshold beyond which the iterative */
/* is considered to diverge. */
size_type nit; /* iteration number. */
double res; /* last computed residu. */
std::string name; /* eventually, name of the method. */
bool written;
void (*callback)(const gmm::iteration&);
public :
void init(void) {
nit = 0; res = 0.0; written = false;
resminreach = 1E200; resadd = 0.0;
callback = 0;
}
iteration(double r = 1.0E-8, int noi = 0, size_type mit = size_type(-1),
double div_res = 1E200)
: rhsn(1.0), maxiter(mit), noise(noi), resmax(r), diverged_res(div_res)
{ init(); }
void operator ++(int) { nit++; written = false; resadd += res; }
void operator ++() { (*this)++; }
bool first(void) { return nit == 0; }
/* get/set the "noisyness" (verbosity) of the solvers */
int get_noisy(void) const { return noise; }
void set_noisy(int n) { noise = n; }
void reduce_noisy(void) { if (noise > 0) noise--; }
double get_resmax(void) const { return resmax; }
void set_resmax(double r) { resmax = r; }
double get_res() const { return res; }
void enforce_converged(bool c = true)
{ if (c) res = double(0); else res = rhsn * resmax + double(1); }
/* change the user-definable callback, called after each iteration */
void set_callback(void (*t)(const gmm::iteration&)) {
callback = t;
}
double get_diverged_residual(void) const { return diverged_res; }
void set_diverged_residual(double r) { diverged_res = r; }
size_type get_iteration(void) const { return nit; }
void set_iteration(size_type i) { nit = i; }
size_type get_maxiter(void) const { return maxiter; }
void set_maxiter(size_type i) { maxiter = i; }
double get_rhsnorm(void) const { return rhsn; }
void set_rhsnorm(double r) { rhsn = r; }
bool converged(void) {
return !isnan(res) && res <= rhsn * resmax;
}
bool converged(double nr) {
res = gmm::abs(nr);
resminreach = std::min(resminreach, res);
return converged();
}
template <typename VECT> bool converged(const VECT &v)
{ return converged(gmm::vect_norm2(v)); }
bool diverged(void) {
return isnan(res) || (nit>=maxiter)
|| (res>=rhsn*diverged_res && nit > 4);
}
bool diverged(double nr) {
res = gmm::abs(nr);
resminreach = std::min(resminreach, res);
return diverged();
}
bool finished(double nr) {
if (callback) callback(*this);
if (noise > 0 && !written) {
double a = (rhsn == 0) ? 1.0 : rhsn;
converged(nr);
cout << name << " iter " << std::setw(3) << nit << " residual "
<< std::setw(12) << gmm::abs(nr) / a;
// if (nit % 100 == 0 && nit > 0) {
// cout << " (residual min " << resminreach / a << " mean val "
// << resadd / (100.0 * a) << " )";
// resadd = 0.0;
// }
cout << endl;
written = true;
}
return (converged(nr) || diverged(nr));
}
template <typename VECT> bool finished_vect(const VECT &v)
{ return finished(double(gmm::vect_norm2(v))); }
void set_name(const std::string &n) { name = n; }
const std::string &get_name(void) const { return name; }
};
}
#endif /* GMM_ITER_H__ */

111
gmm/gmm_iter_solvers.h Normal file
View File

@ -0,0 +1,111 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_iter_solvers.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date October 13, 2002.
@brief Include standard gmm iterative solvers (cg, gmres, ...)
*/
#ifndef GMM_ITER_SOLVERS_H__
#define GMM_ITER_SOLVERS_H__
#include "gmm_iter.h"
namespace gmm {
/** mixed method to find a zero of a real function G, a priori
* between a and b. If the zero is not between a and b, iterations
* of secant are applied. When a convenient interval is found,
* iterations of dichotomie and regula falsi are applied.
*/
template <typename FUNC, typename T>
T find_root(const FUNC &G, T a = T(0), T b = T(1),
T tol = gmm::default_tol(T())) {
T c, Ga = G(a), Gb = G(b), Gc, d;
d = gmm::abs(b - a);
#if 0
for (int i = 0; i < 4; i++) { /* secant iterations. */
if (d < tol) return (b + a) / 2.0;
c = b - Gb * (b - a) / (Gb - Ga); Gc = G(c);
a = b; b = c; Ga = Gb; Gb = Gc;
d = gmm::abs(b - a);
}
#endif
while (Ga * Gb > 0.0) { /* secant iterations. */
if (d < tol) return (b + a) / 2.0;
c = b - Gb * (b - a) / (Gb - Ga); Gc = G(c);
a = b; b = c; Ga = Gb; Gb = Gc;
d = gmm::abs(b - a);
}
c = std::max(a, b); a = std::min(a, b); b = c;
while (d > tol) {
c = b - (b - a) * (Gb / (Gb - Ga)); /* regula falsi. */
if (c > b) c = b;
if (c < a) c = a;
Gc = G(c);
if (Gc*Gb > 0) { b = c; Gb = Gc; } else { a = c; Ga = Gc; }
c = (b + a) / 2.0 ; Gc = G(c); /* Dichotomie. */
if (Gc*Gb > 0) { b = c; Gb = Gc; } else { a = c; Ga = Gc; }
d = gmm::abs(b - a); c = (b + a) / 2.0; if ((c == a) || (c == b)) d = 0.0;
}
return (b + a) / 2.0;
}
}
#include "gmm_precond_diagonal.h"
#include "gmm_precond_ildlt.h"
#include "gmm_precond_ildltt.h"
#include "gmm_precond_mr_approx_inverse.h"
#include "gmm_precond_ilu.h"
#include "gmm_precond_ilut.h"
#include "gmm_precond_ilutp.h"
#include "gmm_solver_cg.h"
#include "gmm_solver_bicgstab.h"
#include "gmm_solver_qmr.h"
#include "gmm_solver_constrained_cg.h"
#include "gmm_solver_Schwarz_additive.h"
#include "gmm_modified_gram_schmidt.h"
#include "gmm_tri_solve.h"
#include "gmm_solver_gmres.h"
#include "gmm_solver_bfgs.h"
#include "gmm_least_squares_cg.h"
// #include "gmm_solver_idgmres.h"
#endif // GMM_ITER_SOLVERS_H__

55
gmm/gmm_kernel.h Normal file
View File

@ -0,0 +1,55 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_kernel.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date November 15, 2003.
@brief Include the base gmm files.
*/
#ifndef GMM_KERNEL_H__
#define GMM_KERNEL_H__
#include "gmm_def.h"
#include "gmm_blas.h"
#include "gmm_real_part.h"
#include "gmm_interface.h"
#include "gmm_sub_vector.h"
#include "gmm_sub_matrix.h"
#include "gmm_vector_to_matrix.h"
#include "gmm_vector.h"
#include "gmm_matrix.h"
#include "gmm_tri_solve.h"
#include "gmm_blas_interface.h"
#include "gmm_lapack_interface.h"
#endif // GMM_KERNEL_H__

470
gmm/gmm_lapack_interface.h Normal file
View File

@ -0,0 +1,470 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2003-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_lapack_interface.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date October 7, 2003.
@brief gmm interface for LAPACK
*/
#ifndef GMM_LAPACK_INTERFACE_H
#define GMM_LAPACK_INTERFACE_H
#include "gmm_blas_interface.h"
#include "gmm_dense_lu.h"
#include "gmm_dense_qr.h"
#if defined(GMM_USES_LAPACK)
namespace gmm {
/* ********************************************************************* */
/* Operations interfaced for T = float, double, std::complex<float> */
/* or std::complex<double> : */
/* */
/* lu_factor(dense_matrix<T>, std::vector<int>) */
/* lu_solve(dense_matrix<T>, std::vector<T>, std::vector<T>) */
/* lu_solve(dense_matrix<T>, std::vector<int>, std::vector<T>, */
/* std::vector<T>) */
/* lu_solve_transposed(dense_matrix<T>, std::vector<int>, std::vector<T>,*/
/* std::vector<T>) */
/* lu_inverse(dense_matrix<T>) */
/* lu_inverse(dense_matrix<T>, std::vector<int>, dense_matrix<T>) */
/* */
/* qr_factor(dense_matrix<T>, dense_matrix<T>, dense_matrix<T>) */
/* */
/* implicit_qr_algorithm(dense_matrix<T>, std::vector<T>) */
/* implicit_qr_algorithm(dense_matrix<T>, std::vector<T>, */
/* dense_matrix<T>) */
/* implicit_qr_algorithm(dense_matrix<T>, std::vector<std::complex<T> >) */
/* implicit_qr_algorithm(dense_matrix<T>, std::vector<std::complex<T> >, */
/* dense_matrix<T>) */
/* */
/* geev_interface_right */
/* geev_interface_left */
/* */
/* schur(dense_matrix<T>, dense_matrix<T>, dense_matrix<T>) */
/* */
/* svd(dense_matrix<T>, dense_matrix<T>, dense_matrix<T>, std::vector<T>)*/
/* svd(dense_matrix<T>, dense_matrix<T>, dense_matrix<T>, */
/* std::vector<std::complex<T> >) */
/* */
/* ********************************************************************* */
/* ********************************************************************* */
/* LAPACK functions used. */
/* ********************************************************************* */
extern "C" {
void sgetrf_(...); void dgetrf_(...); void cgetrf_(...); void zgetrf_(...);
void sgetrs_(...); void dgetrs_(...); void cgetrs_(...); void zgetrs_(...);
void sgetri_(...); void dgetri_(...); void cgetri_(...); void zgetri_(...);
void sgeqrf_(...); void dgeqrf_(...); void cgeqrf_(...); void zgeqrf_(...);
void sorgqr_(...); void dorgqr_(...); void cungqr_(...); void zungqr_(...);
void sormqr_(...); void dormqr_(...); void cunmqr_(...); void zunmqr_(...);
void sgees_ (...); void dgees_ (...); void cgees_ (...); void zgees_ (...);
void sgeev_ (...); void dgeev_ (...); void cgeev_ (...); void zgeev_ (...);
void sgeesx_(...); void dgeesx_(...); void cgeesx_(...); void zgeesx_(...);
void sgesvd_(...); void dgesvd_(...); void cgesvd_(...); void zgesvd_(...);
}
/* ********************************************************************* */
/* LU decomposition. */
/* ********************************************************************* */
# define getrf_interface(lapack_name, base_type) inline \
size_type lu_factor(dense_matrix<base_type > &A, std::vector<int> &ipvt){\
GMMLAPACK_TRACE("getrf_interface"); \
int m = int(mat_nrows(A)), n = int(mat_ncols(A)), lda(m), info(0); \
if (m && n) lapack_name(&m, &n, &A(0,0), &lda, &ipvt[0], &info); \
return size_type(info); \
}
getrf_interface(sgetrf_, BLAS_S)
getrf_interface(dgetrf_, BLAS_D)
getrf_interface(cgetrf_, BLAS_C)
getrf_interface(zgetrf_, BLAS_Z)
/* ********************************************************************* */
/* LU solve. */
/* ********************************************************************* */
# define getrs_interface(f_name, trans1, lapack_name, base_type) inline \
void f_name(const dense_matrix<base_type > &A, \
const std::vector<int> &ipvt, std::vector<base_type > &x, \
const std::vector<base_type > &b) { \
GMMLAPACK_TRACE("getrs_interface"); \
int n = int(mat_nrows(A)), info, nrhs(1); \
gmm::copy(b, x); trans1; \
if (n) \
lapack_name(&t, &n, &nrhs, &(A(0,0)),&n,&ipvt[0], &x[0], &n, &info); \
}
# define getrs_trans_n const char t = 'N'
# define getrs_trans_t const char t = 'T'
getrs_interface(lu_solve, getrs_trans_n, sgetrs_, BLAS_S)
getrs_interface(lu_solve, getrs_trans_n, dgetrs_, BLAS_D)
getrs_interface(lu_solve, getrs_trans_n, cgetrs_, BLAS_C)
getrs_interface(lu_solve, getrs_trans_n, zgetrs_, BLAS_Z)
getrs_interface(lu_solve_transposed, getrs_trans_t, sgetrs_, BLAS_S)
getrs_interface(lu_solve_transposed, getrs_trans_t, dgetrs_, BLAS_D)
getrs_interface(lu_solve_transposed, getrs_trans_t, cgetrs_, BLAS_C)
getrs_interface(lu_solve_transposed, getrs_trans_t, zgetrs_, BLAS_Z)
/* ********************************************************************* */
/* LU inverse. */
/* ********************************************************************* */
# define getri_interface(lapack_name, base_type) inline \
void lu_inverse(const dense_matrix<base_type > &LU, \
std::vector<int> &ipvt, const dense_matrix<base_type > &A_) { \
GMMLAPACK_TRACE("getri_interface"); \
dense_matrix<base_type> &A \
= const_cast<dense_matrix<base_type > &>(A_); \
int n = int(mat_nrows(A)), info, lwork(10000); base_type work[10000]; \
if (n) { \
std::copy(LU.begin(), LU.end(), A.begin()); \
lapack_name(&n, &A(0,0), &n, &ipvt[0], &work[0], &lwork, &info); \
} \
}
getri_interface(sgetri_, BLAS_S)
getri_interface(dgetri_, BLAS_D)
getri_interface(cgetri_, BLAS_C)
getri_interface(zgetri_, BLAS_Z)
/* ********************************************************************* */
/* QR factorization. */
/* ********************************************************************* */
# define geqrf_interface(lapack_name1, base_type) inline \
void qr_factor(dense_matrix<base_type > &A){ \
GMMLAPACK_TRACE("geqrf_interface"); \
int m = int(mat_nrows(A)), n = int(mat_ncols(A)), info, lwork(-1); \
base_type work1; \
if (m && n) { \
std::vector<base_type > tau(n); \
lapack_name1(&m, &n, &A(0,0), &m, &tau[0], &work1 , &lwork, &info); \
lwork = int(gmm::real(work1)); \
std::vector<base_type > work(lwork); \
lapack_name1(&m, &n, &A(0,0), &m, &tau[0], &work[0], &lwork, &info); \
GMM_ASSERT1(!info, "QR factorization failed"); \
} \
}
geqrf_interface(sgeqrf_, BLAS_S)
geqrf_interface(dgeqrf_, BLAS_D)
// For complex values, housholder vectors are not the same as in
// gmm::lu_factor. Impossible to interface for the moment.
// geqrf_interface(cgeqrf_, BLAS_C)
// geqrf_interface(zgeqrf_, BLAS_Z)
# define geqrf_interface2(lapack_name1, lapack_name2, base_type) inline \
void qr_factor(const dense_matrix<base_type > &A, \
dense_matrix<base_type > &Q, dense_matrix<base_type > &R) { \
GMMLAPACK_TRACE("geqrf_interface2"); \
int m = int(mat_nrows(A)), n = int(mat_ncols(A)), info, lwork(-1); \
base_type work1; \
if (m && n) { \
std::copy(A.begin(), A.end(), Q.begin()); \
std::vector<base_type > tau(n); \
lapack_name1(&m, &n, &Q(0,0), &m, &tau[0], &work1 , &lwork, &info); \
lwork = int(gmm::real(work1)); \
std::vector<base_type > work(lwork); \
lapack_name1(&m, &n, &Q(0,0), &m, &tau[0], &work[0], &lwork, &info); \
GMM_ASSERT1(!info, "QR factorization failed"); \
base_type *p = &R(0,0), *q = &Q(0,0); \
for (int j = 0; j < n; ++j, q += m-n) \
for (int i = 0; i < n; ++i, ++p, ++q) \
*p = (j < i) ? base_type(0) : *q; \
lapack_name2(&m, &n, &n, &Q(0,0), &m,&tau[0],&work[0],&lwork,&info); \
} \
else gmm::clear(Q); \
}
geqrf_interface2(sgeqrf_, sorgqr_, BLAS_S)
geqrf_interface2(dgeqrf_, dorgqr_, BLAS_D)
geqrf_interface2(cgeqrf_, cungqr_, BLAS_C)
geqrf_interface2(zgeqrf_, zungqr_, BLAS_Z)
/* ********************************************************************* */
/* QR algorithm for eigenvalues search. */
/* ********************************************************************* */
# define gees_interface(lapack_name, base_type) \
template <typename VECT> inline void implicit_qr_algorithm( \
const dense_matrix<base_type > &A, const VECT &eigval_, \
dense_matrix<base_type > &Q, \
double tol=gmm::default_tol(base_type()), bool compvect = true) { \
GMMLAPACK_TRACE("gees_interface"); \
typedef bool (*L_fp)(...); L_fp p = 0; \
int n = int(mat_nrows(A)), info, lwork(-1), sdim; base_type work1; \
if (!n) return; \
dense_matrix<base_type > H(n,n); gmm::copy(A, H); \
char jobvs = (compvect ? 'V' : 'N'), sort = 'N'; \
std::vector<double> rwork(n), eigv1(n), eigv2(n); \
lapack_name(&jobvs, &sort, p, &n, &H(0,0), &n, &sdim, &eigv1[0], \
&eigv2[0], &Q(0,0), &n, &work1, &lwork, &rwork[0], &info); \
lwork = int(gmm::real(work1)); \
std::vector<base_type > work(lwork); \
lapack_name(&jobvs, &sort, p, &n, &H(0,0), &n, &sdim, &eigv1[0], \
&eigv2[0], &Q(0,0), &n, &work[0], &lwork, &rwork[0],&info);\
GMM_ASSERT1(!info, "QR algorithm failed"); \
extract_eig(H, const_cast<VECT &>(eigval_), tol); \
}
# define gees_interface2(lapack_name, base_type) \
template <typename VECT> inline void implicit_qr_algorithm( \
const dense_matrix<base_type > &A, const VECT &eigval_, \
dense_matrix<base_type > &Q, \
double tol=gmm::default_tol(base_type()), bool compvect = true) { \
GMMLAPACK_TRACE("gees_interface2"); \
typedef bool (*L_fp)(...); L_fp p = 0; \
int n = int(mat_nrows(A)), info, lwork(-1), sdim; base_type work1; \
if (!n) return; \
dense_matrix<base_type > H(n,n); gmm::copy(A, H); \
char jobvs = (compvect ? 'V' : 'N'), sort = 'N'; \
std::vector<double> rwork(n), eigvv(n*2); \
lapack_name(&jobvs, &sort, p, &n, &H(0,0), &n, &sdim, &eigvv[0], \
&Q(0,0), &n, &work1, &lwork, &rwork[0], &rwork[0], &info); \
lwork = int(gmm::real(work1)); \
std::vector<base_type > work(lwork); \
lapack_name(&jobvs, &sort, p, &n, &H(0,0), &n, &sdim, &eigvv[0], \
&Q(0,0), &n, &work[0], &lwork, &rwork[0], &rwork[0],&info);\
GMM_ASSERT1(!info, "QR algorithm failed"); \
extract_eig(H, const_cast<VECT &>(eigval_), tol); \
}
gees_interface(sgees_, BLAS_S)
gees_interface(dgees_, BLAS_D)
gees_interface2(cgees_, BLAS_C)
gees_interface2(zgees_, BLAS_Z)
# define jobv_right char jobvl = 'N', jobvr = 'V';
# define jobv_left char jobvl = 'V', jobvr = 'N';
# define geev_interface(lapack_name, base_type, side) \
template <typename VECT> inline void geev_interface_ ## side( \
const dense_matrix<base_type > &A, const VECT &eigval_, \
dense_matrix<base_type > &Q) { \
GMMLAPACK_TRACE("geev_interface"); \
int n = int(mat_nrows(A)), info, lwork(-1); base_type work1; \
if (!n) return; \
dense_matrix<base_type > H(n,n); gmm::copy(A, H); \
jobv_ ## side \
std::vector<base_type > eigvr(n), eigvi(n); \
lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigvr[0], &eigvi[0], \
&Q(0,0), &n, &Q(0,0), &n, &work1, &lwork, &info); \
lwork = int(gmm::real(work1)); \
std::vector<base_type > work(lwork); \
lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigvr[0], &eigvi[0], \
&Q(0,0), &n, &Q(0,0), &n, &work[0], &lwork, &info); \
GMM_ASSERT1(!info, "QR algorithm failed"); \
gmm::copy(eigvr, gmm::real_part(const_cast<VECT &>(eigval_))); \
gmm::copy(eigvi, gmm::imag_part(const_cast<VECT &>(eigval_))); \
}
# define geev_interface2(lapack_name, base_type, side) \
template <typename VECT> inline void geev_interface_ ## side( \
const dense_matrix<base_type > &A, const VECT &eigval_, \
dense_matrix<base_type > &Q) { \
GMMLAPACK_TRACE("geev_interface"); \
int n = int(mat_nrows(A)), info, lwork(-1); base_type work1; \
if (!n) return; \
dense_matrix<base_type > H(n,n); gmm::copy(A, H); \
jobv_ ## side \
std::vector<base_type::value_type> rwork(2*n); \
std::vector<base_type> eigv(n); \
lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigv[0], &Q(0,0), &n, \
&Q(0,0), &n, &work1, &lwork, &rwork[0], &info); \
lwork = int(gmm::real(work1)); \
std::vector<base_type > work(lwork); \
lapack_name(&jobvl, &jobvr, &n, &H(0,0), &n, &eigv[0], &Q(0,0), &n, \
&Q(0,0), &n, &work[0], &lwork, &rwork[0], &info); \
GMM_ASSERT1(!info, "QR algorithm failed"); \
gmm::copy(eigv, const_cast<VECT &>(eigval_)); \
}
geev_interface(sgeev_, BLAS_S, right)
geev_interface(dgeev_, BLAS_D, right)
geev_interface2(cgeev_, BLAS_C, right)
geev_interface2(zgeev_, BLAS_Z, right)
geev_interface(sgeev_, BLAS_S, left)
geev_interface(dgeev_, BLAS_D, left)
geev_interface2(cgeev_, BLAS_C, left)
geev_interface2(zgeev_, BLAS_Z, left)
/* ********************************************************************* */
/* SCHUR algorithm: */
/* A = Q*S*(Q^T), with Q orthogonal and S upper quasi-triangula */
/* ********************************************************************* */
# define geesx_interface(lapack_name, base_type) inline \
void schur(dense_matrix<base_type> &A, \
dense_matrix<base_type> &S, \
dense_matrix<base_type> &Q) { \
GMMLAPACK_TRACE("geesx_interface"); \
int m = int(mat_nrows(A)), n = int(mat_ncols(A)); \
GMM_ASSERT1(m == n, "Schur decomposition requires square matrix"); \
char jobvs = 'V', sort = 'N', sense = 'N'; \
bool select = false; \
int lwork = 8*n, sdim = 0, liwork = 1; \
std::vector<base_type> work(lwork), wr(n), wi(n); \
std::vector<int> iwork(liwork); \
std::vector<int> bwork(1); \
resize(S, n, n); copy(A, S); \
resize(Q, n, n); \
base_type rconde(0), rcondv(0); \
int info = -1; \
lapack_name(&jobvs, &sort, &select, &sense, &n, &S(0,0), &n, \
&sdim, &wr[0], &wi[0], &Q(0,0), &n, &rconde, &rcondv, \
&work[0], &lwork, &iwork[0], &liwork, &bwork[0], &info);\
GMM_ASSERT1(!info, "SCHUR algorithm failed"); \
}
# define geesx_interface2(lapack_name, base_type) inline \
void schur(dense_matrix<base_type> &A, \
dense_matrix<base_type> &S, \
dense_matrix<base_type> &Q) { \
GMMLAPACK_TRACE("geesx_interface"); \
int m = int(mat_nrows(A)), n = int(mat_ncols(A)); \
GMM_ASSERT1(m == n, "Schur decomposition requires square matrix"); \
char jobvs = 'V', sort = 'N', sense = 'N'; \
bool select = false; \
int lwork = 8*n, sdim = 0; \
std::vector<base_type::value_type> rwork(lwork); \
std::vector<base_type> work(lwork), w(n); \
std::vector<int> bwork(1); \
resize(S, n, n); copy(A, S); \
resize(Q, n, n); \
base_type rconde(0), rcondv(0); \
int info = -1; \
lapack_name(&jobvs, &sort, &select, &sense, &n, &S(0,0), &n, \
&sdim, &w[0], &Q(0,0), &n, &rconde, &rcondv, \
&work[0], &lwork, &rwork[0], &bwork[0], &info); \
GMM_ASSERT1(!info, "SCHUR algorithm failed"); \
}
geesx_interface(sgeesx_, BLAS_S)
geesx_interface(dgeesx_, BLAS_D)
geesx_interface2(cgeesx_, BLAS_C)
geesx_interface2(zgeesx_, BLAS_Z)
template <typename MAT>
void schur(const MAT &A_, MAT &S, MAT &Q) {
MAT A(A_);
schur(A, S, Q);
}
/* ********************************************************************* */
/* Interface to SVD. Does not correspond to a Gmm++ functionnality. */
/* Author : Sebastian Nowozin <sebastian.nowozin@tuebingen.mpg.de> */
/* ********************************************************************* */
# define gesvd_interface(lapack_name, base_type) inline \
void svd(dense_matrix<base_type> &X, \
dense_matrix<base_type> &U, \
dense_matrix<base_type> &Vtransposed, \
std::vector<base_type> &sigma) { \
GMMLAPACK_TRACE("gesvd_interface"); \
int m = int(mat_nrows(X)), n = int(mat_ncols(X)); \
int mn_min = m < n ? m : n; \
sigma.resize(mn_min); \
std::vector<base_type> work(15 * mn_min); \
int lwork = int(work.size()); \
resize(U, m, m); \
resize(Vtransposed, n, n); \
char job = 'A'; \
int info = -1; \
lapack_name(&job, &job, &m, &n, &X(0,0), &m, &sigma[0], &U(0,0), \
&m, &Vtransposed(0,0), &n, &work[0], &lwork, &info); \
}
# define cgesvd_interface(lapack_name, base_type, base_type2) inline \
void svd(dense_matrix<base_type> &X, \
dense_matrix<base_type> &U, \
dense_matrix<base_type> &Vtransposed, \
std::vector<base_type2> &sigma) { \
GMMLAPACK_TRACE("gesvd_interface"); \
int m = int(mat_nrows(X)), n = int(mat_ncols(X)); \
int mn_min = m < n ? m : n; \
sigma.resize(mn_min); \
std::vector<base_type> work(15 * mn_min); \
std::vector<base_type2> rwork(5 * mn_min); \
int lwork = int(work.size()); \
resize(U, m, m); \
resize(Vtransposed, n, n); \
char job = 'A'; \
int info = -1; \
lapack_name(&job, &job, &m, &n, &X(0,0), &m, &sigma[0], &U(0,0), \
&m, &Vtransposed(0,0), &n, &work[0], &lwork, \
&rwork[0], &info); \
}
gesvd_interface(sgesvd_, BLAS_S)
gesvd_interface(dgesvd_, BLAS_D)
cgesvd_interface(cgesvd_, BLAS_C, BLAS_S)
cgesvd_interface(zgesvd_, BLAS_Z, BLAS_D)
template <typename MAT, typename VEC>
void svd(const MAT &X_, MAT &U, MAT &Vtransposed, VEC &sigma) {
MAT X(X_);
svd(X, U, Vtransposed, sigma);
}
}
#else
namespace gmm
{
template <typename MAT>
void schur(const MAT &A_, MAT &S, MAT &Q)
{
GMM_ASSERT1(false, "Use of function schur(A,S,Q) requires GetFEM++ "
"to be built with Lapack");
}
}// namespace gmm
#endif // GMM_USES_LAPACK
#endif // GMM_LAPACK_INTERFACE_H

View File

@ -0,0 +1,96 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard, Benjamin Schleimer
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_leastsquares_cg.h
@author Benjamin Schleimer <bensch128 (at) yahoo (dot) com>
@date January 23, 2007.
@brief Conjugate gradient least squares algorithm.
Algorithm taken from http://www.stat.washington.edu/wxs/Stat538-w05/Notes/conjugate-gradients.pdf page 6
*/
#ifndef GMM_LEAST_SQUARES_CG_H__
#define GMM_LEAST_SQUARES_CG_H__
#include "gmm_kernel.h"
#include "gmm_iter.h"
#include "gmm_conjugated.h"
namespace gmm {
template <typename Matrix, typename Vector1, typename Vector2>
void least_squares_cg(const Matrix& C, Vector1& x, const Vector2& y,
iteration &iter) {
typedef typename temporary_dense_vector<Vector1>::vector_type temp_vector;
typedef typename linalg_traits<Vector1>::value_type T;
T rho, rho_1(0), a;
temp_vector p(vect_size(x)), q(vect_size(y)), g(vect_size(x));
temp_vector r(vect_size(y));
iter.set_rhsnorm(gmm::sqrt(gmm::abs(vect_hp(y, y))));
if (iter.get_rhsnorm() == 0.0)
clear(x);
else {
mult(C, scaled(x, T(-1)), y, r);
mult(conjugated(C), r, g);
rho = vect_hp(g, g);
copy(g, p);
while (!iter.finished_vect(g)) {
if (!iter.first()) {
rho = vect_hp(g, g);
add(g, scaled(p, rho / rho_1), p);
}
mult(C, p, q);
a = rho / vect_hp(q, q);
add(scaled(p, a), x);
add(scaled(q, -a), r);
// NOTE: how do we minimize the impact to the transpose?
mult(conjugated(C), r, g);
rho_1 = rho;
++iter;
}
}
}
template <typename Matrix, typename Precond,
typename Vector1, typename Vector2> inline
void least_squares_cg(const Matrix& C, const Vector1& x, const Vector2& y,
iteration &iter)
{ least_squares_cg(C, linalg_const_cast(x), y, iter); }
}
#endif // GMM_SOLVER_CG_H__

1199
gmm/gmm_matrix.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,127 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
//===========================================================================
//
// Copyright (c) 1998-2001, University of Notre Dame. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the University of Notre Dame nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//===========================================================================
/**@file gmm_modified_gram_schmidt.h
@author Andrew Lumsdaine <lums@osl.iu.edu>, Lie-Quan Lee <llee@osl.iu.edu>
@date October 13, 2002.
@brief Modified Gram-Schmidt orthogonalization
*/
#ifndef GMM_MODIFIED_GRAM_SCHMIDT_H
#define GMM_MODIFIED_GRAM_SCHMIDT_H
#include "gmm_kernel.h"
namespace gmm {
template <typename T>
class modified_gram_schmidt {
protected:
typedef dense_matrix<T> MAT;
MAT M;
public:
modified_gram_schmidt(int restart, size_t s) : M(s, restart+1) {}
typename linalg_traits<MAT>::const_sub_col_type
operator[](size_t i) const { return mat_const_col(M, i); }
typename linalg_traits<MAT>::sub_col_type
operator[](size_t i) { return mat_col(M, i); }
inline size_type nrows(void) const { return M.nrows(); }
inline size_type ncols(void) const { return M.ncols(); }
MAT &mat(void) { return M; }
const MAT &mat(void) const { return M; }
};
template <typename T, typename VecHi> inline
void orthogonalize(modified_gram_schmidt<T>& V, const VecHi& Hi_, size_t i) {
VecHi& Hi = const_cast<VecHi&>(Hi_);
for (size_t k = 0; k <= i; k++) {
Hi[k] = gmm::vect_hp(V[i+1], V[k]);
gmm::add(gmm::scaled(V[k], -Hi[k]), V[i+1]);
}
}
template <typename T, typename VecHi>
void orthogonalize_with_refinment(modified_gram_schmidt<T>& V,
const VecHi& Hi_, size_t i) {
VecHi& Hi = const_cast<VecHi&>(Hi_);
orthogonalize(V, Hi_, i);
sub_interval SUBI(0, V.nrows()), SUBJ(0, i+1);
std::vector<T> corr(i+1);
gmm::mult(conjugated(sub_matrix(V.mat(), SUBI, SUBJ)),
V[i+1], corr);
gmm::mult(sub_matrix(V.mat(), SUBI, SUBJ),
scaled(corr, T(-1)), V[i+1],V[i+1]);
gmm::add(corr, sub_vector(Hi, SUBJ));
}
template <typename T, typename VecS, typename VecX>
void combine(modified_gram_schmidt<T>& V, const VecS& s, VecX& x, size_t i)
{ for (size_t j = 0; j < i; ++j) gmm::add(gmm::scaled(V[j], s[j]), x); }
}
#endif

128
gmm/gmm_opt.h Normal file
View File

@ -0,0 +1,128 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2003-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_opt.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date July 9, 2003.
@brief Optimization for some small cases (inversion of 2x2 matrices etc.)
*/
#ifndef GMM_OPT_H__
#define GMM_OPT_H__
namespace gmm {
/* ********************************************************************* */
/* Optimized determinant and inverse for small matrices (2x2 and 3x3) */
/* with dense_matrix<T>. */
/* ********************************************************************* */
template <typename T> T lu_det(const dense_matrix<T> &A) {
size_type n(mat_nrows(A));
if (n) {
const T *p = &(A(0,0));
switch (n) {
case 1 : return (*p);
case 2 : return (*p) * (*(p+3)) - (*(p+1)) * (*(p+2));
// Not stable for nearly singular matrices
// case 3 : return (*p) * ((*(p+4)) * (*(p+8)) - (*(p+5)) * (*(p+7)))
// - (*(p+1)) * ((*(p+3)) * (*(p+8)) - (*(p+5)) * (*(p+6)))
// + (*(p+2)) * ((*(p+3)) * (*(p+7)) - (*(p+4)) * (*(p+6)));
default :
{
dense_matrix<T> B(mat_nrows(A), mat_ncols(A));
std::vector<size_type> ipvt(mat_nrows(A));
gmm::copy(A, B);
lu_factor(B, ipvt);
return lu_det(B, ipvt);
}
}
}
return T(1);
}
template <typename T> T lu_inverse(const dense_matrix<T> &A_, bool doassert = true) {
dense_matrix<T>& A = const_cast<dense_matrix<T> &>(A_);
size_type N = mat_nrows(A);
T det(1);
if (N) {
T *p = &(A(0,0));
if (N <= 2) {
switch (N) {
case 1 : {
det = *p;
if (doassert) GMM_ASSERT1(det!=T(0), "non invertible matrix");
if (det == T(0)) break;
*p = T(1) / det;
} break;
case 2 : {
det = (*p) * (*(p+3)) - (*(p+1)) * (*(p+2));
if (doassert) GMM_ASSERT1(det!=T(0), "non invertible matrix");
if (det == T(0)) break;
std::swap(*p, *(p+3));
*p++ /= det; *p++ /= -det; *p++ /= -det; *p++ /= det;
} break;
// case 3 : { // not stable for nearly singular matrices
// T a, b, c, d, e, f, g, h, i;
// a = (*(p+4)) * (*(p+8)) - (*(p+5)) * (*(p+7));
// b = - (*(p+1)) * (*(p+8)) + (*(p+2)) * (*(p+7));
// c = (*(p+1)) * (*(p+5)) - (*(p+2)) * (*(p+4));
// d = - (*(p+3)) * (*(p+8)) + (*(p+5)) * (*(p+6));
// e = (*(p+0)) * (*(p+8)) - (*(p+2)) * (*(p+6));
// f = - (*(p+0)) * (*(p+5)) + (*(p+2)) * (*(p+3));
// g = (*(p+3)) * (*(p+7)) - (*(p+4)) * (*(p+6));
// h = - (*(p+0)) * (*(p+7)) + (*(p+1)) * (*(p+6));
// i = (*(p+0)) * (*(p+4)) - (*(p+1)) * (*(p+3));
// det = (*p) * a + (*(p+1)) * d + (*(p+2)) * g;
// GMM_ASSERT1(det!=T(0), "non invertible matrix");
// *p++ = a / det; *p++ = b / det; *p++ = c / det;
// *p++ = d / det; *p++ = e / det; *p++ = f / det;
// *p++ = g / det; *p++ = h / det; *p++ = i / det;
// } break;
}
}
else {
dense_matrix<T> B(mat_nrows(A), mat_ncols(A));
std::vector<int> ipvt(mat_nrows(A));
gmm::copy(A, B);
size_type info = lu_factor(B, ipvt);
GMM_ASSERT1(!info, "non invertible matrix");
lu_inverse(B, ipvt, A);
return lu_det(B, ipvt);
}
}
return det;
}
}
#endif // GMM_OPT_H__

65
gmm/gmm_precond.h Normal file
View File

@ -0,0 +1,65 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2004-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
#ifndef GMM_PRECOND_H
#define GMM_PRECOND_H
#include "gmm_kernel.h"
/** @file gmm_precond.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date March 29, 2004.
@brief gmm preconditioners.
*/
/* Preconditioner concept : */
/* */
/* A the matrix, P the preconditioner PA well conditioned. */
/* PRECOND precontioner type. */
/* mult(P, v, w) : w <- P v */
/* transposed_mult(P, v, w) : w <- transposed(P) v */
/* left_mult(P, v, w) : see qmr solver */
/* right_mult(P, v, w) : see qmr solver */
/* transposed_left_mult(P, v, w) : see qmr solver */
/* transposed_right_mult(P, v, w) : see qmr solver */
/* */
/* PRECOND P() : empty preconditioner. */
/* PRECOND P(A, ...) : preconditioner for the matrix A, with optional */
/* parameters */
/* PRECOND(...) : empty precondtioner with parameters set. */
/* P.build_with(A) : build a precondtioner for A. */
/* */
/* *********************************************************************** */
#endif

132
gmm/gmm_precond_diagonal.h Normal file
View File

@ -0,0 +1,132 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2003-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_precond_diagonal.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date June 5, 2003.
@brief Diagonal matrix preconditoner.
*/
#ifndef GMM_PRECOND_DIAGONAL_H
#define GMM_PRECOND_DIAGONAL_H
#include "gmm_precond.h"
namespace gmm {
/** Diagonal preconditioner. */
template<typename Matrix> struct diagonal_precond {
typedef typename linalg_traits<Matrix>::value_type value_type;
typedef typename number_traits<value_type>::magnitude_type magnitude_type;
std::vector<magnitude_type> diag;
void build_with(const Matrix &M) {
diag.resize(mat_nrows(M));
for (size_type i = 0; i < mat_nrows(M); ++i) {
magnitude_type x = gmm::abs(M(i, i));
if (x == magnitude_type(0)) {
x = magnitude_type(1);
GMM_WARNING2("The matrix has a zero on its diagonal");
}
diag[i] = magnitude_type(1) / x;
}
}
size_type memsize() const { return sizeof(*this) + diag.size() * sizeof(value_type); }
diagonal_precond(const Matrix &M) { build_with(M); }
diagonal_precond(void) {}
};
template <typename Matrix, typename V2> inline
void mult_diag_p(const diagonal_precond<Matrix>& P, V2 &v2, abstract_sparse){
typename linalg_traits<V2>::iterator it = vect_begin(v2),
ite = vect_end(v2);
for (; it != ite; ++it) *it *= P.diag[it.index()];
}
template <typename Matrix, typename V2> inline
void mult_diag_p(const diagonal_precond<Matrix>& P,V2 &v2, abstract_skyline)
{ mult_diag_p(P, v2, abstract_sparse()); }
template <typename Matrix, typename V2> inline
void mult_diag_p(const diagonal_precond<Matrix>& P, V2 &v2, abstract_dense){
for (size_type i = 0; i < P.diag.size(); ++i) v2[i] *= P.diag[i];
}
template <typename Matrix, typename V1, typename V2> inline
void mult(const diagonal_precond<Matrix>& P, const V1 &v1, V2 &v2) {
GMM_ASSERT2(P.diag.size() == vect_size(v2),"dimensions mismatch");
copy(v1, v2);
mult_diag_p(P, v2, typename linalg_traits<V2>::storage_type());
}
template <typename Matrix, typename V1, typename V2> inline
void transposed_mult(const diagonal_precond<Matrix>& P,const V1 &v1,V2 &v2) {
mult(P, v1, v2);
}
// # define DIAG_LEFT_MULT_SQRT
template <typename Matrix, typename V1, typename V2> inline
void left_mult(const diagonal_precond<Matrix>& P, const V1 &v1, V2 &v2) {
GMM_ASSERT2(P.diag.size() == vect_size(v2), "dimensions mismatch");
copy(v1, v2);
# ifdef DIAG_LEFT_MULT_SQRT
for (size_type i= 0; i < P.diag.size(); ++i) v2[i] *= gmm::sqrt(P.diag[i]);
# else
for (size_type i= 0; i < P.diag.size(); ++i) v2[i] *= P.diag[i];
# endif
}
template <typename Matrix, typename V1, typename V2> inline
void transposed_left_mult(const diagonal_precond<Matrix>& P,
const V1 &v1, V2 &v2)
{ left_mult(P, v1, v2); }
template <typename Matrix, typename V1, typename V2> inline
void right_mult(const diagonal_precond<Matrix>& P, const V1 &v1, V2 &v2) {
// typedef typename linalg_traits<Matrix>::value_type T;
GMM_ASSERT2(P.diag.size() == vect_size(v2), "dimensions mismatch");
copy(v1, v2);
# ifdef DIAG_LEFT_MULT_SQRT
for (size_type i= 0; i < P.diag.size(); ++i) v2[i] *= gmm::sqrt(P.diag[i]);
# endif
}
template <typename Matrix, typename V1, typename V2> inline
void transposed_right_mult(const diagonal_precond<Matrix>& P,
const V1 &v1, V2 &v2)
{ right_mult(P, v1, v2); }
}
#endif

241
gmm/gmm_precond_ildlt.h Normal file
View File

@ -0,0 +1,241 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2003-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
// This file is a modified version of cholesky.h from ITL.
// See http://osl.iu.edu/research/itl/
// Following the corresponding Copyright notice.
//===========================================================================
//
// Copyright (c) 1998-2001, University of Notre Dame. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the University of Notre Dame nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//===========================================================================
#ifndef GMM_PRECOND_ILDLT_H
#define GMM_PRECOND_ILDLT_H
/**@file gmm_precond_ildlt.h
@author Andrew Lumsdaine <lums@osl.iu.edu>
@author Lie-Quan Lee <llee@osl.iu.edu>
@author Yves Renard <yves.renard@insa-lyon.fr>
@date June 5, 2003.
@brief Incomplete Level 0 ILDLT Preconditioner.
*/
#include "gmm_precond.h"
namespace gmm {
/** Incomplete Level 0 LDLT Preconditioner.
For use with symmetric real or hermitian complex sparse matrices.
Notes: The idea under a concrete Preconditioner such as Incomplete
Cholesky is to create a Preconditioner object to use in iterative
methods.
Y. Renard : Transformed in LDLT for stability reason.
U=LT is stored in csr format. D is stored on the diagonal of U.
*/
template <typename Matrix>
class ildlt_precond {
public :
typedef typename linalg_traits<Matrix>::value_type value_type;
typedef typename number_traits<value_type>::magnitude_type magnitude_type;
typedef csr_matrix_ref<value_type *, size_type *, size_type *, 0> tm_type;
tm_type U;
protected :
std::vector<value_type> Tri_val;
std::vector<size_type> Tri_ind, Tri_ptr;
template<typename M> void do_ildlt(const M& A, row_major);
void do_ildlt(const Matrix& A, col_major);
public:
size_type nrows(void) const { return mat_nrows(U); }
size_type ncols(void) const { return mat_ncols(U); }
value_type &D(size_type i) { return Tri_val[Tri_ptr[i]]; }
const value_type &D(size_type i) const { return Tri_val[Tri_ptr[i]]; }
ildlt_precond(void) {}
void build_with(const Matrix& A) {
Tri_ptr.resize(mat_nrows(A)+1);
do_ildlt(A, typename principal_orientation_type<typename
linalg_traits<Matrix>::sub_orientation>::potype());
}
ildlt_precond(const Matrix& A) { build_with(A); }
size_type memsize() const {
return sizeof(*this) +
Tri_val.size() * sizeof(value_type) +
(Tri_ind.size()+Tri_ptr.size()) * sizeof(size_type);
}
};
template <typename Matrix> template<typename M>
void ildlt_precond<Matrix>::do_ildlt(const M& A, row_major) {
typedef typename linalg_traits<Matrix>::storage_type store_type;
typedef value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type Tri_loc = 0, n = mat_nrows(A), d, g, h, i, j, k;
if (n == 0) return;
T z, zz;
Tri_ptr[0] = 0;
R prec = default_tol(R());
R max_pivot = gmm::abs(A(0,0)) * prec;
for (int count = 0; count < 2; ++count) {
if (count) { Tri_val.resize(Tri_loc); Tri_ind.resize(Tri_loc); }
for (Tri_loc = 0, i = 0; i < n; ++i) {
typedef typename linalg_traits<M>::const_sub_row_type row_type;
row_type row = mat_const_row(A, i);
typename linalg_traits<typename org_type<row_type>::t>::const_iterator
it = vect_const_begin(row), ite = vect_const_end(row);
if (count) { Tri_val[Tri_loc] = T(0); Tri_ind[Tri_loc] = i; }
++Tri_loc; // diagonal element
for (k = 0; it != ite; ++it, ++k) {
j = index_of_it(it, k, store_type());
if (i == j) {
if (count) Tri_val[Tri_loc-1] = *it;
}
else if (j > i) {
if (count) { Tri_val[Tri_loc] = *it; Tri_ind[Tri_loc]=j; }
++Tri_loc;
}
}
Tri_ptr[i+1] = Tri_loc;
}
}
if (A(0,0) == T(0)) {
Tri_val[Tri_ptr[0]] = T(1);
GMM_WARNING2("pivot 0 is too small");
}
for (k = 0; k < n; k++) {
d = Tri_ptr[k];
z = T(gmm::real(Tri_val[d])); Tri_val[d] = z;
if (gmm::abs(z) <= max_pivot) {
Tri_val[d] = z = T(1);
GMM_WARNING2("pivot " << k << " is too small [" << gmm::abs(z) << "]");
}
max_pivot = std::max(max_pivot, std::min(gmm::abs(z) * prec, R(1)));
for (i = d + 1; i < Tri_ptr[k+1]; ++i) Tri_val[i] /= z;
for (i = d + 1; i < Tri_ptr[k+1]; ++i) {
zz = gmm::conj(Tri_val[i] * z);
h = Tri_ind[i];
g = i;
for (j = Tri_ptr[h] ; j < Tri_ptr[h+1]; ++j)
for ( ; g < Tri_ptr[k+1] && Tri_ind[g] <= Tri_ind[j]; ++g)
if (Tri_ind[g] == Tri_ind[j])
Tri_val[j] -= zz * Tri_val[g];
}
}
U = tm_type(&(Tri_val[0]), &(Tri_ind[0]), &(Tri_ptr[0]),
n, mat_ncols(A));
}
template <typename Matrix>
void ildlt_precond<Matrix>::do_ildlt(const Matrix& A, col_major)
{ do_ildlt(gmm::conjugated(A), row_major()); }
template <typename Matrix, typename V1, typename V2> inline
void mult(const ildlt_precond<Matrix>& P, const V1 &v1, V2 &v2) {
gmm::copy(v1, v2);
gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
for (size_type i = 0; i < mat_nrows(P.U); ++i) v2[i] /= P.D(i);
gmm::upper_tri_solve(P.U, v2, true);
}
template <typename Matrix, typename V1, typename V2> inline
void transposed_mult(const ildlt_precond<Matrix>& P,const V1 &v1,V2 &v2)
{ mult(P, v1, v2); }
template <typename Matrix, typename V1, typename V2> inline
void left_mult(const ildlt_precond<Matrix>& P, const V1 &v1, V2 &v2) {
copy(v1, v2);
gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
for (size_type i = 0; i < mat_nrows(P.U); ++i) v2[i] /= P.D(i);
}
template <typename Matrix, typename V1, typename V2> inline
void right_mult(const ildlt_precond<Matrix>& P, const V1 &v1, V2 &v2)
{ copy(v1, v2); gmm::upper_tri_solve(P.U, v2, true); }
template <typename Matrix, typename V1, typename V2> inline
void transposed_left_mult(const ildlt_precond<Matrix>& P, const V1 &v1,
V2 &v2) {
copy(v1, v2);
gmm::upper_tri_solve(P.U, v2, true);
for (size_type i = 0; i < mat_nrows(P.U); ++i) v2[i] /= P.D(i);
}
template <typename Matrix, typename V1, typename V2> inline
void transposed_right_mult(const ildlt_precond<Matrix>& P, const V1 &v1,
V2 &v2)
{ copy(v1, v2); gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true); }
}
#endif

174
gmm/gmm_precond_ildltt.h Normal file
View File

@ -0,0 +1,174 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2003-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_precond_ildltt.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date June 30, 2003.
@brief incomplete LDL^t (cholesky) preconditioner with fill-in and threshold.
*/
#ifndef GMM_PRECOND_ILDLTT_H
#define GMM_PRECOND_ILDLTT_H
// Store U = LT and D in indiag. On each line, the fill-in is the number
// of non-zero elements on the line of the original matrix plus K, except if
// the matrix is dense. In this case the fill-in is K on each line.
#include "gmm_precond_ilut.h"
namespace gmm {
/** incomplete LDL^t (cholesky) preconditioner with fill-in and
threshold. */
template <typename Matrix>
class ildltt_precond {
public :
typedef typename linalg_traits<Matrix>::value_type value_type;
typedef typename number_traits<value_type>::magnitude_type magnitude_type;
typedef rsvector<value_type> svector;
row_matrix<svector> U;
std::vector<magnitude_type> indiag;
protected:
size_type K;
double eps;
template<typename M> void do_ildltt(const M&, row_major);
void do_ildltt(const Matrix&, col_major);
public:
void build_with(const Matrix& A, int k_ = -1, double eps_ = double(-1)) {
if (k_ >= 0) K = k_;
if (eps_ >= double(0)) eps = eps_;
gmm::resize(U, mat_nrows(A), mat_ncols(A));
indiag.resize(std::min(mat_nrows(A), mat_ncols(A)));
do_ildltt(A, typename principal_orientation_type<typename
linalg_traits<Matrix>::sub_orientation>::potype());
}
ildltt_precond(const Matrix& A, int k_, double eps_)
: U(mat_nrows(A),mat_ncols(A)), K(k_), eps(eps_) { build_with(A); }
ildltt_precond(void) { K=10; eps = 1E-7; }
ildltt_precond(size_type k_, double eps_) : K(k_), eps(eps_) {}
size_type memsize() const {
return sizeof(*this) + nnz(U)*sizeof(value_type) + indiag.size() * sizeof(magnitude_type);
}
};
template<typename Matrix> template<typename M>
void ildltt_precond<Matrix>::do_ildltt(const M& A,row_major) {
typedef value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type n = mat_nrows(A);
if (n == 0) return;
svector w(n);
T tmp;
R prec = default_tol(R()), max_pivot = gmm::abs(A(0,0)) * prec;
gmm::clear(U);
for (size_type i = 0; i < n; ++i) {
gmm::copy(mat_const_row(A, i), w);
double norm_row = gmm::vect_norm2(w);
for (size_type krow = 0, k; krow < w.nb_stored(); ++krow) {
typename svector::iterator wk = w.begin() + krow;
if ((k = wk->c) >= i) break;
if (gmm::is_complex(wk->e)) {
tmp = gmm::conj(U(k, i))/indiag[k]; // not completely satisfactory ..
gmm::add(scaled(mat_row(U, k), -tmp), w);
}
else {
tmp = wk->e;
if (gmm::abs(tmp) < eps * norm_row) { w.sup(k); --krow; }
else { wk->e += tmp; gmm::add(scaled(mat_row(U, k), -tmp), w); }
}
}
tmp = w[i];
if (gmm::abs(gmm::real(tmp)) <= max_pivot)
{ GMM_WARNING2("pivot " << i << " is too small"); tmp = T(1); }
max_pivot = std::max(max_pivot, std::min(gmm::abs(tmp) * prec, R(1)));
indiag[i] = R(1) / gmm::real(tmp);
gmm::clean(w, eps * norm_row);
gmm::scale(w, T(indiag[i]));
std::sort(w.begin(), w.end(), elt_rsvector_value_less_<T>());
typename svector::const_iterator wit = w.begin(), wite = w.end();
for (size_type nnu = 0; wit != wite; ++wit) // copy to be optimized ...
if (wit->c > i) { if (nnu < K) { U(i, wit->c) = wit->e; ++nnu; } }
}
}
template<typename Matrix>
void ildltt_precond<Matrix>::do_ildltt(const Matrix& A, col_major)
{ do_ildltt(gmm::conjugated(A), row_major()); }
template <typename Matrix, typename V1, typename V2> inline
void mult(const ildltt_precond<Matrix>& P, const V1 &v1, V2 &v2) {
gmm::copy(v1, v2);
gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
for (size_type i = 0; i < P.indiag.size(); ++i) v2[i] *= P.indiag[i];
gmm::upper_tri_solve(P.U, v2, true);
}
template <typename Matrix, typename V1, typename V2> inline
void transposed_mult(const ildltt_precond<Matrix>& P,const V1 &v1, V2 &v2)
{ mult(P, v1, v2); }
template <typename Matrix, typename V1, typename V2> inline
void left_mult(const ildltt_precond<Matrix>& P, const V1 &v1, V2 &v2) {
copy(v1, v2);
gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true);
for (size_type i = 0; i < P.indiag.size(); ++i) v2[i] *= P.indiag[i];
}
template <typename Matrix, typename V1, typename V2> inline
void right_mult(const ildltt_precond<Matrix>& P, const V1 &v1, V2 &v2)
{ copy(v1, v2); gmm::upper_tri_solve(P.U, v2, true); }
template <typename Matrix, typename V1, typename V2> inline
void transposed_left_mult(const ildltt_precond<Matrix>& P, const V1 &v1,
V2 &v2) {
copy(v1, v2);
gmm::upper_tri_solve(P.U, v2, true);
for (size_type i = 0; i < P.indiag.size(); ++i) v2[i] *= P.indiag[i];
}
template <typename Matrix, typename V1, typename V2> inline
void transposed_right_mult(const ildltt_precond<Matrix>& P, const V1 &v1,
V2 &v2)
{ copy(v1, v2); gmm::lower_tri_solve(gmm::conjugated(P.U), v2, true); }
}
#endif

280
gmm/gmm_precond_ilu.h Normal file
View File

@ -0,0 +1,280 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
// This file is a modified version of ilu.h from ITL.
// See http://osl.iu.edu/research/itl/
// Following the corresponding Copyright notice.
//===========================================================================
//
// Copyright (c) 1998-2001, University of Notre Dame. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the University of Notre Dame nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//===========================================================================
/**@file gmm_precond_ilu.h
@author Andrew Lumsdaine <lums@osl.iu.edu>
@author Lie-Quan Lee <llee@osl.iu.edu>
@author Yves Renard <yves.renard@insa-lyon.fr>
@date June 5, 2003.
@brief Incomplete LU without fill-in Preconditioner.
*/
#ifndef GMM_PRECOND_ILU_H
#define GMM_PRECOND_ILU_H
//
// Notes: The idea under a concrete Preconditioner such
// as Incomplete LU is to create a Preconditioner
// object to use in iterative methods.
//
#include "gmm_precond.h"
namespace gmm {
/** Incomplete LU without fill-in Preconditioner. */
template <typename Matrix>
class ilu_precond {
public :
typedef typename linalg_traits<Matrix>::value_type value_type;
typedef csr_matrix_ref<value_type *, size_type *, size_type *, 0> tm_type;
tm_type U, L;
bool invert;
protected :
std::vector<value_type> L_val, U_val;
std::vector<size_type> L_ind, U_ind, L_ptr, U_ptr;
template<typename M> void do_ilu(const M& A, row_major);
void do_ilu(const Matrix& A, col_major);
public:
size_type nrows(void) const { return mat_nrows(L); }
size_type ncols(void) const { return mat_ncols(U); }
void build_with(const Matrix& A) {
invert = false;
L_ptr.resize(mat_nrows(A)+1);
U_ptr.resize(mat_nrows(A)+1);
do_ilu(A, typename principal_orientation_type<typename
linalg_traits<Matrix>::sub_orientation>::potype());
}
ilu_precond(const Matrix& A) { build_with(A); }
ilu_precond(void) {}
size_type memsize() const {
return sizeof(*this) +
(L_val.size()+U_val.size()) * sizeof(value_type) +
(L_ind.size()+L_ptr.size()) * sizeof(size_type) +
(U_ind.size()+U_ptr.size()) * sizeof(size_type);
}
};
template <typename Matrix> template <typename M>
void ilu_precond<Matrix>::do_ilu(const M& A, row_major) {
typedef typename linalg_traits<Matrix>::storage_type store_type;
typedef value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type L_loc = 0, U_loc = 0, n = mat_nrows(A), i, j, k;
if (n == 0) return;
L_ptr[0] = 0; U_ptr[0] = 0;
R prec = default_tol(R());
R max_pivot = gmm::abs(A(0,0)) * prec;
for (int count = 0; count < 2; ++count) {
if (count) {
L_val.resize(L_loc); L_ind.resize(L_loc);
U_val.resize(U_loc); U_ind.resize(U_loc);
}
L_loc = U_loc = 0;
for (i = 0; i < n; ++i) {
typedef typename linalg_traits<M>::const_sub_row_type row_type;
row_type row = mat_const_row(A, i);
typename linalg_traits<typename org_type<row_type>::t>::const_iterator
it = vect_const_begin(row), ite = vect_const_end(row);
if (count) { U_val[U_loc] = T(0); U_ind[U_loc] = i; }
++U_loc; // diagonal element
for (k = 0; it != ite && k < 1000; ++it, ++k) {
// if a plain row is present, retains only the 1000 firsts
// nonzero elements. ---> a sort should be done.
j = index_of_it(it, k, store_type());
if (j < i) {
if (count) { L_val[L_loc] = *it; L_ind[L_loc] = j; }
L_loc++;
}
else if (i == j) {
if (count) U_val[U_loc-1] = *it;
}
else {
if (count) { U_val[U_loc] = *it; U_ind[U_loc] = j; }
U_loc++;
}
}
L_ptr[i+1] = L_loc; U_ptr[i+1] = U_loc;
}
}
if (A(0,0) == T(0)) {
U_val[U_ptr[0]] = T(1);
GMM_WARNING2("pivot 0 is too small");
}
size_type qn, pn, rn;
for (i = 1; i < n; i++) {
pn = U_ptr[i];
if (gmm::abs(U_val[pn]) <= max_pivot) {
U_val[pn] = T(1);
GMM_WARNING2("pivot " << i << " is too small");
}
max_pivot = std::max(max_pivot,
std::min(gmm::abs(U_val[pn]) * prec, R(1)));
for (j = L_ptr[i]; j < L_ptr[i+1]; j++) {
pn = U_ptr[L_ind[j]];
T multiplier = (L_val[j] /= U_val[pn]);
qn = j + 1;
rn = U_ptr[i];
for (pn++; pn < U_ptr[L_ind[j]+1] && U_ind[pn] < i; pn++) {
while (qn < L_ptr[i+1] && L_ind[qn] < U_ind[pn])
qn++;
if (qn < L_ptr[i+1] && U_ind[pn] == L_ind[qn])
L_val[qn] -= multiplier * U_val[pn];
}
for (; pn < U_ptr[L_ind[j]+1]; pn++) {
while (rn < U_ptr[i+1] && U_ind[rn] < U_ind[pn])
rn++;
if (rn < U_ptr[i+1] && U_ind[pn] == U_ind[rn])
U_val[rn] -= multiplier * U_val[pn];
}
}
}
L = tm_type(&(L_val[0]), &(L_ind[0]), &(L_ptr[0]), n, mat_ncols(A));
U = tm_type(&(U_val[0]), &(U_ind[0]), &(U_ptr[0]), n, mat_ncols(A));
}
template <typename Matrix>
void ilu_precond<Matrix>::do_ilu(const Matrix& A, col_major) {
do_ilu(gmm::transposed(A), row_major());
invert = true;
}
template <typename Matrix, typename V1, typename V2> inline
void mult(const ilu_precond<Matrix>& P, const V1 &v1, V2 &v2) {
gmm::copy(v1, v2);
if (P.invert) {
gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
}
else {
gmm::lower_tri_solve(P.L, v2, true);
gmm::upper_tri_solve(P.U, v2, false);
}
}
template <typename Matrix, typename V1, typename V2> inline
void transposed_mult(const ilu_precond<Matrix>& P,const V1 &v1,V2 &v2) {
gmm::copy(v1, v2);
if (P.invert) {
gmm::lower_tri_solve(P.L, v2, true);
gmm::upper_tri_solve(P.U, v2, false);
}
else {
gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
}
}
template <typename Matrix, typename V1, typename V2> inline
void left_mult(const ilu_precond<Matrix>& P, const V1 &v1, V2 &v2) {
copy(v1, v2);
if (P.invert) gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
else gmm::lower_tri_solve(P.L, v2, true);
}
template <typename Matrix, typename V1, typename V2> inline
void right_mult(const ilu_precond<Matrix>& P, const V1 &v1, V2 &v2) {
copy(v1, v2);
if (P.invert) gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
else gmm::upper_tri_solve(P.U, v2, false);
}
template <typename Matrix, typename V1, typename V2> inline
void transposed_left_mult(const ilu_precond<Matrix>& P, const V1 &v1,
V2 &v2) {
copy(v1, v2);
if (P.invert) gmm::upper_tri_solve(P.U, v2, false);
else gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
}
template <typename Matrix, typename V1, typename V2> inline
void transposed_right_mult(const ilu_precond<Matrix>& P, const V1 &v1,
V2 &v2) {
copy(v1, v2);
if (P.invert) gmm::lower_tri_solve(P.L, v2, true);
else gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
}
}
#endif

263
gmm/gmm_precond_ilut.h Normal file
View File

@ -0,0 +1,263 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
// This file is a modified version of ilut.h from ITL.
// See http://osl.iu.edu/research/itl/
// Following the corresponding Copyright notice.
//===========================================================================
//
// Copyright (c) 1998-2001, University of Notre Dame. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the University of Notre Dame nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//===========================================================================
#ifndef GMM_PRECOND_ILUT_H
#define GMM_PRECOND_ILUT_H
/**@file gmm_precond_ilut.h
@author Andrew Lumsdaine <lums@osl.iu.edu>, Lie-Quan Lee <llee@osl.iu.edu>
@date June 5, 2003.
@brief ILUT: Incomplete LU with threshold and K fill-in Preconditioner.
*/
/*
Performane comparing for SSOR, ILU and ILUT based on sherman 5 matrix
in Harwell-Boeing collection on Sun Ultra 30 UPA/PCI (UltraSPARC-II 296MHz)
Preconditioner & Factorization time & Number of Iteration \\ \hline
SSOR & 0.010577 & 41 \\
ILU & 0.019336 & 32 \\
ILUT with 0 fill-in and threshold of 1.0e-6 & 0.343612 & 23 \\
ILUT with 5 fill-in and threshold of 1.0e-6 & 0.343612 & 18 \\ \hline
*/
#include "gmm_precond.h"
namespace gmm {
template<typename T> struct elt_rsvector_value_less_ {
inline bool operator()(const elt_rsvector_<T>& a,
const elt_rsvector_<T>& b) const
{ return (gmm::abs(a.e) > gmm::abs(b.e)); }
};
/** Incomplete LU with threshold and K fill-in Preconditioner.
The algorithm of ILUT(A, 0, 1.0e-6) is slower than ILU(A). If No
fill-in is arrowed, you can use ILU instead of ILUT.
Notes: The idea under a concrete Preconditioner such as ilut is to
create a Preconditioner object to use in iterative methods.
*/
template <typename Matrix>
class ilut_precond {
public :
typedef typename linalg_traits<Matrix>::value_type value_type;
typedef wsvector<value_type> _wsvector;
typedef rsvector<value_type> _rsvector;
typedef row_matrix<_rsvector> LU_Matrix;
bool invert;
LU_Matrix L, U;
protected:
size_type K;
double eps;
template<typename M> void do_ilut(const M&, row_major);
void do_ilut(const Matrix&, col_major);
public:
void build_with(const Matrix& A, int k_ = -1, double eps_ = double(-1)) {
if (k_ >= 0) K = k_;
if (eps_ >= double(0)) eps = eps_;
invert = false;
gmm::resize(L, mat_nrows(A), mat_ncols(A));
gmm::resize(U, mat_nrows(A), mat_ncols(A));
do_ilut(A, typename principal_orientation_type<typename
linalg_traits<Matrix>::sub_orientation>::potype());
}
ilut_precond(const Matrix& A, int k_, double eps_)
: L(mat_nrows(A), mat_ncols(A)), U(mat_nrows(A), mat_ncols(A)),
K(k_), eps(eps_) { build_with(A); }
ilut_precond(size_type k_, double eps_) : K(k_), eps(eps_) {}
ilut_precond(void) { K = 10; eps = 1E-7; }
size_type memsize() const {
return sizeof(*this) + (nnz(U)+nnz(L))*sizeof(value_type);
}
};
template<typename Matrix> template<typename M>
void ilut_precond<Matrix>::do_ilut(const M& A, row_major) {
typedef value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type n = mat_nrows(A);
if (n == 0) return;
std::vector<T> indiag(n);
_wsvector w(mat_ncols(A));
_rsvector ww(mat_ncols(A)), wL(mat_ncols(A)), wU(mat_ncols(A));
T tmp;
gmm::clear(U); gmm::clear(L);
R prec = default_tol(R());
R max_pivot = gmm::abs(A(0,0)) * prec;
for (size_type i = 0; i < n; ++i) {
gmm::copy(mat_const_row(A, i), w);
double norm_row = gmm::vect_norm2(w);
typename _wsvector::iterator wkold = w.end();
for (typename _wsvector::iterator wk = w.begin();
wk != w.end() && wk->first < i; ) {
size_type k = wk->first;
tmp = (wk->second) * indiag[k];
if (gmm::abs(tmp) < eps * norm_row) w.erase(k);
else { wk->second += tmp; gmm::add(scaled(mat_row(U, k), -tmp), w); }
if (wkold == w.end()) wk = w.begin(); else { wk = wkold; ++wk; }
if (wk != w.end() && wk->first == k)
{ if (wkold == w.end()) wkold = w.begin(); else ++wkold; ++wk; }
}
tmp = w[i];
if (gmm::abs(tmp) <= max_pivot) {
GMM_WARNING2("pivot " << i << " too small. try with ilutp ?");
w[i] = tmp = T(1);
}
max_pivot = std::max(max_pivot, std::min(gmm::abs(tmp) * prec, R(1)));
indiag[i] = T(1) / tmp;
gmm::clean(w, eps * norm_row);
gmm::copy(w, ww);
std::sort(ww.begin(), ww.end(), elt_rsvector_value_less_<T>());
typename _rsvector::const_iterator wit = ww.begin(), wite = ww.end();
size_type nnl = 0, nnu = 0;
wL.base_resize(K); wU.base_resize(K+1);
typename _rsvector::iterator witL = wL.begin(), witU = wU.begin();
for (; wit != wite; ++wit)
if (wit->c < i) { if (nnl < K) { *witL++ = *wit; ++nnl; } }
else { if (nnu < K || wit->c == i) { *witU++ = *wit; ++nnu; } }
wL.base_resize(nnl); wU.base_resize(nnu);
std::sort(wL.begin(), wL.end());
std::sort(wU.begin(), wU.end());
gmm::copy(wL, L.row(i));
gmm::copy(wU, U.row(i));
}
}
template<typename Matrix>
void ilut_precond<Matrix>::do_ilut(const Matrix& A, col_major) {
do_ilut(gmm::transposed(A), row_major());
invert = true;
}
template <typename Matrix, typename V1, typename V2> inline
void mult(const ilut_precond<Matrix>& P, const V1 &v1, V2 &v2) {
gmm::copy(v1, v2);
if (P.invert) {
gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
}
else {
gmm::lower_tri_solve(P.L, v2, true);
gmm::upper_tri_solve(P.U, v2, false);
}
}
template <typename Matrix, typename V1, typename V2> inline
void transposed_mult(const ilut_precond<Matrix>& P,const V1 &v1,V2 &v2) {
gmm::copy(v1, v2);
if (P.invert) {
gmm::lower_tri_solve(P.L, v2, true);
gmm::upper_tri_solve(P.U, v2, false);
}
else {
gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
}
}
template <typename Matrix, typename V1, typename V2> inline
void left_mult(const ilut_precond<Matrix>& P, const V1 &v1, V2 &v2) {
copy(v1, v2);
if (P.invert) gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
else gmm::lower_tri_solve(P.L, v2, true);
}
template <typename Matrix, typename V1, typename V2> inline
void right_mult(const ilut_precond<Matrix>& P, const V1 &v1, V2 &v2) {
copy(v1, v2);
if (P.invert) gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
else gmm::upper_tri_solve(P.U, v2, false);
}
template <typename Matrix, typename V1, typename V2> inline
void transposed_left_mult(const ilut_precond<Matrix>& P, const V1 &v1,
V2 &v2) {
copy(v1, v2);
if (P.invert) gmm::upper_tri_solve(P.U, v2, false);
else gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
}
template <typename Matrix, typename V1, typename V2> inline
void transposed_right_mult(const ilut_precond<Matrix>& P, const V1 &v1,
V2 &v2) {
copy(v1, v2);
if (P.invert) gmm::lower_tri_solve(P.L, v2, true);
else gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
}
}
#endif

284
gmm/gmm_precond_ilutp.h Normal file
View File

@ -0,0 +1,284 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2004-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_precond_ilutp.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date October 14, 2004.
@brief ILUTP: Incomplete LU with threshold and K fill-in Preconditioner and
column pivoting.
*/
#ifndef GMM_PRECOND_ILUTP_H
#define GMM_PRECOND_ILUTP_H
#include "gmm_precond_ilut.h"
namespace gmm {
/**
ILUTP: Incomplete LU with threshold and K fill-in Preconditioner and
column pivoting.
See Yousef Saad, Iterative Methods for
sparse linear systems, PWS Publishing Company, section 10.4.4
TODO : store the permutation by cycles to avoid the temporary vector
*/
template <typename Matrix>
class ilutp_precond {
public :
typedef typename linalg_traits<Matrix>::value_type value_type;
typedef wsvector<value_type> _wsvector;
typedef rsvector<value_type> _rsvector;
typedef row_matrix<_rsvector> LU_Matrix;
typedef col_matrix<_wsvector> CLU_Matrix;
bool invert;
LU_Matrix L, U;
gmm::unsorted_sub_index indperm;
gmm::unsorted_sub_index indperminv;
mutable std::vector<value_type> temporary;
protected:
size_type K;
double eps;
template<typename M> void do_ilutp(const M&, row_major);
void do_ilutp(const Matrix&, col_major);
public:
void build_with(const Matrix& A, int k_ = -1, double eps_ = double(-1)) {
if (k_ >= 0) K = k_;
if (eps_ >= double(0)) eps = eps_;
invert = false;
gmm::resize(L, mat_nrows(A), mat_ncols(A));
gmm::resize(U, mat_nrows(A), mat_ncols(A));
do_ilutp(A, typename principal_orientation_type<typename
linalg_traits<Matrix>::sub_orientation>::potype());
}
ilutp_precond(const Matrix& A, size_type k_, double eps_)
: L(mat_nrows(A), mat_ncols(A)), U(mat_nrows(A), mat_ncols(A)),
K(k_), eps(eps_) { build_with(A); }
ilutp_precond(int k_, double eps_) : K(k_), eps(eps_) {}
ilutp_precond(void) { K = 10; eps = 1E-7; }
size_type memsize() const {
return sizeof(*this) + (nnz(U)+nnz(L))*sizeof(value_type);
}
};
template<typename Matrix> template<typename M>
void ilutp_precond<Matrix>::do_ilutp(const M& A, row_major) {
typedef value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type n = mat_nrows(A);
CLU_Matrix CU(n,n);
if (n == 0) return;
std::vector<T> indiag(n);
temporary.resize(n);
std::vector<size_type> ipvt(n), ipvtinv(n);
for (size_type i = 0; i < n; ++i) ipvt[i] = ipvtinv[i] = i;
indperm = unsorted_sub_index(ipvt);
indperminv = unsorted_sub_index(ipvtinv);
_wsvector w(mat_ncols(A));
_rsvector ww(mat_ncols(A));
T tmp = T(0);
gmm::clear(L); gmm::clear(U);
R prec = default_tol(R());
R max_pivot = gmm::abs(A(0,0)) * prec;
for (size_type i = 0; i < n; ++i) {
copy(sub_vector(mat_const_row(A, i), indperm), w);
double norm_row = gmm::vect_norm2(mat_const_row(A, i));
typename _wsvector::iterator wkold = w.end();
for (typename _wsvector::iterator wk = w.begin();
wk != w.end() && wk->first < i; ) {
size_type k = wk->first;
tmp = (wk->second) * indiag[k];
if (gmm::abs(tmp) < eps * norm_row) w.erase(k);
else { wk->second += tmp; gmm::add(scaled(mat_row(U, k), -tmp), w); }
if (wkold == w.end()) wk = w.begin(); else { wk = wkold; ++wk; }
if (wk != w.end() && wk->first == k)
{ if (wkold == w.end()) wkold = w.begin(); else ++wkold; ++wk; }
}
gmm::clean(w, eps * norm_row);
gmm::copy(w, ww);
std::sort(ww.begin(), ww.end(), elt_rsvector_value_less_<T>());
typename _rsvector::const_iterator wit = ww.begin(), wite = ww.end();
size_type ip = size_type(-1);
for (; wit != wite; ++wit)
if (wit->c >= i) { ip = wit->c; tmp = wit->e; break; }
if (ip == size_type(-1) || gmm::abs(tmp) <= max_pivot)
{ GMM_WARNING2("pivot " << i << " too small"); ip=i; ww[i]=tmp=T(1); }
max_pivot = std::max(max_pivot, std::min(gmm::abs(tmp) * prec, R(1)));
indiag[i] = T(1) / tmp;
wit = ww.begin();
size_type nnl = 0, nnu = 0;
L[i].base_resize(K); U[i].base_resize(K+1);
typename _rsvector::iterator witL = L[i].begin(), witU = U[i].begin();
for (; wit != wite; ++wit) {
if (wit->c < i) { if (nnl < K) { *witL++ = *wit; ++nnl; } }
else if (nnu < K || wit->c == i)
{ CU(i, wit->c) = wit->e; *witU++ = *wit; ++nnu; }
}
L[i].base_resize(nnl); U[i].base_resize(nnu);
std::sort(L[i].begin(), L[i].end());
std::sort(U[i].begin(), U[i].end());
if (ip != i) {
typename _wsvector::const_iterator iti = CU.col(i).begin();
typename _wsvector::const_iterator itie = CU.col(i).end();
typename _wsvector::const_iterator itp = CU.col(ip).begin();
typename _wsvector::const_iterator itpe = CU.col(ip).end();
while (iti != itie && itp != itpe) {
if (iti->first < itp->first)
{ U.row(iti->first).swap_indices(i, ip); ++iti; }
else if (iti->first > itp->first)
{ U.row(itp->first).swap_indices(i,ip);++itp; }
else
{ U.row(iti->first).swap_indices(i, ip); ++iti; ++itp; }
}
for( ; iti != itie; ++iti) U.row(iti->first).swap_indices(i, ip);
for( ; itp != itpe; ++itp) U.row(itp->first).swap_indices(i, ip);
CU.swap_col(i, ip);
indperm.swap(i, ip);
indperminv.swap(ipvt[i], ipvt[ip]);
std::swap(ipvtinv[ipvt[i]], ipvtinv[ipvt[ip]]);
std::swap(ipvt[i], ipvt[ip]);
}
}
}
template<typename Matrix>
void ilutp_precond<Matrix>::do_ilutp(const Matrix& A, col_major) {
do_ilutp(gmm::transposed(A), row_major());
invert = true;
}
template <typename Matrix, typename V1, typename V2> inline
void mult(const ilutp_precond<Matrix>& P, const V1 &v1, V2 &v2) {
if (P.invert) {
gmm::copy(gmm::sub_vector(v1, P.indperm), v2);
gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
}
else {
gmm::copy(v1, P.temporary);
gmm::lower_tri_solve(P.L, P.temporary, true);
gmm::upper_tri_solve(P.U, P.temporary, false);
gmm::copy(gmm::sub_vector(P.temporary, P.indperminv), v2);
}
}
template <typename Matrix, typename V1, typename V2> inline
void transposed_mult(const ilutp_precond<Matrix>& P,const V1 &v1,V2 &v2) {
if (P.invert) {
gmm::copy(v1, P.temporary);
gmm::lower_tri_solve(P.L, P.temporary, true);
gmm::upper_tri_solve(P.U, P.temporary, false);
gmm::copy(gmm::sub_vector(P.temporary, P.indperminv), v2);
}
else {
gmm::copy(gmm::sub_vector(v1, P.indperm), v2);
gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
}
}
template <typename Matrix, typename V1, typename V2> inline
void left_mult(const ilutp_precond<Matrix>& P, const V1 &v1, V2 &v2) {
if (P.invert) {
gmm::copy(gmm::sub_vector(v1, P.indperm), v2);
gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
}
else {
copy(v1, v2);
gmm::lower_tri_solve(P.L, v2, true);
}
}
template <typename Matrix, typename V1, typename V2> inline
void right_mult(const ilutp_precond<Matrix>& P, const V1 &v1, V2 &v2) {
if (P.invert) {
copy(v1, v2);
gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
}
else {
copy(v1, P.temporary);
gmm::upper_tri_solve(P.U, P.temporary, false);
gmm::copy(gmm::sub_vector(P.temporary, P.indperminv), v2);
}
}
template <typename Matrix, typename V1, typename V2> inline
void transposed_left_mult(const ilutp_precond<Matrix>& P, const V1 &v1,
V2 &v2) {
if (P.invert) {
copy(v1, P.temporary);
gmm::upper_tri_solve(P.U, P.temporary, false);
gmm::copy(gmm::sub_vector(P.temporary, P.indperminv), v2);
}
else {
copy(v1, v2);
gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
}
}
template <typename Matrix, typename V1, typename V2> inline
void transposed_right_mult(const ilutp_precond<Matrix>& P, const V1 &v1,
V2 &v2) {
if (P.invert) {
copy(v1, v2);
gmm::lower_tri_solve(P.L, v2, true);
}
else {
gmm::copy(gmm::sub_vector(v1, P.indperm), v2);
gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
}
}
}
#endif

View File

@ -0,0 +1,149 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
// This file is a modified version of approximate_inverse.h from ITL.
// See http://osl.iu.edu/research/itl/
// Following the corresponding Copyright notice.
//===========================================================================
//
// Copyright (c) 1998-2001, University of Notre Dame. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the University of Notre Dame nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//===========================================================================
/**@file gmm_precond_mr_approx_inverse.h
@author Andrew Lumsdaine <lums@osl.iu.edu>
@author Lie-Quan Lee <llee@osl.iu.edu>
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date June 5, 2003.
@brief Approximate inverse via MR iteration.
*/
#ifndef GMM_PRECOND_MR_APPROX_INVERSE_H
#define GMM_PRECOND_MR_APPROX_INVERSE_H
#include "gmm_precond.h"
namespace gmm {
/** Approximate inverse via MR iteration (see P301 of Saad book).
*/
template <typename Matrix>
struct mr_approx_inverse_precond {
typedef typename linalg_traits<Matrix>::value_type value_type;
typedef typename number_traits<value_type>::magnitude_type magnitude_type;
typedef typename principal_orientation_type<typename
linalg_traits<Matrix>::sub_orientation>::potype sub_orientation;
typedef wsvector<value_type> VVector;
typedef col_matrix<VVector> MMatrix;
MMatrix M;
size_type nb_it;
magnitude_type threshold;
void build_with(const Matrix& A);
mr_approx_inverse_precond(const Matrix& A, size_type nb_it_,
magnitude_type threshold_)
: M(mat_nrows(A), mat_ncols(A))
{ threshold = threshold_; nb_it = nb_it_; build_with(A); }
mr_approx_inverse_precond(void)
{ threshold = magnitude_type(1E-7); nb_it = 5; }
mr_approx_inverse_precond(size_type nb_it_, magnitude_type threshold_)
{ threshold = threshold_; nb_it = nb_it_; }
const MMatrix &approx_inverse(void) const { return M; }
};
template <typename Matrix, typename V1, typename V2> inline
void mult(const mr_approx_inverse_precond<Matrix>& P, const V1 &v1, V2 &v2)
{ mult(P.M, v1, v2); }
template <typename Matrix, typename V1, typename V2> inline
void transposed_mult(const mr_approx_inverse_precond<Matrix>& P,
const V1 &v1,V2 &v2)
{ mult(gmm::conjugated(P.M), v1, v2); }
template <typename Matrix>
void mr_approx_inverse_precond<Matrix>::build_with(const Matrix& A) {
gmm::resize(M, mat_nrows(A), mat_ncols(A));
typedef value_type T;
typedef magnitude_type R;
VVector m(mat_ncols(A)),r(mat_ncols(A)),ei(mat_ncols(A)),Ar(mat_ncols(A));
T alpha = mat_trace(A)/ mat_euclidean_norm_sqr(A);
if (alpha == T(0)) alpha = T(1);
for (size_type i = 0; i < mat_nrows(A); ++i) {
gmm::clear(m); gmm::clear(ei);
m[i] = alpha;
ei[i] = T(1);
for (size_type j = 0; j < nb_it; ++j) {
gmm::mult(A, gmm::scaled(m, T(-1)), r);
gmm::add(ei, r);
gmm::mult(A, r, Ar);
T nAr = vect_sp(Ar,Ar);
if (gmm::abs(nAr) > R(0)) {
gmm::add(gmm::scaled(r, gmm::safe_divide(vect_sp(r, Ar), vect_sp(Ar, Ar))), m);
gmm::clean(m, threshold * gmm::vect_norm2(m));
} else gmm::clear(m);
}
if (gmm::vect_norm2(m) == R(0)) m[i] = alpha;
gmm::copy(m, M.col(i));
}
}
}
#endif

499
gmm/gmm_range_basis.h Normal file
View File

@ -0,0 +1,499 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2009-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_range_basis.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date March 10, 2009.
@brief Extract a basis of the range of a (large sparse) matrix from the
columns of this matrix.
*/
#ifndef GMM_RANGE_BASIS_H
#define GMM_RANGE_BASIS_H
#include "gmm_dense_qr.h"
#include "gmm_dense_lu.h"
#include "gmm_kernel.h"
#include "gmm_iter.h"
#include <set>
#include <list>
namespace gmm {
template <typename T, typename VECT, typename MAT1>
void tridiag_qr_algorithm
(std::vector<typename number_traits<T>::magnitude_type> diag,
std::vector<T> sdiag, const VECT &eigval_, const MAT1 &eigvect_,
bool compvect, tol_type_for_qr tol = default_tol_for_qr) {
VECT &eigval = const_cast<VECT &>(eigval_);
MAT1 &eigvect = const_cast<MAT1 &>(eigvect_);
typedef typename number_traits<T>::magnitude_type R;
if (compvect) gmm::copy(identity_matrix(), eigvect);
size_type n = diag.size(), q = 0, p, ite = 0;
if (n == 0) return;
if (n == 1) { eigval[0] = gmm::real(diag[0]); return; }
symmetric_qr_stop_criterion(diag, sdiag, p, q, tol);
while (q < n) {
sub_interval SUBI(p, n-p-q), SUBJ(0, mat_ncols(eigvect)), SUBK(p, n-p-q);
if (!compvect) SUBK = sub_interval(0,0);
symmetric_Wilkinson_qr_step(sub_vector(diag, SUBI),
sub_vector(sdiag, SUBI),
sub_matrix(eigvect, SUBJ, SUBK), compvect);
symmetric_qr_stop_criterion(diag, sdiag, p, q, tol*R(3));
++ite;
GMM_ASSERT1(ite < n*100, "QR algorithm failed.");
}
gmm::copy(diag, eigval);
}
// Range basis with a restarted Lanczos method
template <typename Mat>
void range_basis_eff_Lanczos(const Mat &BB, std::set<size_type> &columns,
double EPS=1E-12) {
typedef std::set<size_type> TAB;
typedef typename linalg_traits<Mat>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type nc_r = columns.size(), k;
col_matrix< rsvector<T> > B(mat_nrows(BB), mat_ncols(BB));
k = 0;
for (TAB::iterator it = columns.begin(); it!=columns.end(); ++it, ++k){
gmm::copy(scaled(mat_col(BB, *it), T(1)/vect_norm2(mat_col(BB, *it))),
mat_col(B, *it));
}
std::vector<T> w(mat_nrows(B));
size_type restart = 120;
std::vector<T> sdiag(restart);
std::vector<R> eigval(restart), diag(restart);
dense_matrix<T> eigvect(restart, restart);
R rho = R(-1), rho2;
while (nc_r) {
std::vector<T> v(nc_r), v0(nc_r), wl(nc_r);
dense_matrix<T> lv(nc_r, restart);
if (rho < R(0)) { // Estimate of the spectral radius of B^* B
gmm::fill_random(v);
for (size_type i = 0; i < 100; ++i) {
gmm::scale(v, T(1)/vect_norm2(v));
gmm::copy(v, v0);
k = 0; gmm::clear(w);
for (TAB::iterator it=columns.begin(); it!=columns.end(); ++it, ++k)
add(scaled(mat_col(B, *it), v[k]), w);
k = 0;
for (TAB::iterator it=columns.begin(); it!=columns.end(); ++it, ++k)
v[k] = vect_hp(w, mat_col(B, *it));
rho = gmm::abs(vect_hp(v, v0) / vect_hp(v0, v0));
}
rho *= R(2);
}
// Computing vectors of the null space of de B^* B with restarted Lanczos
rho2 = 0;
gmm::fill_random(v);
size_type iter = 0;
for(;;++iter) {
R rho_old = rho2;
R beta = R(0), alpha;
gmm::scale(v, T(1)/vect_norm2(v));
size_type eff_restart = restart;
if (sdiag.size() != restart) {
sdiag.resize(restart); eigval.resize(restart); diag.resize(restart); gmm::resize(eigvect, restart, restart);
gmm::resize(lv, nc_r, restart);
}
for (size_type i = 0; i < restart; ++i) { // Lanczos iterations
gmm::copy(v, mat_col(lv, i));
gmm::clear(w);
k = 0;
for (TAB::iterator it=columns.begin(); it!=columns.end(); ++it, ++k)
add(scaled(mat_col(B, *it), v[k]), w);
k = 0;
for (TAB::iterator it=columns.begin(); it!=columns.end(); ++it, ++k)
wl[k] = v[k]*rho - vect_hp(w, mat_col(B, *it)) - beta*v0[k];
alpha = gmm::real(vect_hp(wl, v));
diag[i] = alpha;
gmm::add(gmm::scaled(v, -alpha), wl);
sdiag[i] = beta = vect_norm2(wl);
gmm::copy(v, v0);
if (beta < EPS) { eff_restart = i+1; break; }
gmm::copy(gmm::scaled(wl, T(1) / beta), v);
}
if (eff_restart != restart) {
sdiag.resize(eff_restart); eigval.resize(eff_restart); diag.resize(eff_restart);
gmm::resize(eigvect, eff_restart, eff_restart); gmm::resize(lv, nc_r, eff_restart);
}
tridiag_qr_algorithm(diag, sdiag, eigval, eigvect, true);
size_type num = size_type(-1);
rho2 = R(0);
for (size_type j = 0; j < eff_restart; ++j)
{ R nvp=gmm::abs(eigval[j]); if (nvp > rho2) { rho2=nvp; num=j; }}
GMM_ASSERT1(num != size_type(-1), "Internal error");
gmm::mult(lv, mat_col(eigvect, num), v);
if (gmm::abs(rho2-rho_old) < rho_old*R(EPS)) break;
// if (gmm::abs(rho-rho2) < rho*R(gmm::sqrt(EPS))) break;
if (gmm::abs(rho-rho2) < rho*R(EPS)*R(100)) break;
}
if (gmm::abs(rho-rho2) < rho*R(EPS*10.)) {
size_type j_max = size_type(-1), j = 0;
R val_max = R(0);
for (TAB::iterator it=columns.begin(); it!=columns.end(); ++it, ++j)
if (gmm::abs(v[j]) > val_max)
{ val_max = gmm::abs(v[j]); j_max = *it; }
columns.erase(j_max); nc_r = columns.size();
}
else break;
}
}
// Range basis with LU decomposition. Not stable from a numerical viewpoint.
// Complex version not verified
template <typename Mat>
void range_basis_eff_lu(const Mat &B, std::set<size_type> &columns,
std::vector<bool> &c_ortho, double EPS) {
typedef std::set<size_type> TAB;
typedef typename linalg_traits<Mat>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type nc_r = 0, nc_o = 0, nc = mat_ncols(B), nr = mat_nrows(B), i, j;
for (TAB::iterator it=columns.begin(); it!=columns.end(); ++it)
if (!(c_ortho[*it])) ++nc_r; else nc_o++;
if (nc_r > 0) {
gmm::row_matrix< gmm::rsvector<T> > Hr(nc, nc_r), Ho(nc, nc_o);
gmm::row_matrix< gmm::rsvector<T> > BBr(nr, nc_r), BBo(nr, nc_o);
i = j = 0;
for (TAB::iterator it=columns.begin(); it!=columns.end(); ++it)
if (!(c_ortho[*it]))
{ Hr(*it, i) = T(1)/ vect_norminf(mat_col(B, *it)); ++i; }
else
{ Ho(*it, j) = T(1)/ vect_norm2(mat_col(B, *it)); ++j; }
gmm::mult(B, Hr, BBr);
gmm::mult(B, Ho, BBo);
gmm::dense_matrix<T> M(nc_r, nc_r), BBB(nc_r, nc_o), MM(nc_r, nc_r);
gmm::mult(gmm::conjugated(BBr), BBr, M);
gmm::mult(gmm::conjugated(BBr), BBo, BBB);
gmm::mult(BBB, gmm::conjugated(BBB), MM);
gmm::add(gmm::scaled(MM, T(-1)), M);
std::vector<int> ipvt(nc_r);
gmm::lu_factor(M, ipvt);
R emax = R(0);
for (i = 0; i < nc_r; ++i) emax = std::max(emax, gmm::abs(M(i,i)));
i = 0;
std::set<size_type> c = columns;
for (TAB::iterator it = c.begin(); it != c.end(); ++it)
if (!(c_ortho[*it])) {
if (gmm::abs(M(i,i)) <= R(EPS)*emax) columns.erase(*it);
++i;
}
}
}
// Range basis with Gram-Schmidt orthogonalization (sparse version)
// The sparse version is better when the sparsity is high and less efficient
// than the dense version for high degree elements (P3, P4 ...)
// Complex version not verified
template <typename Mat>
void range_basis_eff_Gram_Schmidt_sparse(const Mat &BB,
std::set<size_type> &columns,
std::vector<bool> &c_ortho,
double EPS) {
typedef std::set<size_type> TAB;
typedef typename linalg_traits<Mat>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type nc = mat_ncols(BB), nr = mat_nrows(BB);
std::set<size_type> c = columns, rc = columns;
gmm::col_matrix< rsvector<T> > B(nr, nc);
for (std::set<size_type>::iterator it = columns.begin();
it != columns.end(); ++it) {
gmm::copy(mat_col(BB, *it), mat_col(B, *it));
gmm::scale(mat_col(B, *it), T(1)/vect_norm2(mat_col(B, *it)));
}
for (std::set<size_type>::iterator it = c.begin(); it != c.end(); ++it)
if (c_ortho[*it]) {
for (std::set<size_type>::iterator it2 = rc.begin();
it2 != rc.end(); ++it2)
if (!(c_ortho[*it2])) {
T r = -vect_hp(mat_col(B, *it2), mat_col(B, *it));
if (r != T(0)) add(scaled(mat_col(B, *it), r), mat_col(B, *it2));
}
rc.erase(*it);
}
while (rc.size()) {
R nmax = R(0); size_type cmax = size_type(-1);
for (std::set<size_type>::iterator it=rc.begin(); it != rc.end();) {
TAB::iterator itnext = it; ++itnext;
R n = vect_norm2(mat_col(B, *it));
if (nmax < n) { nmax = n; cmax = *it; }
if (n < R(EPS)) { columns.erase(*it); rc.erase(*it); }
it = itnext;
}
if (nmax < R(EPS)) break;
gmm::scale(mat_col(B, cmax), T(1)/vect_norm2(mat_col(B, cmax)));
rc.erase(cmax);
for (std::set<size_type>::iterator it=rc.begin(); it!=rc.end(); ++it) {
T r = -vect_hp(mat_col(B, *it), mat_col(B, cmax));
if (r != T(0)) add(scaled(mat_col(B, cmax), r), mat_col(B, *it));
}
}
for (std::set<size_type>::iterator it=rc.begin(); it!=rc.end(); ++it)
columns.erase(*it);
}
// Range basis with Gram-Schmidt orthogonalization (dense version)
template <typename Mat>
void range_basis_eff_Gram_Schmidt_dense(const Mat &B,
std::set<size_type> &columns,
std::vector<bool> &c_ortho,
double EPS) {
typedef std::set<size_type> TAB;
typedef typename linalg_traits<Mat>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type nc_r = columns.size(), nc = mat_ncols(B), nr = mat_nrows(B), i;
std::set<size_type> rc;
row_matrix< gmm::rsvector<T> > H(nc, nc_r), BB(nr, nc_r);
std::vector<T> v(nc_r);
std::vector<size_type> ind(nc_r);
i = 0;
for (TAB::iterator it = columns.begin(); it != columns.end(); ++it, ++i)
H(*it, i) = T(1) / vect_norm2(mat_col(B, *it));
mult(B, H, BB);
dense_matrix<T> M(nc_r, nc_r);
mult(gmm::conjugated(BB), BB, M);
i = 0;
for (TAB::iterator it = columns.begin(); it != columns.end(); ++it, ++i)
if (c_ortho[*it]) {
gmm::copy(mat_row(M, i), v);
rank_one_update(M, scaled(v, T(-1)), v);
M(i, i) = T(1);
}
else { rc.insert(i); ind[i] = *it; }
while (rc.size() > 0) {
// Next pivot
R nmax = R(0); size_type imax = size_type(-1);
for (TAB::iterator it = rc.begin(); it != rc.end();) {
TAB::iterator itnext = it; ++itnext;
R a = gmm::abs(M(*it, *it));
if (a > nmax) { nmax = a; imax = *it; }
if (a < R(EPS)) { columns.erase(ind[*it]); rc.erase(*it); }
it = itnext;
}
if (nmax < R(EPS)) break;
// Normalization
gmm::scale(mat_row(M, imax), T(1) / sqrt(nmax));
gmm::scale(mat_col(M, imax), T(1) / sqrt(nmax));
// orthogonalization
copy(mat_row(M, imax), v);
rank_one_update(M, scaled(v, T(-1)), v);
M(imax, imax) = T(1);
rc.erase(imax);
}
for (std::set<size_type>::iterator it=rc.begin(); it!=rc.end(); ++it)
columns.erase(ind[*it]);
}
template <typename L> size_type nnz_eps(const L& l, double eps) {
typename linalg_traits<L>::const_iterator it = vect_const_begin(l),
ite = vect_const_end(l);
size_type res(0);
for (; it != ite; ++it) if (gmm::abs(*it) >= eps) ++res;
return res;
}
template <typename L>
bool reserve__rb(const L& l, std::vector<bool> &b, double eps) {
typename linalg_traits<L>::const_iterator it = vect_const_begin(l),
ite = vect_const_end(l);
bool ok = true;
for (; it != ite; ++it)
if (gmm::abs(*it) >= eps && b[it.index()]) ok = false;
if (ok) {
for (it = vect_const_begin(l); it != ite; ++it)
if (gmm::abs(*it) >= eps) b[it.index()] = true;
}
return ok;
}
template <typename Mat>
void range_basis(const Mat &B, std::set<size_type> &columns,
double EPS, col_major, bool skip_init=false) {
typedef typename linalg_traits<Mat>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type nc = mat_ncols(B), nr = mat_nrows(B);
std::vector<R> norms(nc);
std::vector<bool> c_ortho(nc), booked(nr);
std::vector< std::set<size_type> > nnzs(mat_nrows(B));
if (!skip_init) {
R norm_max = R(0);
for (size_type i = 0; i < nc; ++i) {
norms[i] = vect_norminf(mat_col(B, i));
norm_max = std::max(norm_max, norms[i]);
}
columns.clear();
for (size_type i = 0; i < nc; ++i)
if (norms[i] > norm_max*R(EPS)) {
columns.insert(i);
nnzs[nnz_eps(mat_col(B, i), R(EPS) * norms[i])].insert(i);
}
for (size_type i = 1; i < nr; ++i)
for (std::set<size_type>::iterator it = nnzs[i].begin();
it != nnzs[i].end(); ++it)
if (reserve__rb(mat_col(B, *it), booked, R(EPS) * norms[*it]))
c_ortho[*it] = true;
}
size_type sizesm[7] = {125, 200, 350, 550, 800, 1100, 1500}, actsize;
for (int k = 0; k < 7; ++k) {
size_type nc_r = columns.size();
std::set<size_type> c1, cres;
actsize = sizesm[k];
for (std::set<size_type>::iterator it = columns.begin();
it != columns.end(); ++it) {
c1.insert(*it);
if (c1.size() >= actsize) {
range_basis_eff_Gram_Schmidt_dense(B, c1, c_ortho, EPS);
for (std::set<size_type>::iterator it2=c1.begin(); it2 != c1.end();
++it2) cres.insert(*it2);
c1.clear();
}
}
if (c1.size() > 1)
range_basis_eff_Gram_Schmidt_dense(B, c1, c_ortho, EPS);
for (std::set<size_type>::iterator it = c1.begin(); it != c1.end(); ++it)
cres.insert(*it);
columns = cres;
if (nc_r <= actsize) return;
if (columns.size() == nc_r) break;
if (sizesm[k] >= 350 && columns.size() > (nc_r*19)/20) break;
}
if (columns.size() > std::max(size_type(10), actsize))
range_basis_eff_Lanczos(B, columns, EPS);
else
range_basis_eff_Gram_Schmidt_dense(B, columns, c_ortho, EPS);
}
template <typename Mat>
void range_basis(const Mat &B, std::set<size_type> &columns,
double EPS, row_major) {
typedef typename linalg_traits<Mat>::value_type T;
gmm::col_matrix< rsvector<T> > BB(mat_nrows(B), mat_ncols(B));
GMM_WARNING3("A copy of a row matrix is done into a column matrix "
"for range basis algorithm.");
gmm::copy(B, BB);
range_basis(BB, columns, EPS);
}
/** Range Basis :
Extract a basis of the range of a (large sparse) matrix selecting some
column vectors of this matrix. This is in particular useful to select
an independent set of linear constraints.
The algorithm is optimized for two cases :
- when the (non trivial) kernel is small. An iterativ algorithm
based on Lanczos method is applied
- when the (non trivial) kernel is large and most of the dependencies
can be detected locally. A block Gram-Schmidt is applied first then
a restarted Lanczos method when the remaining kernel is greatly
smaller.
The restarted Lanczos method could be improved or replaced by a block
Lanczos method, a block Wiedelann method (in order to be parallelized for
instance) or simply could compute more than one vector of the null
space at each iteration.
The LU decomposition has been tested for local elimination but gives bad
results : the algorithm is unstable and do not permit to give the right
number of vector at the end of the process. Moreover, the number of final
vectors depends greatly on the number of vectors in a block of the local
analysis.
*/
template <typename Mat>
void range_basis(const Mat &B, std::set<size_type> &columns,
double EPS=1E-12) {
range_basis(B, columns, EPS,
typename principal_orientation_type
<typename linalg_traits<Mat>::sub_orientation>::potype());
}
}
#endif

605
gmm/gmm_real_part.h Normal file
View File

@ -0,0 +1,605 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2003-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_real_part.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date September 18, 2003.
@brief extract the real/imaginary part of vectors/matrices
*/
#ifndef GMM_REAL_PART_H
#define GMM_REAL_PART_H
#include "gmm_def.h"
#include "gmm_vector.h"
namespace gmm {
struct linalg_real_part {};
struct linalg_imag_part {};
template <typename R, typename PART> struct which_part {};
template <typename C> typename number_traits<C>::magnitude_type
real_or_imag_part(C x, linalg_real_part) { return gmm::real(x); }
template <typename C> typename number_traits<C>::magnitude_type
real_or_imag_part(C x, linalg_imag_part) { return gmm::imag(x); }
template <typename T, typename C, typename OP> C
complex_from(T x, C y, OP op, linalg_real_part) { return std::complex<T>(op(std::real(y), x), std::imag(y)); }
template <typename T, typename C, typename OP> C
complex_from(T x, C y, OP op,linalg_imag_part) { return std::complex<T>(std::real(y), op(std::imag(y), x)); }
template<typename T> struct project2nd {
T operator()(T , T b) const { return b; }
};
template<typename T, typename R, typename PART> class ref_elt_vector<T, which_part<R, PART> > {
R r;
public :
operator T() const { return real_or_imag_part(std::complex<T>(r), PART()); }
ref_elt_vector(R r_) : r(r_) {}
inline ref_elt_vector &operator =(T v)
{ r = complex_from(v, std::complex<T>(r), gmm::project2nd<T>(), PART()); return *this; }
inline bool operator ==(T v) const { return (r == v); }
inline bool operator !=(T v) const { return (r != v); }
inline ref_elt_vector &operator +=(T v)
{ r = complex_from(v, std::complex<T>(r), std::plus<T>(), PART()); return *this; }
inline ref_elt_vector &operator -=(T v)
{ r = complex_from(v, std::complex<T>(r), std::minus<T>(), PART()); return *this; }
inline ref_elt_vector &operator /=(T v)
{ r = complex_from(v, std::complex<T>(r), std::divides<T>(), PART()); return *this; }
inline ref_elt_vector &operator *=(T v)
{ r = complex_from(v, std::complex<T>(r), std::multiplies<T>(), PART()); return *this; }
inline ref_elt_vector &operator =(const ref_elt_vector &re)
{ *this = T(re); return *this; }
T operator +() { return T(*this); } // necessary for unknow reason
T operator -() { return -T(*this); } // necessary for unknow reason
T operator +(T v) { return T(*this)+ v; } // necessary for unknow reason
T operator -(T v) { return T(*this)- v; } // necessary for unknow reason
T operator *(T v) { return T(*this)* v; } // necessary for unknow reason
T operator /(T v) { return T(*this)/ v; } // necessary for unknow reason
};
template<typename reference> struct ref_or_value_type {
template <typename T, typename W>
static W r(const T &x, linalg_real_part, W) {
return gmm::real(x);
}
template <typename T, typename W>
static W r(const T &x, linalg_imag_part, W) {
return gmm::imag(x);
}
};
template<typename U, typename R, typename PART>
struct ref_or_value_type<ref_elt_vector<U, which_part<R, PART> > > {
template<typename T , typename W>
static const T &r(const T &x, linalg_real_part, W)
{ return x; }
template<typename T, typename W>
static const T &r(const T &x, linalg_imag_part, W) {
return x;
}
template<typename T , typename W>
static T &r(T &x, linalg_real_part, W)
{ return x; }
template<typename T, typename W>
static T &r(T &x, linalg_imag_part, W) {
return x;
}
};
/* ********************************************************************* */
/* Reference to the real part of (complex) vectors */
/* ********************************************************************* */
template <typename IT, typename MIT, typename PART>
struct part_vector_iterator {
typedef typename std::iterator_traits<IT>::value_type vtype;
typedef typename gmm::number_traits<vtype>::magnitude_type value_type;
typedef value_type *pointer;
typedef ref_elt_vector<value_type, which_part<typename std::iterator_traits<IT>::reference, PART> > reference;
typedef typename std::iterator_traits<IT>::difference_type difference_type;
typedef typename std::iterator_traits<IT>::iterator_category
iterator_category;
IT it;
part_vector_iterator(void) {}
explicit part_vector_iterator(const IT &i) : it(i) {}
part_vector_iterator(const part_vector_iterator<MIT, MIT, PART> &i) : it(i.it) {}
size_type index(void) const { return it.index(); }
part_vector_iterator operator ++(int)
{ part_vector_iterator tmp = *this; ++it; return tmp; }
part_vector_iterator operator --(int)
{ part_vector_iterator tmp = *this; --it; return tmp; }
part_vector_iterator &operator ++() { ++it; return *this; }
part_vector_iterator &operator --() { --it; return *this; }
part_vector_iterator &operator +=(difference_type i)
{ it += i; return *this; }
part_vector_iterator &operator -=(difference_type i)
{ it -= i; return *this; }
part_vector_iterator operator +(difference_type i) const
{ part_vector_iterator itb = *this; return (itb += i); }
part_vector_iterator operator -(difference_type i) const
{ part_vector_iterator itb = *this; return (itb -= i); }
difference_type operator -(const part_vector_iterator &i) const
{ return difference_type(it - i.it); }
reference operator *() const { return reference(*it); }
reference operator [](size_type ii) const { return reference(it[ii]); }
bool operator ==(const part_vector_iterator &i) const
{ return (i.it == it); }
bool operator !=(const part_vector_iterator &i) const
{ return (i.it != it); }
bool operator < (const part_vector_iterator &i) const
{ return (it < i.it); }
};
template <typename PT, typename PART> struct part_vector {
typedef part_vector<PT, PART> this_type;
typedef typename std::iterator_traits<PT>::value_type V;
typedef V * CPT;
typedef typename select_ref<typename linalg_traits<V>::const_iterator,
typename linalg_traits<V>::iterator, PT>::ref_type iterator;
typedef typename linalg_traits<this_type>::reference reference;
typedef typename linalg_traits<this_type>::value_type value_type;
typedef typename linalg_traits<this_type>::porigin_type porigin_type;
iterator begin_, end_;
porigin_type origin;
size_type size_;
size_type size(void) const { return size_; }
reference operator[](size_type i) const {
return reference(ref_or_value_type<reference>::r(
linalg_traits<V>::access(origin, begin_, end_, i),
PART(), value_type()));
}
part_vector(V &v)
: begin_(vect_begin(v)), end_(vect_end(v)),
origin(linalg_origin(v)), size_(gmm::vect_size(v)) {}
part_vector(const V &v)
: begin_(vect_begin(const_cast<V &>(v))),
end_(vect_end(const_cast<V &>(v))),
origin(linalg_origin(const_cast<V &>(v))), size_(gmm::vect_size(v)) {}
part_vector() {}
part_vector(const part_vector<CPT, PART> &cr)
: begin_(cr.begin_),end_(cr.end_),origin(cr.origin), size_(cr.size_) {}
};
template <typename IT, typename MIT, typename ORG, typename PT,
typename PART> inline
void set_to_begin(part_vector_iterator<IT, MIT, PART> &it,
ORG o, part_vector<PT, PART> *, linalg_modifiable) {
typedef part_vector<PT, PART> VECT;
typedef typename linalg_traits<VECT>::V_reference ref_t;
set_to_begin(it.it, o, typename linalg_traits<VECT>::pV(), ref_t());
}
template <typename IT, typename MIT, typename ORG, typename PT,
typename PART> inline
void set_to_begin(part_vector_iterator<IT, MIT, PART> &it,
ORG o, const part_vector<PT, PART> *, linalg_modifiable) {
typedef part_vector<PT, PART> VECT;
typedef typename linalg_traits<VECT>::V_reference ref_t;
set_to_begin(it.it, o, typename linalg_traits<VECT>::pV(), ref_t());
}
template <typename IT, typename MIT, typename ORG, typename PT,
typename PART> inline
void set_to_end(part_vector_iterator<IT, MIT, PART> &it,
ORG o, part_vector<PT, PART> *, linalg_modifiable) {
typedef part_vector<PT, PART> VECT;
typedef typename linalg_traits<VECT>::V_reference ref_t;
set_to_end(it.it, o, typename linalg_traits<VECT>::pV(), ref_t());
}
template <typename IT, typename MIT, typename ORG,
typename PT, typename PART> inline
void set_to_end(part_vector_iterator<IT, MIT, PART> &it,
ORG o, const part_vector<PT, PART> *,
linalg_modifiable) {
typedef part_vector<PT, PART> VECT;
typedef typename linalg_traits<VECT>::V_reference ref_t;
set_to_end(it.it, o, typename linalg_traits<VECT>::pV(), ref_t());
}
template <typename PT, typename PART> std::ostream &operator <<
(std::ostream &o, const part_vector<PT, PART>& m)
{ gmm::write(o,m); return o; }
/* ********************************************************************* */
/* Reference to the real or imaginary part of (complex) matrices */
/* ********************************************************************* */
template <typename PT, typename PART> struct part_row_ref {
typedef part_row_ref<PT, PART> this_type;
typedef typename std::iterator_traits<PT>::value_type M;
typedef M * CPT;
typedef typename std::iterator_traits<PT>::reference ref_M;
typedef typename select_ref<typename linalg_traits<this_type>
::const_row_iterator, typename linalg_traits<this_type>
::row_iterator, PT>::ref_type iterator;
typedef typename linalg_traits<this_type>::value_type value_type;
typedef typename linalg_traits<this_type>::reference reference;
typedef typename linalg_traits<this_type>::porigin_type porigin_type;
iterator begin_, end_;
porigin_type origin;
size_type nr, nc;
part_row_ref(ref_M m)
: begin_(mat_row_begin(m)), end_(mat_row_end(m)),
origin(linalg_origin(m)), nr(mat_nrows(m)), nc(mat_ncols(m)) {}
part_row_ref(const part_row_ref<CPT, PART> &cr) :
begin_(cr.begin_),end_(cr.end_), origin(cr.origin),nr(cr.nr),nc(cr.nc) {}
reference operator()(size_type i, size_type j) const {
return reference(ref_or_value_type<reference>::r(
linalg_traits<M>::access(begin_+i, j),
PART(), value_type()));
}
};
template<typename PT, typename PART> std::ostream &operator <<
(std::ostream &o, const part_row_ref<PT, PART>& m)
{ gmm::write(o,m); return o; }
template <typename PT, typename PART> struct part_col_ref {
typedef part_col_ref<PT, PART> this_type;
typedef typename std::iterator_traits<PT>::value_type M;
typedef M * CPT;
typedef typename std::iterator_traits<PT>::reference ref_M;
typedef typename select_ref<typename linalg_traits<this_type>
::const_col_iterator, typename linalg_traits<this_type>
::col_iterator, PT>::ref_type iterator;
typedef typename linalg_traits<this_type>::value_type value_type;
typedef typename linalg_traits<this_type>::reference reference;
typedef typename linalg_traits<this_type>::porigin_type porigin_type;
iterator begin_, end_;
porigin_type origin;
size_type nr, nc;
part_col_ref(ref_M m)
: begin_(mat_col_begin(m)), end_(mat_col_end(m)),
origin(linalg_origin(m)), nr(mat_nrows(m)), nc(mat_ncols(m)) {}
part_col_ref(const part_col_ref<CPT, PART> &cr) :
begin_(cr.begin_),end_(cr.end_), origin(cr.origin),nr(cr.nr),nc(cr.nc) {}
reference operator()(size_type i, size_type j) const {
return reference(ref_or_value_type<reference>::r(
linalg_traits<M>::access(begin_+j, i),
PART(), value_type()));
}
};
template<typename PT, typename PART> std::ostream &operator <<
(std::ostream &o, const part_col_ref<PT, PART>& m)
{ gmm::write(o,m); return o; }
template <typename TYPE, typename PART, typename PT>
struct part_return_ {
typedef abstract_null_type return_type;
};
template <typename PT, typename PART>
struct part_return_<row_major, PART, PT> {
typedef typename std::iterator_traits<PT>::value_type L;
typedef typename select_return<part_row_ref<const L *, PART>,
part_row_ref< L *, PART>, PT>::return_type return_type;
};
template <typename PT, typename PART>
struct part_return_<col_major, PART, PT> {
typedef typename std::iterator_traits<PT>::value_type L;
typedef typename select_return<part_col_ref<const L *, PART>,
part_col_ref<L *, PART>, PT>::return_type return_type;
};
template <typename PT, typename PART, typename LT> struct part_return__{
typedef abstract_null_type return_type;
};
template <typename PT, typename PART>
struct part_return__<PT, PART, abstract_matrix> {
typedef typename std::iterator_traits<PT>::value_type L;
typedef typename part_return_<typename principal_orientation_type<
typename linalg_traits<L>::sub_orientation>::potype, PART,
PT>::return_type return_type;
};
template <typename PT, typename PART>
struct part_return__<PT, PART, abstract_vector> {
typedef typename std::iterator_traits<PT>::value_type L;
typedef typename select_return<part_vector<const L *, PART>,
part_vector<L *, PART>, PT>::return_type return_type;
};
template <typename PT, typename PART> struct part_return {
typedef typename std::iterator_traits<PT>::value_type L;
typedef typename part_return__<PT, PART,
typename linalg_traits<L>::linalg_type>::return_type return_type;
};
template <typename L> inline
typename part_return<const L *, linalg_real_part>::return_type
real_part(const L &l) {
return typename part_return<const L *, linalg_real_part>::return_type
(linalg_cast(const_cast<L &>(l)));
}
template <typename L> inline
typename part_return<L *, linalg_real_part>::return_type
real_part(L &l) {
return typename part_return<L *, linalg_real_part>::return_type(linalg_cast(l));
}
template <typename L> inline
typename part_return<const L *, linalg_imag_part>::return_type
imag_part(const L &l) {
return typename part_return<const L *, linalg_imag_part>::return_type
(linalg_cast(const_cast<L &>(l)));
}
template <typename L> inline
typename part_return<L *, linalg_imag_part>::return_type
imag_part(L &l) {
return typename part_return<L *, linalg_imag_part>::return_type(linalg_cast(l));
}
template <typename PT, typename PART>
struct linalg_traits<part_vector<PT, PART> > {
typedef part_vector<PT, PART> this_type;
typedef this_type * pthis_type;
typedef PT pV;
typedef typename std::iterator_traits<PT>::value_type V;
typedef typename linalg_traits<V>::index_sorted index_sorted;
typedef typename linalg_traits<V>::is_reference V_reference;
typedef typename linalg_traits<V>::origin_type origin_type;
typedef typename select_ref<const origin_type *, origin_type *,
PT>::ref_type porigin_type;
typedef typename which_reference<PT>::is_reference is_reference;
typedef abstract_vector linalg_type;
typedef typename linalg_traits<V>::value_type vtype;
typedef typename number_traits<vtype>::magnitude_type value_type;
typedef typename select_ref<value_type, ref_elt_vector<value_type,
which_part<typename linalg_traits<V>::reference,
PART> >, PT>::ref_type reference;
typedef typename select_ref<typename linalg_traits<V>::const_iterator,
typename linalg_traits<V>::iterator, PT>::ref_type pre_iterator;
typedef typename select_ref<abstract_null_type,
part_vector_iterator<pre_iterator, pre_iterator, PART>,
PT>::ref_type iterator;
typedef part_vector_iterator<typename linalg_traits<V>::const_iterator,
pre_iterator, PART> const_iterator;
typedef typename linalg_traits<V>::storage_type storage_type;
static size_type size(const this_type &v) { return v.size(); }
static iterator begin(this_type &v) {
iterator it; it.it = v.begin_;
if (!is_const_reference(is_reference()) && is_sparse(storage_type()))
set_to_begin(it, v.origin, pthis_type(), is_reference());
return it;
}
static const_iterator begin(const this_type &v) {
const_iterator it(v.begin_);
if (!is_const_reference(is_reference()) && is_sparse(storage_type()))
{ set_to_begin(it, v.origin, pthis_type(), is_reference()); }
return it;
}
static iterator end(this_type &v) {
iterator it(v.end_);
if (!is_const_reference(is_reference()) && is_sparse(storage_type()))
set_to_end(it, v.origin, pthis_type(), is_reference());
return it;
}
static const_iterator end(const this_type &v) {
const_iterator it(v.end_);
if (!is_const_reference(is_reference()) && is_sparse(storage_type()))
set_to_end(it, v.origin, pthis_type(), is_reference());
return it;
}
static origin_type* origin(this_type &v) { return v.origin; }
static const origin_type* origin(const this_type &v) { return v.origin; }
static void clear(origin_type* o, const iterator &begin_,
const iterator &end_, abstract_sparse) {
std::deque<size_type> ind;
iterator it = begin_;
for (; it != end_; ++it) ind.push_front(it.index());
for (; !(ind.empty()); ind.pop_back())
access(o, begin_, end_, ind.back()) = value_type(0);
}
static void clear(origin_type* o, const iterator &begin_,
const iterator &end_, abstract_skyline) {
clear(o, begin_, end_, abstract_sparse());
}
static void clear(origin_type* o, const iterator &begin_,
const iterator &end_, abstract_dense) {
for (iterator it = begin_; it != end_; ++it) *it = value_type(0);
}
static void clear(origin_type* o, const iterator &begin_,
const iterator &end_)
{ clear(o, begin_, end_, storage_type()); }
static void do_clear(this_type &v) { clear(v.origin, begin(v), end(v)); }
static value_type access(const origin_type *o, const const_iterator &it,
const const_iterator &ite, size_type i) {
return real_or_imag_part(linalg_traits<V>::access(o, it.it, ite.it,i),
PART());
}
static reference access(origin_type *o, const iterator &it,
const iterator &ite, size_type i)
{ return reference(linalg_traits<V>::access(o, it.it, ite.it,i)); }
};
template <typename PT, typename PART>
struct linalg_traits<part_row_ref<PT, PART> > {
typedef part_row_ref<PT, PART> this_type;
typedef typename std::iterator_traits<PT>::value_type M;
typedef typename linalg_traits<M>::origin_type origin_type;
typedef typename select_ref<const origin_type *, origin_type *,
PT>::ref_type porigin_type;
typedef typename which_reference<PT>::is_reference is_reference;
typedef abstract_matrix linalg_type;
typedef typename linalg_traits<M>::value_type vtype;
typedef typename number_traits<vtype>::magnitude_type value_type;
typedef typename linalg_traits<M>::storage_type storage_type;
typedef abstract_null_type sub_col_type;
typedef abstract_null_type const_sub_col_type;
typedef abstract_null_type col_iterator;
typedef abstract_null_type const_col_iterator;
typedef typename org_type<typename linalg_traits<M>::const_sub_row_type>::t
pre_const_sub_row_type;
typedef typename org_type<typename linalg_traits<M>::sub_row_type>::t pre_sub_row_type;
typedef part_vector<const pre_const_sub_row_type *, PART>
const_sub_row_type;
typedef typename select_ref<abstract_null_type,
part_vector<pre_sub_row_type *, PART>, PT>::ref_type sub_row_type;
typedef typename linalg_traits<M>::const_row_iterator const_row_iterator;
typedef typename select_ref<abstract_null_type, typename
linalg_traits<M>::row_iterator, PT>::ref_type row_iterator;
typedef typename select_ref<
typename linalg_traits<const_sub_row_type>::reference,
typename linalg_traits<sub_row_type>::reference,
PT>::ref_type reference;
typedef row_major sub_orientation;
typedef typename linalg_traits<M>::index_sorted index_sorted;
static size_type ncols(const this_type &v) { return v.nc; }
static size_type nrows(const this_type &v) { return v.nr; }
static const_sub_row_type row(const const_row_iterator &it)
{ return const_sub_row_type(linalg_traits<M>::row(it)); }
static sub_row_type row(const row_iterator &it)
{ return sub_row_type(linalg_traits<M>::row(it)); }
static row_iterator row_begin(this_type &m) { return m.begin_; }
static row_iterator row_end(this_type &m) { return m.end_; }
static const_row_iterator row_begin(const this_type &m)
{ return m.begin_; }
static const_row_iterator row_end(const this_type &m) { return m.end_; }
static origin_type* origin(this_type &v) { return v.origin; }
static const origin_type* origin(const this_type &v) { return v.origin; }
static void do_clear(this_type &v);
static value_type access(const const_row_iterator &itrow, size_type i)
{ return real_or_imag_part(linalg_traits<M>::access(itrow, i), PART()); }
static reference access(const row_iterator &itrow, size_type i) {
return reference(ref_or_value_type<reference>::r(
linalg_traits<M>::access(itrow, i),
PART(), value_type()));
}
};
template <typename PT, typename PART>
struct linalg_traits<part_col_ref<PT, PART> > {
typedef part_col_ref<PT, PART> this_type;
typedef typename std::iterator_traits<PT>::value_type M;
typedef typename linalg_traits<M>::origin_type origin_type;
typedef typename select_ref<const origin_type *, origin_type *,
PT>::ref_type porigin_type;
typedef typename which_reference<PT>::is_reference is_reference;
typedef abstract_matrix linalg_type;
typedef typename linalg_traits<M>::value_type vtype;
typedef typename number_traits<vtype>::magnitude_type value_type;
typedef typename linalg_traits<M>::storage_type storage_type;
typedef abstract_null_type sub_row_type;
typedef abstract_null_type const_sub_row_type;
typedef abstract_null_type row_iterator;
typedef abstract_null_type const_row_iterator;
typedef typename org_type<typename linalg_traits<M>::const_sub_col_type>::t
pre_const_sub_col_type;
typedef typename org_type<typename linalg_traits<M>::sub_col_type>::t pre_sub_col_type;
typedef part_vector<const pre_const_sub_col_type *, PART>
const_sub_col_type;
typedef typename select_ref<abstract_null_type,
part_vector<pre_sub_col_type *, PART>, PT>::ref_type sub_col_type;
typedef typename linalg_traits<M>::const_col_iterator const_col_iterator;
typedef typename select_ref<abstract_null_type, typename
linalg_traits<M>::col_iterator, PT>::ref_type col_iterator;
typedef typename select_ref<
typename linalg_traits<const_sub_col_type>::reference,
typename linalg_traits<sub_col_type>::reference,
PT>::ref_type reference;
typedef col_major sub_orientation;
typedef typename linalg_traits<M>::index_sorted index_sorted;
static size_type nrows(const this_type &v) { return v.nr; }
static size_type ncols(const this_type &v) { return v.nc; }
static const_sub_col_type col(const const_col_iterator &it)
{ return const_sub_col_type(linalg_traits<M>::col(it)); }
static sub_col_type col(const col_iterator &it)
{ return sub_col_type(linalg_traits<M>::col(it)); }
static col_iterator col_begin(this_type &m) { return m.begin_; }
static col_iterator col_end(this_type &m) { return m.end_; }
static const_col_iterator col_begin(const this_type &m)
{ return m.begin_; }
static const_col_iterator col_end(const this_type &m) { return m.end_; }
static origin_type* origin(this_type &v) { return v.origin; }
static const origin_type* origin(const this_type &v) { return v.origin; }
static void do_clear(this_type &v);
static value_type access(const const_col_iterator &itcol, size_type i)
{ return real_or_imag_part(linalg_traits<M>::access(itcol, i), PART()); }
static reference access(const col_iterator &itcol, size_type i) {
return reference(ref_or_value_type<reference>::r(
linalg_traits<M>::access(itcol, i),
PART(), value_type()));
}
};
template <typename PT, typename PART>
void linalg_traits<part_col_ref<PT, PART> >::do_clear(this_type &v) {
col_iterator it = mat_col_begin(v), ite = mat_col_end(v);
for (; it != ite; ++it) clear(col(it));
}
template <typename PT, typename PART>
void linalg_traits<part_row_ref<PT, PART> >::do_clear(this_type &v) {
row_iterator it = mat_row_begin(v), ite = mat_row_end(v);
for (; it != ite; ++it) clear(row(it));
}
}
#endif // GMM_REAL_PART_H

526
gmm/gmm_ref.h Normal file
View File

@ -0,0 +1,526 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2000-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
#ifndef GMM_REF_H__
#define GMM_REF_H__
/** @file gmm_ref.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date August 26, 2000.
* @brief Provide some simple pseudo-containers.
*
* WARNING : modifiying the container infirm the validity of references.
*/
#include <iterator>
#include "gmm_except.h"
namespace gmm {
/* ********************************************************************* */
/* Simple reference. */
/* ********************************************************************* */
template<typename ITER> class tab_ref {
protected :
ITER begin_, end_;
public :
typedef typename std::iterator_traits<ITER>::value_type value_type;
typedef typename std::iterator_traits<ITER>::pointer pointer;
typedef typename std::iterator_traits<ITER>::pointer const_pointer;
typedef typename std::iterator_traits<ITER>::reference reference;
typedef typename std::iterator_traits<ITER>::reference const_reference;
typedef typename std::iterator_traits<ITER>::difference_type
difference_type;
typedef ITER iterator;
typedef ITER const_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef size_t size_type;
bool empty(void) const { return begin_ == end_; }
size_type size(void) const { return end_ - begin_; }
const iterator &begin(void) { return begin_; }
const const_iterator &begin(void) const { return begin_; }
const iterator &end(void) { return end_; }
const const_iterator &end(void) const { return end_; }
reverse_iterator rbegin(void) { return reverse_iterator(end()); }
const_reverse_iterator rbegin(void) const
{ return const_reverse_iterator(end()); }
reverse_iterator rend(void) { return reverse_iterator(begin()); }
const_reverse_iterator rend(void) const
{ return const_reverse_iterator(begin()); }
reference front(void) { return *begin(); }
const_reference front(void) const { return *begin(); }
reference back(void) { return *(--(end())); }
const_reference back(void) const { return *(--(end())); }
void pop_front(void) { ++begin_; }
const_reference operator [](size_type ii) const { return *(begin_ + ii);}
reference operator [](size_type ii) { return *(begin_ + ii); }
tab_ref(void) {}
tab_ref(const ITER &b, const ITER &e) : begin_(b), end_(e) {}
};
/* ********************************************************************* */
/* Reference with index. */
/* ********************************************************************* */
// template<typename ITER> struct tab_ref_index_iterator_
// : public dynamic_array<size_t>::const_iterator
// {
// typedef typename std::iterator_traits<ITER>::value_type value_type;
// typedef typename std::iterator_traits<ITER>::pointer pointer;
// typedef typename std::iterator_traits<ITER>::reference reference;
// typedef typename std::iterator_traits<ITER>::difference_type
// difference_type;
// typedef std::random_access_iterator_tag iterator_category;
// typedef size_t size_type;
// typedef dynamic_array<size_type>::const_iterator dnas_iterator_;
// typedef tab_ref_index_iterator_<ITER> iterator;
// ITER piter;
// iterator operator ++(int)
// { iterator tmp = *this; ++(*((dnas_iterator_ *)(this))); return tmp; }
// iterator operator --(int)
// { iterator tmp = *this; --(*((dnas_iterator_ *)(this))); return tmp; }
// iterator &operator ++()
// { ++(*((dnas_iterator_ *)(this))); return *this; }
// iterator &operator --()
// { --(*((dnas_iterator_ *)(this))); return *this; }
// iterator &operator +=(difference_type i)
// { (*((dnas_iterator_ *)(this))) += i; return *this; }
// iterator &operator -=(difference_type i)
// { (*((dnas_iterator_ *)(this))) -= i; return *this; }
// iterator operator +(difference_type i) const
// { iterator it = *this; return (it += i); }
// iterator operator -(difference_type i) const
// { iterator it = *this; return (it -= i); }
// difference_type operator -(const iterator &i) const
// { return *((dnas_iterator_ *)(this)) - *((dnas_iterator_ *)(&i)); }
// reference operator *() const
// { return *(piter + *((*((dnas_iterator_ *)(this))))); }
// reference operator [](int ii)
// { return *(piter + *((*((dnas_iterator_ *)(this+ii))))); }
// bool operator ==(const iterator &i) const
// {
// return ((piter) == ((i.piter))
// && *((dnas_iterator_ *)(this)) == *((*((dnas_iterator_ *)(this)))));
// }
// bool operator !=(const iterator &i) const
// { return !(i == *this); }
// bool operator < (const iterator &i) const
// {
// return ((piter) == ((i.piter))
// && *((dnas_iterator_ *)(this)) < *((*((dnas_iterator_ *)(this)))));
// }
// tab_ref_index_iterator_(void) {}
// tab_ref_index_iterator_(const ITER &iter, const dnas_iterator_ &dnas_iter)
// : dnas_iterator_(dnas_iter), piter(iter) {}
// };
// template<typename ITER> class tab_ref_index
// {
// public :
// typedef typename std::iterator_traits<ITER>::value_type value_type;
// typedef typename std::iterator_traits<ITER>::pointer pointer;
// typedef typename std::iterator_traits<ITER>::pointer const_pointer;
// typedef typename std::iterator_traits<ITER>::reference reference;
// typedef typename std::iterator_traits<ITER>::reference const_reference;
// typedef typename std::iterator_traits<ITER>::difference_type
// difference_type;
// typedef size_t size_type;
// typedef tab_ref_index_iterator_<ITER> iterator;
// typedef iterator const_iterator;
// typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
// typedef std::reverse_iterator<iterator> reverse_iterator;
// protected :
// ITER begin_;
// dynamic_array<size_type> index_;
// public :
// bool empty(void) const { return index_.empty(); }
// size_type size(void) const { return index_.size(); }
// iterator begin(void) { return iterator(begin_, index_.begin()); }
// const_iterator begin(void) const
// { return iterator(begin_, index_.begin()); }
// iterator end(void) { return iterator(begin_, index_.end()); }
// const_iterator end(void) const { return iterator(begin_, index_.end()); }
// reverse_iterator rbegin(void) { return reverse_iterator(end()); }
// const_reverse_iterator rbegin(void) const
// { return const_reverse_iterator(end()); }
// reverse_iterator rend(void) { return reverse_iterator(begin()); }
// const_reverse_iterator rend(void) const
// { return const_reverse_iterator(begin()); }
// reference front(void) { return *(begin_ +index_[0]); }
// const_reference front(void) const { return *(begin_ +index_[0]); }
// reference back(void) { return *(--(end())); }
// const_reference back(void) const { return *(--(end())); }
// tab_ref_index(void) {}
// tab_ref_index(const ITER &b, const dynamic_array<size_type> &ind)
// { begin_ = b; index_ = ind; }
// // to be changed in a const_reference ?
// value_type operator [](size_type ii) const
// { return *(begin_ + index_[ii]);}
// reference operator [](size_type ii) { return *(begin_ + index_[ii]); }
// };
/// iterator over a gmm::tab_ref_index_ref<ITER,ITER_INDEX>
template<typename ITER, typename ITER_INDEX>
struct tab_ref_index_ref_iterator_
{
typedef typename std::iterator_traits<ITER>::value_type value_type;
typedef typename std::iterator_traits<ITER>::pointer pointer;
typedef typename std::iterator_traits<ITER>::reference reference;
typedef typename std::iterator_traits<ITER>::difference_type
difference_type;
typedef std::random_access_iterator_tag iterator_category;
typedef tab_ref_index_ref_iterator_<ITER, ITER_INDEX> iterator;
typedef size_t size_type;
ITER piter;
ITER_INDEX iter_index;
iterator operator ++(int)
{ iterator tmp = *this; ++iter_index; return tmp; }
iterator operator --(int)
{ iterator tmp = *this; --iter_index; return tmp; }
iterator &operator ++() { ++iter_index; return *this; }
iterator &operator --() { --iter_index; return *this; }
iterator &operator +=(difference_type i)
{ iter_index += i; return *this; }
iterator &operator -=(difference_type i)
{ iter_index -= i; return *this; }
iterator operator +(difference_type i) const
{ iterator it = *this; return (it += i); }
iterator operator -(difference_type i) const
{ iterator it = *this; return (it -= i); }
difference_type operator -(const iterator &i) const
{ return iter_index - i.iter_index; }
reference operator *() const
{ return *(piter + *iter_index); }
reference operator [](size_type ii) const
{ return *(piter + *(iter_index+ii)); }
bool operator ==(const iterator &i) const
{ return ((piter) == ((i.piter)) && iter_index == i.iter_index); }
bool operator !=(const iterator &i) const { return !(i == *this); }
bool operator < (const iterator &i) const
{ return ((piter) == ((i.piter)) && iter_index < i.iter_index); }
tab_ref_index_ref_iterator_(void) {}
tab_ref_index_ref_iterator_(const ITER &iter,
const ITER_INDEX &dnas_iter)
: piter(iter), iter_index(dnas_iter) {}
};
/**
convenience template function for quick obtention of a indexed iterator
without having to specify its (long) typename
*/
template<typename ITER, typename ITER_INDEX>
tab_ref_index_ref_iterator_<ITER,ITER_INDEX>
index_ref_iterator(ITER it, ITER_INDEX it_i) {
return tab_ref_index_ref_iterator_<ITER,ITER_INDEX>(it, it_i);
}
/** indexed array reference (given a container X, and a set of indexes I,
this class provides a pseudo-container Y such that
@code Y[i] = X[I[i]] @endcode
*/
template<typename ITER, typename ITER_INDEX> class tab_ref_index_ref {
public :
typedef std::iterator_traits<ITER> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::pointer pointer;
typedef typename traits_type::pointer const_pointer;
typedef typename traits_type::reference reference;
typedef typename traits_type::reference const_reference;
typedef typename traits_type::difference_type difference_type;
typedef size_t size_type;
typedef tab_ref_index_ref_iterator_<ITER, ITER_INDEX> iterator;
typedef iterator const_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
protected :
ITER begin_;
ITER_INDEX index_begin_, index_end_;
public :
bool empty(void) const { return index_begin_ == index_end_; }
size_type size(void) const { return index_end_ - index_begin_; }
iterator begin(void) { return iterator(begin_, index_begin_); }
const_iterator begin(void) const
{ return iterator(begin_, index_begin_); }
iterator end(void) { return iterator(begin_, index_end_); }
const_iterator end(void) const { return iterator(begin_, index_end_); }
reverse_iterator rbegin(void) { return reverse_iterator(end()); }
const_reverse_iterator rbegin(void) const
{ return const_reverse_iterator(end()); }
reverse_iterator rend(void) { return reverse_iterator(begin()); }
const_reverse_iterator rend(void) const
{ return const_reverse_iterator(begin()); }
reference front(void) { return *(begin_ + *index_begin_); }
const_reference front(void) const { return *(begin_ + *index_begin_); }
reference back(void) { return *(--(end())); }
const_reference back(void) const { return *(--(end())); }
void pop_front(void) { ++index_begin_; }
tab_ref_index_ref(void) {}
tab_ref_index_ref(const ITER &b, const ITER_INDEX &bi,
const ITER_INDEX &ei)
: begin_(b), index_begin_(bi), index_end_(ei) {}
// to be changed in a const_reference ?
const_reference operator [](size_type ii) const
{ return *(begin_ + index_begin_[ii]);}
reference operator [](size_type ii)
{ return *(begin_ + index_begin_[ii]); }
};
/* ********************************************************************* */
/* Reference on regularly spaced elements. */
/* ********************************************************************* */
template<typename ITER> struct tab_ref_reg_spaced_iterator_ {
typedef typename std::iterator_traits<ITER>::value_type value_type;
typedef typename std::iterator_traits<ITER>::pointer pointer;
typedef typename std::iterator_traits<ITER>::reference reference;
typedef typename std::iterator_traits<ITER>::difference_type
difference_type;
typedef typename std::iterator_traits<ITER>::iterator_category
iterator_category;
typedef size_t size_type;
typedef tab_ref_reg_spaced_iterator_<ITER> iterator;
ITER it;
size_type N, i;
iterator operator ++(int) { iterator tmp = *this; i++; return tmp; }
iterator operator --(int) { iterator tmp = *this; i--; return tmp; }
iterator &operator ++() { i++; return *this; }
iterator &operator --() { i--; return *this; }
iterator &operator +=(difference_type ii) { i+=ii; return *this; }
iterator &operator -=(difference_type ii) { i-=ii; return *this; }
iterator operator +(difference_type ii) const
{ iterator itt = *this; return (itt += ii); }
iterator operator -(difference_type ii) const
{ iterator itt = *this; return (itt -= ii); }
difference_type operator -(const iterator &ii) const
{ return (N ? (it - ii.it) / N : 0) + i - ii.i; }
reference operator *() const { return *(it + i*N); }
reference operator [](size_type ii) const { return *(it + (i+ii)*N); }
bool operator ==(const iterator &ii) const
{ return (*this - ii) == difference_type(0); }
bool operator !=(const iterator &ii) const
{ return (*this - ii) != difference_type(0); }
bool operator < (const iterator &ii) const
{ return (*this - ii) < difference_type(0); }
tab_ref_reg_spaced_iterator_(void) {}
tab_ref_reg_spaced_iterator_(const ITER &iter, size_type n, size_type ii)
: it(iter), N(n), i(ii) { }
};
/**
convenience template function for quick obtention of a strided iterator
without having to specify its (long) typename
*/
template<typename ITER> tab_ref_reg_spaced_iterator_<ITER>
reg_spaced_iterator(ITER it, size_t stride) {
return tab_ref_reg_spaced_iterator_<ITER>(it, stride);
}
/**
provide a "strided" view a of container
*/
template<typename ITER> class tab_ref_reg_spaced {
public :
typedef typename std::iterator_traits<ITER>::value_type value_type;
typedef typename std::iterator_traits<ITER>::pointer pointer;
typedef typename std::iterator_traits<ITER>::pointer const_pointer;
typedef typename std::iterator_traits<ITER>::reference reference;
typedef typename std::iterator_traits<ITER>::reference const_reference;
typedef typename std::iterator_traits<ITER>::difference_type
difference_type;
typedef size_t size_type;
typedef tab_ref_reg_spaced_iterator_<ITER> iterator;
typedef iterator const_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
protected :
ITER begin_;
size_type N, size_;
public :
bool empty(void) const { return size_ == 0; }
size_type size(void) const { return size_; }
iterator begin(void) { return iterator(begin_, N, 0); }
const_iterator begin(void) const { return iterator(begin_, N, 0); }
iterator end(void) { return iterator(begin_, N, size_); }
const_iterator end(void) const { return iterator(begin_, N, size_); }
reverse_iterator rbegin(void) { return reverse_iterator(end()); }
const_reverse_iterator rbegin(void) const
{ return const_reverse_iterator(end()); }
reverse_iterator rend(void) { return reverse_iterator(begin()); }
const_reverse_iterator rend(void) const
{ return const_reverse_iterator(begin()); }
reference front(void) { return *begin_; }
const_reference front(void) const { return *begin_; }
reference back(void) { return *(begin_ + N * (size_-1)); }
const_reference back(void) const { return *(begin_ + N * (size_-1)); }
void pop_front(void) { begin_ += N; }
tab_ref_reg_spaced(void) {}
tab_ref_reg_spaced(const ITER &b, size_type n, size_type s)
: begin_(b), N(n), size_(s) {}
const_reference operator [](size_type ii) const
{ return *(begin_ + ii * N);}
reference operator [](size_type ii) { return *(begin_ + ii * N); }
};
/// iterator over a tab_ref_with_selection
template<typename ITER, typename COND>
struct tab_ref_with_selection_iterator_ : public ITER {
typedef typename std::iterator_traits<ITER>::value_type value_type;
typedef typename std::iterator_traits<ITER>::pointer pointer;
typedef typename std::iterator_traits<ITER>::reference reference;
typedef typename std::iterator_traits<ITER>::difference_type
difference_type;
typedef std::forward_iterator_tag iterator_category;
typedef tab_ref_with_selection_iterator_<ITER, COND> iterator;
const COND cond;
void forward(void) { while (!(cond)(*this)) ITER::operator ++(); }
iterator &operator ++()
{ ITER::operator ++(); forward(); return *this; }
iterator operator ++(int)
{ iterator tmp = *this; ++(*this); return tmp; }
tab_ref_with_selection_iterator_(void) {}
tab_ref_with_selection_iterator_(const ITER &iter, const COND c)
: ITER(iter), cond(c) {}
};
/**
given a container X and a predicate P, provide pseudo-container Y
of all elements of X such that P(X[i]).
*/
template<typename ITER, typename COND> class tab_ref_with_selection {
protected :
ITER begin_, end_;
COND cond;
public :
typedef typename std::iterator_traits<ITER>::value_type value_type;
typedef typename std::iterator_traits<ITER>::pointer pointer;
typedef typename std::iterator_traits<ITER>::pointer const_pointer;
typedef typename std::iterator_traits<ITER>::reference reference;
typedef typename std::iterator_traits<ITER>::reference const_reference;
typedef size_t size_type;
typedef tab_ref_with_selection_iterator_<ITER, COND> iterator;
typedef iterator const_iterator;
iterator begin(void) const
{ iterator it(begin_, cond); it.forward(); return it; }
iterator end(void) const { return iterator(end_, cond); }
bool empty(void) const { return begin_ == end_; }
value_type front(void) const { return *begin(); }
void pop_front(void) { ++begin_; begin_ = begin(); }
COND &condition(void) { return cond; }
const COND &condition(void) const { return cond; }
tab_ref_with_selection(void) {}
tab_ref_with_selection(const ITER &b, const ITER &e, const COND &c)
: begin_(b), end_(e), cond(c) { begin_ = begin(); }
};
}
#endif /* GMM_REF_H__ */

434
gmm/gmm_scaled.h Normal file
View File

@ -0,0 +1,434 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_scaled.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date November 10, 2002.
@brief get a scaled view of a vector/matrix.
*/
#ifndef GMM_SCALED_H__
#define GMM_SCALED_H__
#include "gmm_def.h"
namespace gmm {
/* ********************************************************************* */
/* Scaled references on vectors */
/* ********************************************************************* */
template <typename IT, typename S> struct scaled_const_iterator {
typedef typename strongest_numeric_type<typename std::iterator_traits<IT>::value_type,
S>::T value_type;
typedef typename std::iterator_traits<IT>::pointer pointer;
typedef typename std::iterator_traits<IT>::reference reference;
typedef typename std::iterator_traits<IT>::difference_type difference_type;
typedef typename std::iterator_traits<IT>::iterator_category
iterator_category;
IT it;
S r;
scaled_const_iterator(void) {}
scaled_const_iterator(const IT &i, S x) : it(i), r(x) {}
inline size_type index(void) const { return it.index(); }
inline scaled_const_iterator operator ++(int)
{ scaled_const_iterator tmp = *this; ++it; return tmp; }
inline scaled_const_iterator operator --(int)
{ scaled_const_iterator tmp = *this; --it; return tmp; }
inline scaled_const_iterator &operator ++() { ++it; return *this; }
inline scaled_const_iterator &operator --() { --it; return *this; }
inline scaled_const_iterator &operator +=(difference_type i)
{ it += i; return *this; }
inline scaled_const_iterator &operator -=(difference_type i)
{ it -= i; return *this; }
inline scaled_const_iterator operator +(difference_type i) const
{ scaled_const_iterator itb = *this; return (itb += i); }
inline scaled_const_iterator operator -(difference_type i) const
{ scaled_const_iterator itb = *this; return (itb -= i); }
inline difference_type operator -(const scaled_const_iterator &i) const
{ return difference_type(it - i.it); }
inline value_type operator *() const { return (*it) * value_type(r); }
inline value_type operator [](size_type ii) const { return it[ii] * r; }
inline bool operator ==(const scaled_const_iterator &i) const
{ return (i.it == it); }
inline bool operator !=(const scaled_const_iterator &i) const
{ return (i.it != it); }
inline bool operator < (const scaled_const_iterator &i) const
{ return (it < i.it); }
};
template <typename V, typename S> struct scaled_vector_const_ref {
typedef scaled_vector_const_ref<V,S> this_type;
typedef typename linalg_traits<this_type>::value_type value_type;
typedef typename linalg_traits<V>::const_iterator iterator;
typedef typename linalg_traits<this_type>::reference reference;
typedef typename linalg_traits<this_type>::origin_type origin_type;
iterator begin_, end_;
const origin_type *origin;
size_type size_;
S r;
scaled_vector_const_ref(const V &v, S rr)
: begin_(vect_const_begin(v)), end_(vect_const_end(v)),
origin(linalg_origin(v)), size_(vect_size(v)), r(rr) {}
reference operator[](size_type i) const
{ return value_type(r) * linalg_traits<V>::access(origin, begin_, end_, i); }
};
template<typename V, typename S> std::ostream &operator <<
(std::ostream &o, const scaled_vector_const_ref<V,S>& m)
{ gmm::write(o,m); return o; }
/* ********************************************************************* */
/* Scaled references on matrices */
/* ********************************************************************* */
template <typename M, typename S> struct scaled_row_const_iterator {
typedef scaled_row_const_iterator<M,S> iterator;
typedef typename linalg_traits<M>::const_row_iterator ITER;
typedef ptrdiff_t difference_type;
typedef size_t size_type;
ITER it;
S r;
inline iterator operator ++(int) { iterator tmp=*this; it++; return tmp; }
inline iterator operator --(int) { iterator tmp=*this; it--; return tmp; }
inline iterator &operator ++() { it++; return *this; }
inline iterator &operator --() { it--; return *this; }
iterator &operator +=(difference_type i) { it += i; return *this; }
iterator &operator -=(difference_type i) { it -= i; return *this; }
iterator operator +(difference_type i) const
{ iterator itt = *this; return (itt += i); }
iterator operator -(difference_type i) const
{ iterator itt = *this; return (itt -= i); }
difference_type operator -(const iterator &i) const
{ return it - i.it; }
inline ITER operator *() const { return it; }
inline ITER operator [](int i) { return it + i; }
inline bool operator ==(const iterator &i) const { return (it == i.it); }
inline bool operator !=(const iterator &i) const { return !(i == *this); }
inline bool operator < (const iterator &i) const { return (it < i.it); }
scaled_row_const_iterator(void) {}
scaled_row_const_iterator(const ITER &i, S rr)
: it(i), r(rr) { }
};
template <typename M, typename S> struct scaled_row_matrix_const_ref {
typedef scaled_row_matrix_const_ref<M,S> this_type;
typedef typename linalg_traits<M>::const_row_iterator iterator;
typedef typename linalg_traits<this_type>::value_type value_type;
typedef typename linalg_traits<this_type>::origin_type origin_type;
iterator begin_, end_;
const origin_type *origin;
S r;
size_type nr, nc;
scaled_row_matrix_const_ref(const M &m, S rr)
: begin_(mat_row_begin(m)), end_(mat_row_end(m)),
origin(linalg_origin(m)), r(rr), nr(mat_nrows(m)), nc(mat_ncols(m)) {}
value_type operator()(size_type i, size_type j) const
{ return r * linalg_traits<M>::access(begin_+i, j); }
};
template<typename M, typename S> std::ostream &operator <<
(std::ostream &o, const scaled_row_matrix_const_ref<M,S>& m)
{ gmm::write(o,m); return o; }
template <typename M, typename S> struct scaled_col_const_iterator {
typedef scaled_col_const_iterator<M,S> iterator;
typedef typename linalg_traits<M>::const_col_iterator ITER;
typedef ptrdiff_t difference_type;
typedef size_t size_type;
ITER it;
S r;
iterator operator ++(int) { iterator tmp = *this; it++; return tmp; }
iterator operator --(int) { iterator tmp = *this; it--; return tmp; }
iterator &operator ++() { it++; return *this; }
iterator &operator --() { it--; return *this; }
iterator &operator +=(difference_type i) { it += i; return *this; }
iterator &operator -=(difference_type i) { it -= i; return *this; }
iterator operator +(difference_type i) const
{ iterator itt = *this; return (itt += i); }
iterator operator -(difference_type i) const
{ iterator itt = *this; return (itt -= i); }
difference_type operator -(const iterator &i) const
{ return it - i.it; }
ITER operator *() const { return it; }
ITER operator [](int i) { return it + i; }
bool operator ==(const iterator &i) const { return (it == i.it); }
bool operator !=(const iterator &i) const { return !(i == *this); }
bool operator < (const iterator &i) const { return (it < i.it); }
scaled_col_const_iterator(void) {}
scaled_col_const_iterator(const ITER &i, S rr)
: it(i), r(rr) { }
};
template <typename M, typename S> struct scaled_col_matrix_const_ref {
typedef scaled_col_matrix_const_ref<M,S> this_type;
typedef typename linalg_traits<M>::const_col_iterator iterator;
typedef typename linalg_traits<this_type>::value_type value_type;
typedef typename linalg_traits<this_type>::origin_type origin_type;
iterator begin_, end_;
const origin_type *origin;
S r;
size_type nr, nc;
scaled_col_matrix_const_ref(const M &m, S rr)
: begin_(mat_col_begin(m)), end_(mat_col_end(m)),
origin(linalg_origin(m)), r(rr), nr(mat_nrows(m)), nc(mat_ncols(m)) {}
value_type operator()(size_type i, size_type j) const
{ return r * linalg_traits<M>::access(begin_+j, i); }
};
template<typename M, typename S> std::ostream &operator <<
(std::ostream &o, const scaled_col_matrix_const_ref<M,S>& m)
{ gmm::write(o,m); return o; }
template <typename L, typename S, typename R> struct scaled_return__ {
typedef abstract_null_type return_type;
};
template <typename L, typename S> struct scaled_return__<L, S, row_major>
{ typedef scaled_row_matrix_const_ref<L,S> return_type; };
template <typename L, typename S> struct scaled_return__<L, S, col_major>
{ typedef scaled_col_matrix_const_ref<L,S> return_type; };
template <typename L, typename S, typename LT> struct scaled_return_ {
typedef abstract_null_type return_type;
};
template <typename L, typename S> struct scaled_return_<L, S, abstract_vector>
{ typedef scaled_vector_const_ref<L,S> return_type; };
template <typename L, typename S> struct scaled_return_<L, S, abstract_matrix> {
typedef typename scaled_return__<L, S,
typename principal_orientation_type<typename
linalg_traits<L>::sub_orientation>::potype>::return_type return_type;
};
template <typename L, typename S> struct scaled_return {
typedef typename scaled_return_<L, S, typename
linalg_traits<L>::linalg_type>::return_type return_type;
};
template <typename L, typename S> inline
typename scaled_return<L,S>::return_type
scaled(const L &v, S x)
{ return scaled(v, x, typename linalg_traits<L>::linalg_type()); }
template <typename V, typename S> inline
typename scaled_return<V,S>::return_type
scaled(const V &v, S x, abstract_vector)
{ return scaled_vector_const_ref<V,S>(v, x); }
template <typename M, typename S> inline
typename scaled_return<M,S>::return_type
scaled(const M &m, S x,abstract_matrix) {
return scaled(m, x, typename principal_orientation_type<typename
linalg_traits<M>::sub_orientation>::potype());
}
template <typename M, typename S> inline
typename scaled_return<M,S>::return_type
scaled(const M &m, S x, row_major) {
return scaled_row_matrix_const_ref<M,S>(m, x);
}
template <typename M, typename S> inline
typename scaled_return<M,S>::return_type
scaled(const M &m, S x, col_major) {
return scaled_col_matrix_const_ref<M,S>(m, x);
}
/* ******************************************************************** */
/* matrix or vector scale */
/* ******************************************************************** */
template <typename L> inline
void scale(L& l, typename linalg_traits<L>::value_type a)
{ scale(l, a, typename linalg_traits<L>::linalg_type()); }
template <typename L> inline
void scale(const L& l, typename linalg_traits<L>::value_type a)
{ scale(linalg_const_cast(l), a); }
template <typename L> inline
void scale(L& l, typename linalg_traits<L>::value_type a, abstract_vector) {
typename linalg_traits<L>::iterator it = vect_begin(l), ite = vect_end(l);
for ( ; it != ite; ++it) *it *= a;
}
template <typename L>
void scale(L& l, typename linalg_traits<L>::value_type a, abstract_matrix) {
scale(l, a, typename principal_orientation_type<typename
linalg_traits<L>::sub_orientation>::potype());
}
template <typename L>
void scale(L& l, typename linalg_traits<L>::value_type a, row_major) {
typename linalg_traits<L>::row_iterator it = mat_row_begin(l),
ite = mat_row_end(l);
for ( ; it != ite; ++it) scale(linalg_traits<L>::row(it), a);
}
template <typename L>
void scale(L& l, typename linalg_traits<L>::value_type a, col_major) {
typename linalg_traits<L>::col_iterator it = mat_col_begin(l),
ite = mat_col_end(l);
for ( ; it != ite; ++it) scale(linalg_traits<L>::col(it), a);
}
template <typename V, typename S> struct linalg_traits<scaled_vector_const_ref<V,S> > {
typedef scaled_vector_const_ref<V,S> this_type;
typedef linalg_const is_reference;
typedef abstract_vector linalg_type;
typedef typename strongest_numeric_type<S, typename linalg_traits<V>::value_type>::T value_type;
typedef typename linalg_traits<V>::origin_type origin_type;
typedef value_type reference;
typedef abstract_null_type iterator;
typedef scaled_const_iterator<typename linalg_traits<V>::const_iterator, S>
const_iterator;
typedef typename linalg_traits<V>::storage_type storage_type;
typedef typename linalg_traits<V>::index_sorted index_sorted;
static size_type size(const this_type &v) { return v.size_; }
static const_iterator begin(const this_type &v)
{ return const_iterator(v.begin_, v.r); }
static const_iterator end(const this_type &v)
{ return const_iterator(v.end_, v.r); }
static const origin_type* origin(const this_type &v) { return v.origin; }
static value_type access(const origin_type *o, const const_iterator &it,
const const_iterator &ite, size_type i)
{ return it.r * (linalg_traits<V>::access(o, it.it, ite.it, i)); }
};
template <typename M, typename S> struct linalg_traits<scaled_row_matrix_const_ref<M,S> > {
typedef scaled_row_matrix_const_ref<M,S> this_type;
typedef linalg_const is_reference;
typedef abstract_matrix linalg_type;
typedef typename linalg_traits<M>::origin_type origin_type;
typedef typename strongest_numeric_type<S, typename linalg_traits<M>::value_type>::T value_type;
typedef value_type reference;
typedef typename linalg_traits<M>::storage_type storage_type;
typedef typename org_type<typename linalg_traits<M>::const_sub_row_type>::t vector_type;
typedef scaled_vector_const_ref<vector_type,S> sub_row_type;
typedef scaled_vector_const_ref<vector_type,S> const_sub_row_type;
typedef scaled_row_const_iterator<M,S> row_iterator;
typedef scaled_row_const_iterator<M,S> const_row_iterator;
typedef abstract_null_type const_sub_col_type;
typedef abstract_null_type sub_col_type;
typedef abstract_null_type const_col_iterator;
typedef abstract_null_type col_iterator;
typedef row_major sub_orientation;
typedef typename linalg_traits<M>::index_sorted index_sorted;
static size_type nrows(const this_type &m)
{ return m.nr; }
static size_type ncols(const this_type &m)
{ return m.nc; }
static const_sub_row_type row(const const_row_iterator &it)
{ return scaled(linalg_traits<M>::row(it.it), it.r); }
static const_row_iterator row_begin(const this_type &m)
{ return const_row_iterator(m.begin_, m.r); }
static const_row_iterator row_end(const this_type &m)
{ return const_row_iterator(m.end_, m.r); }
static const origin_type* origin(const this_type &m) { return m.origin; }
static value_type access(const const_row_iterator &it, size_type i)
{ return it.r * (linalg_traits<M>::access(it.it, i)); }
};
template <typename M, typename S> struct linalg_traits<scaled_col_matrix_const_ref<M,S> > {
typedef scaled_col_matrix_const_ref<M,S> this_type;
typedef linalg_const is_reference;
typedef abstract_matrix linalg_type;
typedef typename strongest_numeric_type<S, typename linalg_traits<M>::value_type>::T value_type;
typedef typename linalg_traits<M>::origin_type origin_type;
typedef value_type reference;
typedef typename linalg_traits<M>::storage_type storage_type;
typedef typename org_type<typename linalg_traits<M>::const_sub_col_type>::t vector_type;
typedef abstract_null_type sub_col_type;
typedef scaled_vector_const_ref<vector_type,S> const_sub_col_type;
typedef abstract_null_type col_iterator;
typedef scaled_col_const_iterator<M,S> const_col_iterator;
typedef abstract_null_type const_sub_row_type;
typedef abstract_null_type sub_row_type;
typedef abstract_null_type const_row_iterator;
typedef abstract_null_type row_iterator;
typedef col_major sub_orientation;
typedef typename linalg_traits<M>::index_sorted index_sorted;
static size_type ncols(const this_type &m)
{ return m.nc; }
static size_type nrows(const this_type &m)
{ return m.nr; }
static const_sub_col_type col(const const_col_iterator &it)
{ return scaled(linalg_traits<M>::col(it.it), it.r); }
static const_col_iterator col_begin(const this_type &m)
{ return const_col_iterator(m.begin_, m.r); }
static const_col_iterator col_end(const this_type &m)
{ return const_col_iterator(m.end_, m.r); }
static const origin_type* origin(const this_type &m) { return m.origin; }
static value_type access(const const_col_iterator &it, size_type i)
{ return it.r * (linalg_traits<M>::access(it.it, i)); }
};
}
#endif // GMM_SCALED_H__

View File

@ -0,0 +1,805 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_solver_Schwarz_additive.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@author Michel Fournie <fournie@mip.ups-tlse.fr>
@date October 13, 2002.
*/
#ifndef GMM_SOLVERS_SCHWARZ_ADDITIVE_H__
#define GMM_SOLVERS_SCHWARZ_ADDITIVE_H__
#include "gmm_kernel.h"
#include "gmm_superlu_interface.h"
#include "gmm_solver_cg.h"
#include "gmm_solver_gmres.h"
#include "gmm_solver_bicgstab.h"
#include "gmm_solver_qmr.h"
namespace gmm {
/* ******************************************************************** */
/* Additive Schwarz interfaced local solvers */
/* ******************************************************************** */
struct using_cg {};
struct using_gmres {};
struct using_bicgstab {};
struct using_qmr {};
template <typename P, typename local_solver, typename Matrix>
struct actual_precond {
typedef P APrecond;
static const APrecond &transform(const P &PP) { return PP; }
};
template <typename Matrix1, typename Precond, typename Vector>
void AS_local_solve(using_cg, const Matrix1 &A, Vector &x, const Vector &b,
const Precond &P, iteration &iter)
{ cg(A, x, b, P, iter); }
template <typename Matrix1, typename Precond, typename Vector>
void AS_local_solve(using_gmres, const Matrix1 &A, Vector &x,
const Vector &b, const Precond &P, iteration &iter)
{ gmres(A, x, b, P, 100, iter); }
template <typename Matrix1, typename Precond, typename Vector>
void AS_local_solve(using_bicgstab, const Matrix1 &A, Vector &x,
const Vector &b, const Precond &P, iteration &iter)
{ bicgstab(A, x, b, P, iter); }
template <typename Matrix1, typename Precond, typename Vector>
void AS_local_solve(using_qmr, const Matrix1 &A, Vector &x,
const Vector &b, const Precond &P, iteration &iter)
{ qmr(A, x, b, P, iter); }
#if defined(GMM_USES_SUPERLU)
struct using_superlu {};
template <typename P, typename Matrix>
struct actual_precond<P, using_superlu, Matrix> {
typedef typename linalg_traits<Matrix>::value_type value_type;
typedef SuperLU_factor<value_type> APrecond;
template <typename PR>
static APrecond transform(const PR &) { return APrecond(); }
static const APrecond &transform(const APrecond &PP) { return PP; }
};
template <typename Matrix1, typename Precond, typename Vector>
void AS_local_solve(using_superlu, const Matrix1 &, Vector &x,
const Vector &b, const Precond &P, iteration &iter)
{ P.solve(x, b); iter.set_iteration(1); }
#endif
/* ******************************************************************** */
/* Additive Schwarz Linear system */
/* ******************************************************************** */
template <typename Matrix1, typename Matrix2, typename Precond,
typename local_solver>
struct add_schwarz_mat{
typedef typename linalg_traits<Matrix1>::value_type value_type;
const Matrix1 *A;
const std::vector<Matrix2> *vB;
std::vector<Matrix2> vAloc;
mutable iteration iter;
double residual;
mutable size_type itebilan;
mutable std::vector<std::vector<value_type> > gi, fi;
std::vector<typename actual_precond<Precond, local_solver,
Matrix1>::APrecond> precond1;
void init(const Matrix1 &A_, const std::vector<Matrix2> &vB_,
iteration iter_, const Precond &P, double residual_);
add_schwarz_mat(void) {}
add_schwarz_mat(const Matrix1 &A_, const std::vector<Matrix2> &vB_,
iteration iter_, const Precond &P, double residual_)
{ init(A_, vB_, iter_, P, residual_); }
};
template <typename Matrix1, typename Matrix2, typename Precond,
typename local_solver>
void add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver>::init(
const Matrix1 &A_, const std::vector<Matrix2> &vB_,
iteration iter_, const Precond &P, double residual_) {
vB = &vB_; A = &A_; iter = iter_;
residual = residual_;
size_type nb_sub = vB->size();
vAloc.resize(nb_sub);
gi.resize(nb_sub); fi.resize(nb_sub);
precond1.resize(nb_sub);
std::fill(precond1.begin(), precond1.end(),
actual_precond<Precond, local_solver, Matrix1>::transform(P));
itebilan = 0;
if (iter.get_noisy()) cout << "Init pour sub dom ";
#ifdef GMM_USES_MPI
int size,tranche,borne_sup,borne_inf,rank,tag1=11,tag2=12,tag3=13,sizepr = 0;
// int tab[4];
double t_ref,t_final;
MPI_Status status;
t_ref=MPI_Wtime();
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
tranche=nb_sub/size;
borne_inf=rank*tranche;
borne_sup=(rank+1)*tranche;
// if (rank==size-1) borne_sup = nb_sub;
cout << "Nombre de sous domaines " << borne_sup - borne_inf << endl;
int sizeA = mat_nrows(*A);
gmm::csr_matrix<value_type> Acsr(sizeA, sizeA), Acsrtemp(sizeA, sizeA);
gmm::copy(gmm::eff_matrix(*A), Acsr);
int next = (rank + 1) % size;
int previous = (rank + size - 1) % size;
//communication of local information on ring pattern
//Each process receive Nproc-1 contributions
for (int nproc = 0; nproc < size; ++nproc) {
for (size_type i = size_type(borne_inf); i < size_type(borne_sup); ++i) {
// for (size_type i = 0; i < nb_sub/size; ++i) {
// for (size_type i = 0; i < nb_sub; ++i) {
// size_type i=(rank+size*(j-1)+nb_sub)%nb_sub;
cout << "Sous domaines " << i << " : " << mat_ncols((*vB)[i]) << endl;
#else
for (size_type i = 0; i < nb_sub; ++i) {
#endif
if (iter.get_noisy()) cout << i << " " << std::flush;
Matrix2 Maux(mat_ncols((*vB)[i]), mat_nrows((*vB)[i]));
#ifdef GMM_USES_MPI
Matrix2 Maux2(mat_ncols((*vB)[i]), mat_ncols((*vB)[i]));
if (nproc == 0) {
gmm::resize(vAloc[i], mat_ncols((*vB)[i]), mat_ncols((*vB)[i]));
gmm::clear(vAloc[i]);
}
gmm::mult(gmm::transposed((*vB)[i]), Acsr, Maux);
gmm::mult(Maux, (*vB)[i], Maux2);
gmm::add(Maux2, vAloc[i]);
#else
gmm::resize(vAloc[i], mat_ncols((*vB)[i]), mat_ncols((*vB)[i]));
gmm::mult(gmm::transposed((*vB)[i]), *A, Maux);
gmm::mult(Maux, (*vB)[i], vAloc[i]);
#endif
#ifdef GMM_USES_MPI
if (nproc == size - 1 ) {
#endif
precond1[i].build_with(vAloc[i]);
gmm::resize(fi[i], mat_ncols((*vB)[i]));
gmm::resize(gi[i], mat_ncols((*vB)[i]));
#ifdef GMM_USES_MPI
}
#else
}
#endif
#ifdef GMM_USES_MPI
}
if (nproc != size - 1) {
MPI_Sendrecv(&(Acsr.jc[0]), sizeA+1, MPI_INT, next, tag2,
&(Acsrtemp.jc[0]), sizeA+1, MPI_INT, previous, tag2,
MPI_COMM_WORLD, &status);
if (Acsrtemp.jc[sizeA] > size_type(sizepr)) {
sizepr = Acsrtemp.jc[sizeA];
gmm::resize(Acsrtemp.pr, sizepr);
gmm::resize(Acsrtemp.ir, sizepr);
}
MPI_Sendrecv(&(Acsr.ir[0]), Acsr.jc[sizeA], MPI_INT, next, tag1,
&(Acsrtemp.ir[0]), Acsrtemp.jc[sizeA], MPI_INT, previous, tag1,
MPI_COMM_WORLD, &status);
MPI_Sendrecv(&(Acsr.pr[0]), Acsr.jc[sizeA], mpi_type(value_type()), next, tag3,
&(Acsrtemp.pr[0]), Acsrtemp.jc[sizeA], mpi_type(value_type()), previous, tag3,
MPI_COMM_WORLD, &status);
gmm::copy(Acsrtemp, Acsr);
}
}
t_final=MPI_Wtime();
cout<<"temps boucle precond "<< t_final-t_ref<<endl;
#endif
if (iter.get_noisy()) cout << "\n";
}
template <typename Matrix1, typename Matrix2, typename Precond,
typename Vector2, typename Vector3, typename local_solver>
void mult(const add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver> &M,
const Vector2 &p, Vector3 &q) {
size_type itebilan = 0;
#ifdef GMM_USES_MPI
static double tmult_tot = 0.0;
double t_ref = MPI_Wtime();
#endif
// cout << "tmult AS begin " << endl;
mult(*(M.A), p, q);
#ifdef GMM_USES_MPI
tmult_tot += MPI_Wtime()-t_ref;
cout << "tmult_tot = " << tmult_tot << endl;
#endif
std::vector<double> qbis(gmm::vect_size(q));
std::vector<double> qter(gmm::vect_size(q));
#ifdef GMM_USES_MPI
// MPI_Status status;
// MPI_Request request,request1;
// int tag=111;
int size,tranche,borne_sup,borne_inf,rank;
size_type nb_sub=M.fi.size();
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
tranche=nb_sub/size;
borne_inf=rank*tranche;
borne_sup=(rank+1)*tranche;
// if (rank==size-1) borne_sup=nb_sub;
// int next = (rank + 1) % size;
// int previous = (rank + size - 1) % size;
t_ref = MPI_Wtime();
for (size_type i = size_type(borne_inf); i < size_type(borne_sup); ++i)
// for (size_type i = 0; i < nb_sub/size; ++i)
// for (size_type j = 0; j < nb_sub; ++j)
#else
for (size_type i = 0; i < M.fi.size(); ++i)
#endif
{
#ifdef GMM_USES_MPI
// size_type i=j; // (rank+size*(j-1)+nb_sub)%nb_sub;
#endif
gmm::mult(gmm::transposed((*(M.vB))[i]), q, M.fi[i]);
M.iter.init();
AS_local_solve(local_solver(), (M.vAloc)[i], (M.gi)[i],
(M.fi)[i],(M.precond1)[i],M.iter);
itebilan = std::max(itebilan, M.iter.get_iteration());
}
#ifdef GMM_USES_MPI
cout << "First AS loop time " << MPI_Wtime() - t_ref << endl;
#endif
gmm::clear(q);
#ifdef GMM_USES_MPI
t_ref = MPI_Wtime();
// for (size_type j = 0; j < nb_sub; ++j)
for (size_type i = size_type(borne_inf); i < size_type(borne_sup); ++i)
#else
for (size_type i = 0; i < M.gi.size(); ++i)
#endif
{
#ifdef GMM_USES_MPI
// size_type i=j; // (rank+size*(j-1)+nb_sub)%nb_sub;
// gmm::mult((*(M.vB))[i], M.gi[i], qbis,qbis);
gmm::mult((*(M.vB))[i], M.gi[i], qter);
add(qter,qbis,qbis);
#else
gmm::mult((*(M.vB))[i], M.gi[i], q, q);
#endif
}
#ifdef GMM_USES_MPI
//WARNING this add only if you use the ring pattern below
// need to do this below if using a n explicit ring pattern communication
// add(qbis,q,q);
cout << "Second AS loop time " << MPI_Wtime() - t_ref << endl;
#endif
#ifdef GMM_USES_MPI
// int tag1=11;
static double t_tot = 0.0;
double t_final;
t_ref=MPI_Wtime();
// int next = (rank + 1) % size;
// int previous = (rank + size - 1) % size;
//communication of local information on ring pattern
//Each process receive Nproc-1 contributions
// if (size > 1) {
// for (int nproc = 0; nproc < size-1; ++nproc)
// {
// MPI_Sendrecv(&(qbis[0]), gmm::vect_size(q), MPI_DOUBLE, next, tag1,
// &(qter[0]), gmm::vect_size(q),MPI_DOUBLE,previous,tag1,
// MPI_COMM_WORLD,&status);
// gmm::copy(qter, qbis);
// add(qbis,q,q);
// }
// }
MPI_Allreduce(&(qbis[0]), &(q[0]),gmm::vect_size(q), MPI_DOUBLE,
MPI_SUM,MPI_COMM_WORLD);
t_final=MPI_Wtime();
t_tot += t_final-t_ref;
cout<<"["<< rank<<"] temps reduce Resol "<< t_final-t_ref << " t_tot = " << t_tot << endl;
#endif
if (M.iter.get_noisy() > 0) cout << "itebloc = " << itebilan << endl;
M.itebilan += itebilan;
M.iter.set_resmax((M.iter.get_resmax() + M.residual) * 0.5);
}
template <typename Matrix1, typename Matrix2, typename Precond,
typename Vector2, typename Vector3, typename local_solver>
void mult(const add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver> &M,
const Vector2 &p, const Vector3 &q) {
mult(M, p, const_cast<Vector3 &>(q));
}
template <typename Matrix1, typename Matrix2, typename Precond,
typename Vector2, typename Vector3, typename Vector4,
typename local_solver>
void mult(const add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver> &M,
const Vector2 &p, const Vector3 &p2, Vector4 &q)
{ mult(M, p, q); add(p2, q); }
template <typename Matrix1, typename Matrix2, typename Precond,
typename Vector2, typename Vector3, typename Vector4,
typename local_solver>
void mult(const add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver> &M,
const Vector2 &p, const Vector3 &p2, const Vector4 &q)
{ mult(M, p, const_cast<Vector4 &>(q)); add(p2, q); }
/* ******************************************************************** */
/* Additive Schwarz interfaced global solvers */
/* ******************************************************************** */
template <typename ASM_type, typename Vect>
void AS_global_solve(using_cg, const ASM_type &ASM, Vect &x,
const Vect &b, iteration &iter)
{ cg(ASM, x, b, *(ASM.A), identity_matrix(), iter); }
template <typename ASM_type, typename Vect>
void AS_global_solve(using_gmres, const ASM_type &ASM, Vect &x,
const Vect &b, iteration &iter)
{ gmres(ASM, x, b, identity_matrix(), 100, iter); }
template <typename ASM_type, typename Vect>
void AS_global_solve(using_bicgstab, const ASM_type &ASM, Vect &x,
const Vect &b, iteration &iter)
{ bicgstab(ASM, x, b, identity_matrix(), iter); }
template <typename ASM_type, typename Vect>
void AS_global_solve(using_qmr,const ASM_type &ASM, Vect &x,
const Vect &b, iteration &iter)
{ qmr(ASM, x, b, identity_matrix(), iter); }
#if defined(GMM_USES_SUPERLU)
template <typename ASM_type, typename Vect>
void AS_global_solve(using_superlu, const ASM_type &, Vect &,
const Vect &, iteration &) {
GMM_ASSERT1(false, "You cannot use SuperLU as "
"global solver in additive Schwarz meethod");
}
#endif
/* ******************************************************************** */
/* Linear Additive Schwarz method */
/* ******************************************************************** */
/* ref : Domain decomposition algorithms for the p-version finite */
/* element method for elliptic problems, Luca F. Pavarino, */
/* PhD thesis, Courant Institute of Mathematical Sciences, 1992. */
/* ******************************************************************** */
/** Function to call if the ASM matrix is precomputed for successive solve
* with the same system.
*/
template <typename Matrix1, typename Matrix2,
typename Vector2, typename Vector3, typename Precond,
typename local_solver, typename global_solver>
void additive_schwarz(
add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver> &ASM, Vector3 &u,
const Vector2 &f, iteration &iter, const global_solver&) {
typedef typename linalg_traits<Matrix1>::value_type value_type;
size_type nb_sub = ASM.vB->size(), nb_dof = gmm::vect_size(f);
ASM.itebilan = 0;
std::vector<value_type> g(nb_dof);
std::vector<value_type> gbis(nb_dof);
#ifdef GMM_USES_MPI
double t_init=MPI_Wtime();
int size,tranche,borne_sup,borne_inf,rank;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
tranche=nb_sub/size;
borne_inf=rank*tranche;
borne_sup=(rank+1)*tranche;
// if (rank==size-1) borne_sup=nb_sub*size;
for (size_type i = size_type(borne_inf); i < size_type(borne_sup); ++i)
// for (size_type i = 0; i < nb_sub/size; ++i)
// for (size_type j = 0; j < nb_sub; ++j)
// for (size_type i = rank; i < nb_sub; i+=size)
#else
for (size_type i = 0; i < nb_sub; ++i)
#endif
{
#ifdef GMM_USES_MPI
// size_type i=j; // (rank+size*(j-1)+nb_sub)%nb_sub;
#endif
gmm::mult(gmm::transposed((*(ASM.vB))[i]), f, ASM.fi[i]);
ASM.iter.init();
AS_local_solve(local_solver(), ASM.vAloc[i], ASM.gi[i], ASM.fi[i],
ASM.precond1[i], ASM.iter);
ASM.itebilan = std::max(ASM.itebilan, ASM.iter.get_iteration());
#ifdef GMM_USES_MPI
gmm::mult((*(ASM.vB))[i], ASM.gi[i], gbis,gbis);
#else
gmm::mult((*(ASM.vB))[i], ASM.gi[i], g, g);
#endif
}
#ifdef GMM_USES_MPI
cout<<"temps boucle init "<< MPI_Wtime()-t_init<<endl;
double t_ref,t_final;
t_ref=MPI_Wtime();
MPI_Allreduce(&(gbis[0]), &(g[0]),gmm::vect_size(g), MPI_DOUBLE,
MPI_SUM,MPI_COMM_WORLD);
t_final=MPI_Wtime();
cout<<"temps reduce init "<< t_final-t_ref<<endl;
#endif
#ifdef GMM_USES_MPI
t_ref=MPI_Wtime();
cout<<"begin global AS"<<endl;
#endif
AS_global_solve(global_solver(), ASM, u, g, iter);
#ifdef GMM_USES_MPI
t_final=MPI_Wtime();
cout<<"temps AS Global Solve "<< t_final-t_ref<<endl;
#endif
if (iter.get_noisy())
cout << "Total number of internal iterations : " << ASM.itebilan << endl;
}
/** Global function. Compute the ASM matrix and call the previous function.
* The ASM matrix represent the preconditionned linear system.
*/
template <typename Matrix1, typename Matrix2,
typename Vector2, typename Vector3, typename Precond,
typename local_solver, typename global_solver>
void additive_schwarz(const Matrix1 &A, Vector3 &u,
const Vector2 &f, const Precond &P,
const std::vector<Matrix2> &vB,
iteration &iter, local_solver,
global_solver) {
iter.set_rhsnorm(vect_norm2(f));
if (iter.get_rhsnorm() == 0.0) { gmm::clear(u); return; }
iteration iter2 = iter; iter2.reduce_noisy();
iter2.set_maxiter(size_type(-1));
add_schwarz_mat<Matrix1, Matrix2, Precond, local_solver>
ASM(A, vB, iter2, P, iter.get_resmax());
additive_schwarz(ASM, u, f, iter, global_solver());
}
/* ******************************************************************** */
/* Sequential Non-Linear Additive Schwarz method */
/* ******************************************************************** */
/* ref : Nonlinearly Preconditionned Inexact Newton Algorithms, */
/* Xiao-Chuan Cai, David E. Keyes, */
/* SIAM J. Sci. Comp. 24: p183-200. l */
/* ******************************************************************** */
template <typename Matrixt, typename MatrixBi>
class NewtonAS_struct {
public :
typedef Matrixt tangent_matrix_type;
typedef MatrixBi B_matrix_type;
typedef typename linalg_traits<Matrixt>::value_type value_type;
typedef std::vector<value_type> Vector;
virtual size_type size(void) = 0;
virtual const std::vector<MatrixBi> &get_vB() = 0;
virtual void compute_F(Vector &f, Vector &x) = 0;
virtual void compute_tangent_matrix(Matrixt &M, Vector &x) = 0;
// compute Bi^T grad(F(X)) Bi
virtual void compute_sub_tangent_matrix(Matrixt &Mloc, Vector &x,
size_type i) = 0;
// compute Bi^T F(X)
virtual void compute_sub_F(Vector &fi, Vector &x, size_type i) = 0;
virtual ~NewtonAS_struct() {}
};
template <typename Matrixt, typename MatrixBi>
struct AS_exact_gradient {
const std::vector<MatrixBi> &vB;
std::vector<Matrixt> vM;
std::vector<Matrixt> vMloc;
void init(void) {
for (size_type i = 0; i < vB.size(); ++i) {
Matrixt aux(gmm::mat_ncols(vB[i]), gmm::mat_ncols(vM[i]));
gmm::resize(vMloc[i], gmm::mat_ncols(vB[i]), gmm::mat_ncols(vB[i]));
gmm::mult(gmm::transposed(vB[i]), vM[i], aux);
gmm::mult(aux, vB[i], vMloc[i]);
}
}
AS_exact_gradient(const std::vector<MatrixBi> &vB_) : vB(vB_) {
vM.resize(vB.size()); vMloc.resize(vB.size());
for (size_type i = 0; i < vB.size(); ++i) {
gmm::resize(vM[i], gmm::mat_nrows(vB[i]), gmm::mat_nrows(vB[i]));
}
}
};
template <typename Matrixt, typename MatrixBi,
typename Vector2, typename Vector3>
void mult(const AS_exact_gradient<Matrixt, MatrixBi> &M,
const Vector2 &p, Vector3 &q) {
gmm::clear(q);
typedef typename gmm::linalg_traits<Vector3>::value_type T;
std::vector<T> v(gmm::vect_size(p)), w, x;
for (size_type i = 0; i < M.vB.size(); ++i) {
w.resize(gmm::mat_ncols(M.vB[i]));
x.resize(gmm::mat_ncols(M.vB[i]));
gmm::mult(M.vM[i], p, v);
gmm::mult(gmm::transposed(M.vB[i]), v, w);
double rcond;
SuperLU_solve(M.vMloc[i], x, w, rcond);
// gmm::iteration iter(1E-10, 0, 100000);
//gmm::gmres(M.vMloc[i], x, w, gmm::identity_matrix(), 50, iter);
gmm::mult_add(M.vB[i], x, q);
}
}
template <typename Matrixt, typename MatrixBi,
typename Vector2, typename Vector3>
void mult(const AS_exact_gradient<Matrixt, MatrixBi> &M,
const Vector2 &p, const Vector3 &q) {
mult(M, p, const_cast<Vector3 &>(q));
}
template <typename Matrixt, typename MatrixBi,
typename Vector2, typename Vector3, typename Vector4>
void mult(const AS_exact_gradient<Matrixt, MatrixBi> &M,
const Vector2 &p, const Vector3 &p2, Vector4 &q)
{ mult(M, p, q); add(p2, q); }
template <typename Matrixt, typename MatrixBi,
typename Vector2, typename Vector3, typename Vector4>
void mult(const AS_exact_gradient<Matrixt, MatrixBi> &M,
const Vector2 &p, const Vector3 &p2, const Vector4 &q)
{ mult(M, p, const_cast<Vector4 &>(q)); add(p2, q); }
struct S_default_newton_line_search {
double conv_alpha, conv_r;
size_t it, itmax, glob_it;
double alpha, alpha_old, alpha_mult, first_res, alpha_max_ratio;
double alpha_min_ratio, alpha_min;
size_type count, count_pat;
bool max_ratio_reached;
double alpha_max_ratio_reached, r_max_ratio_reached;
size_type it_max_ratio_reached;
double converged_value(void) { return conv_alpha; };
double converged_residual(void) { return conv_r; };
virtual void init_search(double r, size_t git, double = 0.0) {
alpha_min_ratio = 0.9;
alpha_min = 1e-10;
alpha_max_ratio = 10.0;
alpha_mult = 0.25;
itmax = size_type(-1);
glob_it = git; if (git <= 1) count_pat = 0;
conv_alpha = alpha = alpha_old = 1.;
conv_r = first_res = r; it = 0;
count = 0;
max_ratio_reached = false;
}
virtual double next_try(void) {
alpha_old = alpha;
if (alpha >= 0.4) alpha *= 0.5; else alpha *= alpha_mult; ++it;
return alpha_old;
}
virtual bool is_converged(double r, double = 0.0) {
// cout << "r = " << r << " alpha = " << alpha / alpha_mult << " count_pat = " << count_pat << endl;
if (!max_ratio_reached && r < first_res * alpha_max_ratio) {
alpha_max_ratio_reached = alpha_old; r_max_ratio_reached = r;
it_max_ratio_reached = it; max_ratio_reached = true;
}
if (max_ratio_reached && r < r_max_ratio_reached * 0.5
&& r > first_res * 1.1 && it <= it_max_ratio_reached+1) {
alpha_max_ratio_reached = alpha_old; r_max_ratio_reached = r;
it_max_ratio_reached = it;
}
if (count == 0 || r < conv_r)
{ conv_r = r; conv_alpha = alpha_old; count = 1; }
if (conv_r < first_res) ++count;
if (r < first_res * alpha_min_ratio)
{ count_pat = 0; return true; }
if (count >= 5 || (alpha < alpha_min && max_ratio_reached)) {
if (conv_r < first_res * 0.99) count_pat = 0;
if (/*gmm::random() * 50. < -log(conv_alpha)-4.0 ||*/ count_pat >= 3)
{ conv_r=r_max_ratio_reached; conv_alpha=alpha_max_ratio_reached; }
if (conv_r >= first_res * 0.9999) count_pat++;
return true;
}
return false;
}
S_default_newton_line_search(void) { count_pat = 0; }
};
template <typename Matrixt, typename MatrixBi, typename Vector,
typename Precond, typename local_solver, typename global_solver>
void Newton_additive_Schwarz(NewtonAS_struct<Matrixt, MatrixBi> &NS,
const Vector &u_,
iteration &iter, const Precond &P,
local_solver, global_solver) {
Vector &u = const_cast<Vector &>(u_);
typedef typename linalg_traits<Vector>::value_type value_type;
typedef typename number_traits<value_type>::magnitude_type mtype;
typedef actual_precond<Precond, local_solver, Matrixt> chgt_precond;
double residual = iter.get_resmax();
S_default_newton_line_search internal_ls;
S_default_newton_line_search external_ls;
typename chgt_precond::APrecond PP = chgt_precond::transform(P);
iter.set_rhsnorm(mtype(1));
iteration iternc(iter);
iternc.reduce_noisy(); iternc.set_maxiter(size_type(-1));
iteration iter2(iternc);
iteration iter3(iter2); iter3.reduce_noisy();
iteration iter4(iter3);
iternc.set_name("Local Newton");
iter2.set_name("Linear System for Global Newton");
iternc.set_resmax(residual/100.0);
iter3.set_resmax(residual/10000.0);
iter2.set_resmax(residual/1000.0);
iter4.set_resmax(residual/1000.0);
std::vector<value_type> rhs(NS.size()), x(NS.size()), d(NS.size());
std::vector<value_type> xi, xii, fi, di;
std::vector< std::vector<value_type> > vx(NS.get_vB().size());
for (size_type i = 0; i < NS.get_vB().size(); ++i) // for exact gradient
vx[i].resize(NS.size()); // for exact gradient
Matrixt Mloc, M(NS.size(), NS.size());
NS.compute_F(rhs, u);
mtype act_res=gmm::vect_norm2(rhs), act_res_new(0), precond_res = act_res;
mtype alpha;
while(!iter.finished(std::min(act_res, precond_res))) {
for (int SOR_step = 0; SOR_step >= 0; --SOR_step) {
gmm::clear(rhs);
for (size_type isd = 0; isd < NS.get_vB().size(); ++isd) {
const MatrixBi &Bi = (NS.get_vB())[isd];
size_type si = mat_ncols(Bi);
gmm::resize(Mloc, si, si);
xi.resize(si); xii.resize(si); fi.resize(si); di.resize(si);
iternc.init();
iternc.set_maxiter(30); // ?
if (iternc.get_noisy())
cout << "Non-linear local problem " << isd << endl;
gmm::clear(xi);
gmm::copy(u, x);
NS.compute_sub_F(fi, x, isd); gmm::scale(fi, value_type(-1));
mtype r = gmm::vect_norm2(fi), r_t(r);
if (r > value_type(0)) {
iternc.set_rhsnorm(std::max(r, mtype(1)));
while(!iternc.finished(r)) {
NS.compute_sub_tangent_matrix(Mloc, x, isd);
PP.build_with(Mloc);
iter3.init();
AS_local_solve(local_solver(), Mloc, di, fi, PP, iter3);
internal_ls.init_search(r, iternc.get_iteration());
do {
alpha = internal_ls.next_try();
gmm::add(xi, gmm::scaled(di, -alpha), xii);
gmm::mult(Bi, gmm::scaled(xii, -1.0), u, x);
NS.compute_sub_F(fi, x, isd); gmm::scale(fi, value_type(-1));
r_t = gmm::vect_norm2(fi);
} while (!internal_ls.is_converged(r_t));
if (alpha != internal_ls.converged_value()) {
alpha = internal_ls.converged_value();
gmm::add(xi, gmm::scaled(di, -alpha), xii);
gmm::mult(Bi, gmm::scaled(xii, -1.0), u, x);
NS.compute_sub_F(fi, x, isd); gmm::scale(fi, value_type(-1));
r_t = gmm::vect_norm2(fi);
}
gmm::copy(x, vx[isd]); // for exact gradient
if (iternc.get_noisy()) cout << "(step=" << alpha << ")\t";
++iternc; r = r_t; gmm::copy(xii, xi);
}
if (SOR_step) gmm::mult(Bi, gmm::scaled(xii, -1.0), u, u);
gmm::mult(Bi, gmm::scaled(xii, -1.0), rhs, rhs);
}
}
precond_res = gmm::vect_norm2(rhs);
if (SOR_step) cout << "SOR step residual = " << precond_res << endl;
if (precond_res < residual) break;
cout << "Precond residual = " << precond_res << endl;
}
iter2.init();
// solving linear system for the global Newton method
if (0) {
NS.compute_tangent_matrix(M, u);
add_schwarz_mat<Matrixt, MatrixBi, Precond, local_solver>
ASM(M, NS.get_vB(), iter4, P, iter.get_resmax());
AS_global_solve(global_solver(), ASM, d, rhs, iter2);
}
else { // for exact gradient
AS_exact_gradient<Matrixt, MatrixBi> eg(NS.get_vB());
for (size_type i = 0; i < NS.get_vB().size(); ++i) {
NS.compute_tangent_matrix(eg.vM[i], vx[i]);
}
eg.init();
gmres(eg, d, rhs, gmm::identity_matrix(), 50, iter2);
}
// gmm::add(gmm::scaled(rhs, 0.1), u); ++iter;
external_ls.init_search(act_res, iter.get_iteration());
do {
alpha = external_ls.next_try();
gmm::add(gmm::scaled(d, alpha), u, x);
NS.compute_F(rhs, x);
act_res_new = gmm::vect_norm2(rhs);
} while (!external_ls.is_converged(act_res_new));
if (alpha != external_ls.converged_value()) {
alpha = external_ls.converged_value();
gmm::add(gmm::scaled(d, alpha), u, x);
NS.compute_F(rhs, x);
act_res_new = gmm::vect_norm2(rhs);
}
if (iter.get_noisy() > 1) cout << endl;
act_res = act_res_new;
if (iter.get_noisy()) cout << "(step=" << alpha << ")\t unprecond res = " << act_res << " ";
++iter; gmm::copy(x, u);
}
}
}
#endif // GMM_SOLVERS_SCHWARZ_ADDITIVE_H__

210
gmm/gmm_solver_bfgs.h Normal file
View File

@ -0,0 +1,210 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2004-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_solver_bfgs.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date October 14 2004.
@brief Implements BFGS (Broyden, Fletcher, Goldfarb, Shanno) algorithm.
*/
#ifndef GMM_BFGS_H
#define GMM_BFGS_H
#include "gmm_kernel.h"
#include "gmm_iter.h"
namespace gmm {
// BFGS algorithm (Broyden, Fletcher, Goldfarb, Shanno)
// Quasi Newton method for optimization problems.
// with Wolfe Line search.
// delta[k] = x[k+1] - x[k]
// gamma[k] = grad f(x[k+1]) - grad f(x[k])
// H[0] = I
// BFGS : zeta[k] = delta[k] - H[k] gamma[k]
// DFP : zeta[k] = H[k] gamma[k]
// tau[k] = gamma[k]^T zeta[k]
// rho[k] = 1 / gamma[k]^T delta[k]
// BFGS : H[k+1] = H[k] + rho[k](zeta[k] delta[k]^T + delta[k] zeta[k]^T)
// - rho[k]^2 tau[k] delta[k] delta[k]^T
// DFP : H[k+1] = H[k] + rho[k] delta[k] delta[k]^T
// - (1/tau[k])zeta[k] zeta[k]^T
// Object representing the inverse of the Hessian
template <typename VECTOR> struct bfgs_invhessian {
typedef typename linalg_traits<VECTOR>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
std::vector<VECTOR> delta, gamma, zeta;
std::vector<T> tau, rho;
int version;
template<typename VEC1, typename VEC2> void hmult(const VEC1 &X, VEC2 &Y) {
copy(X, Y);
for (size_type k = 0 ; k < delta.size(); ++k) {
T xdelta = vect_sp(X, delta[k]), xzeta = vect_sp(X, zeta[k]);
switch (version) {
case 0 : // BFGS
add(scaled(zeta[k], rho[k]*xdelta), Y);
add(scaled(delta[k], rho[k]*(xzeta-rho[k]*tau[k]*xdelta)), Y);
break;
case 1 : // DFP
add(scaled(delta[k], rho[k]*xdelta), Y);
add(scaled(zeta[k], -xzeta/tau[k]), Y);
break;
}
}
}
void restart(void) {
delta.resize(0); gamma.resize(0); zeta.resize(0);
tau.resize(0); rho.resize(0);
}
template<typename VECT1, typename VECT2>
void update(const VECT1 &deltak, const VECT2 &gammak) {
T vsp = vect_sp(deltak, gammak);
if (vsp == T(0)) return;
size_type N = vect_size(deltak), k = delta.size();
VECTOR Y(N);
hmult(gammak, Y);
delta.resize(k+1); gamma.resize(k+1); zeta.resize(k+1);
tau.resize(k+1); rho.resize(k+1);
resize(delta[k], N); resize(gamma[k], N); resize(zeta[k], N);
gmm::copy(deltak, delta[k]);
gmm::copy(gammak, gamma[k]);
rho[k] = R(1) / vsp;
if (version == 0)
add(delta[k], scaled(Y, -1), zeta[k]);
else
gmm::copy(Y, zeta[k]);
tau[k] = vect_sp(gammak, zeta[k]);
}
bfgs_invhessian(int v = 0) { version = v; }
};
template <typename FUNCTION, typename DERIVATIVE, typename VECTOR>
void bfgs(const FUNCTION &f, const DERIVATIVE &grad, VECTOR &x,
int restart, iteration& iter, int version = 0,
double lambda_init=0.001, double print_norm=1.0) {
typedef typename linalg_traits<VECTOR>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
bfgs_invhessian<VECTOR> invhessian(version);
VECTOR r(vect_size(x)), d(vect_size(x)), y(vect_size(x)), r2(vect_size(x));
grad(x, r);
R lambda = lambda_init, valx = f(x), valy;
int nb_restart(0);
if (iter.get_noisy() >= 1) cout << "value " << valx / print_norm << " ";
while (! iter.finished_vect(r)) {
invhessian.hmult(r, d); gmm::scale(d, T(-1));
// Wolfe Line search
R derivative = gmm::vect_sp(r, d);
R lambda_min(0), lambda_max(0), m1 = 0.27, m2 = 0.57;
bool unbounded = true, blocked = false, grad_computed = false;
for(;;) {
add(x, scaled(d, lambda), y);
valy = f(y);
if (iter.get_noisy() >= 2) {
cout.precision(15);
cout << "Wolfe line search, lambda = " << lambda
<< " value = " << valy /print_norm << endl;
// << " derivative = " << derivative
// << " lambda min = " << lambda_min << " lambda max = "
// << lambda_max << endl; getchar();
}
if (valy <= valx + m1 * lambda * derivative) {
grad(y, r2); grad_computed = true;
T derivative2 = gmm::vect_sp(r2, d);
if (derivative2 >= m2*derivative) break;
lambda_min = lambda;
}
else {
lambda_max = lambda;
unbounded = false;
}
if (unbounded) lambda *= R(10);
else lambda = (lambda_max + lambda_min) / R(2);
if (lambda == lambda_max || lambda == lambda_min) break;
// valy <= R(2)*valx replaced by
// valy <= valx + gmm::abs(derivative)*lambda_init
// for compatibility with negative values (08.24.07).
if (valy <= valx + R(2)*gmm::abs(derivative)*lambda &&
(lambda < R(lambda_init*1E-8) ||
(!unbounded && lambda_max-lambda_min < R(lambda_init*1E-8))))
{ blocked = true; lambda = lambda_init; break; }
}
// Rank two update
++iter;
if (!grad_computed) grad(y, r2);
gmm::add(scaled(r2, -1), r);
if ((iter.get_iteration() % restart) == 0 || blocked) {
if (iter.get_noisy() >= 1) cout << "Restart\n";
invhessian.restart();
if (++nb_restart > 10) {
if (iter.get_noisy() >= 1) cout << "BFGS is blocked, exiting\n";
return;
}
}
else {
invhessian.update(gmm::scaled(d,lambda), gmm::scaled(r,-1));
nb_restart = 0;
}
copy(r2, r); copy(y, x); valx = valy;
if (iter.get_noisy() >= 1)
cout << "BFGS value " << valx/print_norm << "\t";
}
}
template <typename FUNCTION, typename DERIVATIVE, typename VECTOR>
inline void dfp(const FUNCTION &f, const DERIVATIVE &grad, VECTOR &x,
int restart, iteration& iter, int version = 1) {
bfgs(f, grad, x, restart, iter, version);
}
}
#endif

160
gmm/gmm_solver_bicgstab.h Normal file
View File

@ -0,0 +1,160 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
// This file is a modified version of bicgstab.h from ITL.
// See http://osl.iu.edu/research/itl/
// Following the corresponding Copyright notice.
//===========================================================================
//
// Copyright (c) 1998-2001, University of Notre Dame. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the University of Notre Dame nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//===========================================================================
/**@file gmm_solver_bicgstab.h
@author Andrew Lumsdaine <lums@osl.iu.edu>
@author Lie-Quan Lee <llee@osl.iu.edu>
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date October 13, 2002.
@brief BiCGStab iterative solver.
*/
#ifndef GMM_SOLVER_BICGSTAB_H__
#define GMM_SOLVER_BICGSTAB_H__
#include "gmm_kernel.h"
#include "gmm_iter.h"
namespace gmm {
/* ******************************************************************** */
/* BiConjugate Gradient Stabilized */
/* (preconditionned, with parametrable scalar product) */
/* ******************************************************************** */
template <typename Matrix, typename Vector, typename VectorB,
typename Preconditioner>
void bicgstab(const Matrix& A, Vector& x, const VectorB& b,
const Preconditioner& M, iteration &iter) {
typedef typename linalg_traits<Vector>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
typedef typename temporary_dense_vector<Vector>::vector_type temp_vector;
T rho_1, rho_2(0), alpha(0), beta, omega(0);
temp_vector p(vect_size(x)), phat(vect_size(x)), s(vect_size(x)),
shat(vect_size(x)),
t(vect_size(x)), v(vect_size(x)), r(vect_size(x)), rtilde(vect_size(x));
gmm::mult(A, gmm::scaled(x, -T(1)), b, r);
gmm::copy(r, rtilde);
R norm_r = gmm::vect_norm2(r);
iter.set_rhsnorm(gmm::vect_norm2(b));
if (iter.get_rhsnorm() == 0.0) { clear(x); return; }
while (!iter.finished(norm_r)) {
rho_1 = gmm::vect_sp(rtilde, r);
if (rho_1 == T(0)) {
if (iter.get_maxiter() == size_type(-1))
{ GMM_ASSERT1(false, "Bicgstab failed to converge"); }
else { GMM_WARNING1("Bicgstab failed to converge"); return; }
}
if (iter.first())
gmm::copy(r, p);
else {
if (omega == T(0)) {
if (iter.get_maxiter() == size_type(-1))
{ GMM_ASSERT1(false, "Bicgstab failed to converge"); }
else { GMM_WARNING1("Bicgstab failed to converge"); return; }
}
beta = (rho_1 / rho_2) * (alpha / omega);
gmm::add(gmm::scaled(v, -omega), p);
gmm::add(r, gmm::scaled(p, beta), p);
}
gmm::mult(M, p, phat);
gmm::mult(A, phat, v);
alpha = rho_1 / gmm::vect_sp(v, rtilde);
gmm::add(r, gmm::scaled(v, -alpha), s);
if (iter.finished_vect(s))
{ gmm::add(gmm::scaled(phat, alpha), x); break; }
gmm::mult(M, s, shat);
gmm::mult(A, shat, t);
omega = gmm::vect_sp(t, s) / gmm::vect_norm2_sqr(t);
gmm::add(gmm::scaled(phat, alpha), x);
gmm::add(gmm::scaled(shat, omega), x);
gmm::add(s, gmm::scaled(t, -omega), r);
norm_r = gmm::vect_norm2(r);
rho_2 = rho_1;
++iter;
}
}
template <typename Matrix, typename Vector, typename VectorB,
typename Preconditioner>
void bicgstab(const Matrix& A, const Vector& x, const VectorB& b,
const Preconditioner& M, iteration &iter)
{ bicgstab(A, linalg_const_cast(x), b, M, iter); }
}
#endif // GMM_SOLVER_BICGSTAB_H__

180
gmm/gmm_solver_cg.h Normal file
View File

@ -0,0 +1,180 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
// This file is a modified version of cg.h from ITL.
// See http://osl.iu.edu/research/itl/
// Following the corresponding Copyright notice.
//===========================================================================
//
// Copyright (c) 1998-2001, University of Notre Dame. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the University of Notre Dame nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//===========================================================================
/**@file gmm_solver_cg.h
@author Andrew Lumsdaine <lums@osl.iu.edu>
@author Lie-Quan Lee <llee@osl.iu.edu>
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date October 13, 2002.
@brief Conjugate gradient iterative solver.
*/
#ifndef GMM_SOLVER_CG_H__
#define GMM_SOLVER_CG_H__
#include "gmm_kernel.h"
#include "gmm_iter.h"
namespace gmm {
/* ******************************************************************** */
/* conjugate gradient */
/* (preconditionned, with parametrable additional scalar product) */
/* ******************************************************************** */
template <typename Matrix, typename Matps, typename Precond,
typename Vector1, typename Vector2>
void cg(const Matrix& A, Vector1& x, const Vector2& b, const Matps& PS,
const Precond &P, iteration &iter) {
typedef typename temporary_dense_vector<Vector1>::vector_type temp_vector;
typedef typename linalg_traits<Vector1>::value_type T;
T rho, rho_1(0), a;
temp_vector p(vect_size(x)), q(vect_size(x)), r(vect_size(x)),
z(vect_size(x));
iter.set_rhsnorm(gmm::sqrt(gmm::abs(vect_hp(PS, b, b))));
if (iter.get_rhsnorm() == 0.0)
clear(x);
else {
mult(A, scaled(x, T(-1)), b, r);
mult(P, r, z);
rho = vect_hp(PS, z, r);
copy(z, p);
while (!iter.finished_vect(r)) {
if (!iter.first()) {
mult(P, r, z);
rho = vect_hp(PS, z, r);
add(z, scaled(p, rho / rho_1), p);
}
mult(A, p, q);
a = rho / vect_hp(PS, q, p);
add(scaled(p, a), x);
add(scaled(q, -a), r);
rho_1 = rho;
++iter;
}
}
}
template <typename Matrix, typename Matps, typename Precond,
typename Vector1, typename Vector2>
void cg(const Matrix& A, Vector1& x, const Vector2& b, const Matps& PS,
const gmm::identity_matrix &, iteration &iter) {
typedef typename temporary_dense_vector<Vector1>::vector_type temp_vector;
typedef typename linalg_traits<Vector1>::value_type T;
T rho, rho_1(0), a;
temp_vector p(vect_size(x)), q(vect_size(x)), r(vect_size(x));
iter.set_rhsnorm(gmm::sqrt(gmm::abs(vect_hp(PS, b, b))));
if (iter.get_rhsnorm() == 0.0)
clear(x);
else {
mult(A, scaled(x, T(-1)), b, r);
rho = vect_hp(PS, r, r);
copy(r, p);
while (!iter.finished_vect(r)) {
if (!iter.first()) {
rho = vect_hp(PS, r, r);
add(r, scaled(p, rho / rho_1), p);
}
mult(A, p, q);
a = rho / vect_hp(PS, q, p);
add(scaled(p, a), x);
add(scaled(q, -a), r);
rho_1 = rho;
++iter;
}
}
}
template <typename Matrix, typename Matps, typename Precond,
typename Vector1, typename Vector2> inline
void cg(const Matrix& A, const Vector1& x, const Vector2& b, const Matps& PS,
const Precond &P, iteration &iter)
{ cg(A, linalg_const_cast(x), b, PS, P, iter); }
template <typename Matrix, typename Precond,
typename Vector1, typename Vector2> inline
void cg(const Matrix& A, Vector1& x, const Vector2& b,
const Precond &P, iteration &iter)
{ cg(A, x , b, identity_matrix(), P, iter); }
template <typename Matrix, typename Precond,
typename Vector1, typename Vector2> inline
void cg(const Matrix& A, const Vector1& x, const Vector2& b,
const Precond &P, iteration &iter)
{ cg(A, x , b , identity_matrix(), P , iter); }
}
#endif // GMM_SOLVER_CG_H__

View File

@ -0,0 +1,165 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_solver_constrained_cg.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date October 13, 2002.
@brief Constrained conjugate gradient. */
// preconditionning does not work
#ifndef GMM_SOLVER_CCG_H__
#define GMM_SOLVER_CCG_H__
#include "gmm_kernel.h"
#include "gmm_iter.h"
namespace gmm {
template <typename CMatrix, typename CINVMatrix, typename Matps,
typename VectorX>
void pseudo_inverse(const CMatrix &C, CINVMatrix &CINV,
const Matps& /* PS */, VectorX&) {
// compute the pseudo inverse of the non-square matrix C such
// CINV = inv(C * trans(C)) * C.
// based on a conjugate gradient method.
// optimisable : copie de la ligne, precalcul de C * trans(C).
typedef VectorX TmpVec;
typedef typename linalg_traits<VectorX>::value_type value_type;
size_type nr = mat_nrows(C), nc = mat_ncols(C);
TmpVec d(nr), e(nr), l(nc), p(nr), q(nr), r(nr);
value_type rho, rho_1, alpha;
clear(d);
clear(CINV);
for (size_type i = 0; i < nr; ++i) {
d[i] = 1.0; rho = 1.0;
clear(e);
copy(d, r);
copy(d, p);
while (rho >= 1E-38) { /* conjugate gradient to compute e */
/* which is the i nd row of inv(C * trans(C)) */
mult(gmm::transposed(C), p, l);
mult(C, l, q);
alpha = rho / vect_sp(p, q);
add(scaled(p, alpha), e);
add(scaled(q, -alpha), r);
rho_1 = rho;
rho = vect_sp(r, r);
add(r, scaled(p, rho / rho_1), p);
}
mult(transposed(C), e, l); /* l is the i nd row of CINV */
// cout << "l = " << l << endl;
clean(l, 1E-15);
copy(l, mat_row(CINV, i));
d[i] = 0.0;
}
}
/** Compute the minimum of @f$ 1/2((Ax).x) - bx @f$ under the contraint @f$ Cx <= f @f$ */
template < typename Matrix, typename CMatrix, typename Matps,
typename VectorX, typename VectorB, typename VectorF,
typename Preconditioner >
void constrained_cg(const Matrix& A, const CMatrix& C, VectorX& x,
const VectorB& b, const VectorF& f,const Matps& PS,
const Preconditioner& M, iteration &iter) {
typedef typename temporary_dense_vector<VectorX>::vector_type TmpVec;
typedef typename temporary_vector<CMatrix>::vector_type TmpCVec;
typedef row_matrix<TmpCVec> TmpCmat;
typedef typename linalg_traits<VectorX>::value_type value_type;
value_type rho = 1.0, rho_1, lambda, gamma;
TmpVec p(vect_size(x)), q(vect_size(x)), q2(vect_size(x)),
r(vect_size(x)), old_z(vect_size(x)), z(vect_size(x)),
memox(vect_size(x));
std::vector<bool> satured(mat_nrows(C));
clear(p);
iter.set_rhsnorm(sqrt(vect_sp(PS, b, b)));
if (iter.get_rhsnorm() == 0.0) iter.set_rhsnorm(1.0);
TmpCmat CINV(mat_nrows(C), mat_ncols(C));
pseudo_inverse(C, CINV, PS, x);
while(true) {
// computation of residu
copy(z, old_z);
copy(x, memox);
mult(A, scaled(x, -1.0), b, r);
mult(M, r, z); // preconditionner not coherent
bool transition = false;
for (size_type i = 0; i < mat_nrows(C); ++i) {
value_type al = vect_sp(mat_row(C, i), x) - f[i];
if (al >= -1.0E-15) {
if (!satured[i]) { satured[i] = true; transition = true; }
value_type bb = vect_sp(mat_row(CINV, i), z);
if (bb > 0.0) add(scaled(mat_row(C, i), -bb), z);
}
else
satured[i] = false;
}
// descent direction
rho_1 = rho; rho = vect_sp(PS, r, z); // ...
if (iter.finished(rho)) break;
if (iter.get_noisy() > 0 && transition) std::cout << "transition\n";
if (transition || iter.first()) gamma = 0.0;
else gamma = std::max(0.0, (rho - vect_sp(PS, old_z, z) ) / rho_1);
// std::cout << "gamma = " << gamma << endl;
// itl::add(r, itl::scaled(p, gamma), p);
add(z, scaled(p, gamma), p); // ...
++iter;
// one dimensionnal optimization
mult(A, p, q);
lambda = rho / vect_sp(PS, q, p);
for (size_type i = 0; i < mat_nrows(C); ++i)
if (!satured[i]) {
value_type bb = vect_sp(mat_row(C, i), p) - f[i];
if (bb > 0.0)
lambda = std::min(lambda, (f[i]-vect_sp(mat_row(C, i), x)) / bb);
}
add(x, scaled(p, lambda), x);
add(memox, scaled(x, -1.0), memox);
}
}
}
#endif // GMM_SOLVER_CCG_H__

173
gmm/gmm_solver_gmres.h Normal file
View File

@ -0,0 +1,173 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
// This file is a modified version of gmres.h from ITL.
// See http://osl.iu.edu/research/itl/
// Following the corresponding Copyright notice.
//===========================================================================
//
// Copyright (c) 1998-2001, University of Notre Dame. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the University of Notre Dame nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//===========================================================================
/**@file gmm_solver_gmres.h
@author Andrew Lumsdaine <lums@osl.iu.edu>
@author Lie-Quan Lee <llee@osl.iu.edu>
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date October 13, 2002.
@brief GMRES (Generalized Minimum Residual) iterative solver.
*/
#ifndef GMM_KRYLOV_GMRES_H
#define GMM_KRYLOV_GMRES_H
#include "gmm_kernel.h"
#include "gmm_iter.h"
#include "gmm_modified_gram_schmidt.h"
namespace gmm {
/** Generalized Minimum Residual
This solve the unsymmetric linear system Ax = b using restarted GMRES.
See: Y. Saad and M. Schulter. GMRES: A generalized minimum residual
algorithm for solving nonsysmmetric linear systems, SIAM
J. Sci. Statist. Comp. 7(1986), pp, 856-869
*/
template <typename Mat, typename Vec, typename VecB, typename Precond,
typename Basis >
void gmres(const Mat &A, Vec &x, const VecB &b, const Precond &M,
int restart, iteration &outer, Basis& KS) {
typedef typename linalg_traits<Vec>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
std::vector<T> w(vect_size(x)), r(vect_size(x)), u(vect_size(x));
std::vector<T> c_rot(restart+1), s_rot(restart+1), s(restart+1);
gmm::dense_matrix<T> H(restart+1, restart);
#ifdef GMM_USES_MPI
double t_ref, t_prec = MPI_Wtime(), t_tot = 0;
static double tmult_tot = 0.0;
t_ref = MPI_Wtime();
cout << "GMRES " << endl;
#endif
mult(M,b,r);
outer.set_rhsnorm(gmm::vect_norm2(r));
if (outer.get_rhsnorm() == 0.0) { clear(x); return; }
mult(A, scaled(x, T(-1)), b, w);
mult(M, w, r);
R beta = gmm::vect_norm2(r), beta_old = beta;
int blocked = 0;
iteration inner = outer;
inner.reduce_noisy();
inner.set_maxiter(restart);
inner.set_name("GMRes inner");
while (! outer.finished(beta)) {
gmm::copy(gmm::scaled(r, R(1)/beta), KS[0]);
gmm::clear(s);
s[0] = beta;
size_type i = 0; inner.init();
do {
mult(A, KS[i], u);
mult(M, u, KS[i+1]);
orthogonalize(KS, mat_col(H, i), i);
R a = gmm::vect_norm2(KS[i+1]);
H(i+1, i) = T(a);
gmm::scale(KS[i+1], T(1) / a);
for (size_type k = 0; k < i; ++k)
Apply_Givens_rotation_left(H(k,i), H(k+1,i), c_rot[k], s_rot[k]);
Givens_rotation(H(i,i), H(i+1,i), c_rot[i], s_rot[i]);
Apply_Givens_rotation_left(H(i,i), H(i+1,i), c_rot[i], s_rot[i]);
Apply_Givens_rotation_left(s[i], s[i+1], c_rot[i], s_rot[i]);
++inner, ++outer, ++i;
} while (! inner.finished(gmm::abs(s[i])));
upper_tri_solve(H, s, i, false);
combine(KS, s, x, i);
mult(A, gmm::scaled(x, T(-1)), b, w);
mult(M, w, r);
beta_old = std::min(beta, beta_old); beta = gmm::vect_norm2(r);
if (int(inner.get_iteration()) < restart -1 || beta_old <= beta)
++blocked; else blocked = 0;
if (blocked > 10) {
if (outer.get_noisy()) cout << "Gmres is blocked, exiting\n";
break;
}
#ifdef GMM_USES_MPI
t_tot = MPI_Wtime() - t_ref;
cout << "temps GMRES : " << t_tot << endl;
#endif
}
}
template <typename Mat, typename Vec, typename VecB, typename Precond >
void gmres(const Mat &A, Vec &x, const VecB &b,
const Precond &M, int restart, iteration& outer) {
typedef typename linalg_traits<Vec>::value_type T;
modified_gram_schmidt<T> orth(restart, vect_size(x));
gmres(A, x, b, M, restart, outer, orth);
}
}
#endif

805
gmm/gmm_solver_idgmres.h Normal file
View File

@ -0,0 +1,805 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2003-2017 Yves Renard, Caroline Lecalvez
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_solver_idgmres.h
@author Caroline Lecalvez <Caroline.Lecalvez@gmm.insa-tlse.fr>
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date October 6, 2003.
@brief Implicitly restarted and deflated Generalized Minimum Residual.
*/
#ifndef GMM_IDGMRES_H
#define GMM_IDGMRES_H
#include "gmm_kernel.h"
#include "gmm_iter.h"
#include "gmm_dense_sylvester.h"
namespace gmm {
template <typename T> compare_vp {
bool operator()(const std::pair<T, size_type> &a,
const std::pair<T, size_type> &b) const
{ return (gmm::abs(a.first) > gmm::abs(b.first)); }
}
struct idgmres_state {
size_type m, tb_deb, tb_def, p, k, nb_want, nb_unwant;
size_type nb_nolong, tb_deftot, tb_defwant, conv, nb_un, fin;
bool ok;
idgmres_state(size_type mm, size_type pp, size_type kk)
: m(mm), tb_deb(1), tb_def(0), p(pp), k(kk), nb_want(0),
nb_unwant(0), nb_nolong(0), tb_deftot(0), tb_defwant(0),
conv(0), nb_un(0), fin(0), ok(false); {}
}
idgmres_state(size_type mm, size_type pp, size_type kk)
: m(mm), tb_deb(1), tb_def(0), p(pp), k(kk), nb_want(0),
nb_unwant(0), nb_nolong(0), tb_deftot(0), tb_defwant(0),
conv(0), nb_un(0), fin(0), ok(false); {}
template <typename CONT, typename IND>
apply_permutation(CONT &cont, const IND &ind) {
size_type m = ind.end() - ind.begin();
std::vector<bool> sorted(m, false);
for (size_type l = 0; l < m; ++l)
if (!sorted[l] && ind[l] != l) {
typeid(cont[0]) aux = cont[l];
k = ind[l];
cont[l] = cont[k];
sorted[l] = true;
for(k2 = ind[k]; k2 != l; k2 = ind[k]) {
cont[k] = cont[k2];
sorted[k] = true;
k = k2;
}
cont[k] = aux;
}
}
/** Implicitly restarted and deflated Generalized Minimum Residual
See: C. Le Calvez, B. Molina, Implicitly restarted and deflated
FOM and GMRES, numerical applied mathematics,
(30) 2-3 (1999) pp191-212.
@param A Real or complex unsymmetric matrix.
@param x initial guess vector and final result.
@param b right hand side
@param M preconditionner
@param m size of the subspace between two restarts
@param p number of converged ritz values seeked
@param k size of the remaining Krylov subspace when the p ritz values
have not yet converged 0 <= p <= k < m.
@param tol_vp : tolerance on the ritz values.
@param outer
@param KS
*/
template < typename Mat, typename Vec, typename VecB, typename Precond,
typename Basis >
void idgmres(const Mat &A, Vec &x, const VecB &b, const Precond &M,
size_type m, size_type p, size_type k, double tol_vp,
iteration &outer, Basis& KS) {
typedef typename linalg_traits<Mat>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
R a, beta;
idgmres_state st(m, p, k);
std::vector<T> w(vect_size(x)), r(vect_size(x)), u(vect_size(x));
std::vector<T> c_rot(m+1), s_rot(m+1), s(m+1);
std::vector<T> y(m+1), ztest(m+1), gam(m+1);
std::vector<T> gamma(m+1);
gmm::dense_matrix<T> H(m+1, m), Hess(m+1, m),
Hobl(m+1, m), W(vect_size(x), m+1);
gmm::clear(H);
outer.set_rhsnorm(gmm::vect_norm2(b));
if (outer.get_rhsnorm() == 0.0) { clear(x); return; }
mult(A, scaled(x, -1.0), b, w);
mult(M, w, r);
beta = gmm::vect_norm2(r);
iteration inner = outer;
inner.reduce_noisy();
inner.set_maxiter(m);
inner.set_name("GMRes inner iter");
while (! outer.finished(beta)) {
gmm::copy(gmm::scaled(r, 1.0/beta), KS[0]);
gmm::clear(s);
s[0] = beta;
gmm::copy(s, gamma);
inner.set_maxiter(m - st.tb_deb + 1);
size_type i = st.tb_deb - 1; inner.init();
do {
mult(A, KS[i], u);
mult(M, u, KS[i+1]);
orthogonalize_with_refinment(KS, mat_col(H, i), i);
H(i+1, i) = a = gmm::vect_norm2(KS[i+1]);
gmm::scale(KS[i+1], R(1) / a);
gmm::copy(mat_col(H, i), mat_col(Hess, i));
gmm::copy(mat_col(H, i), mat_col(Hobl, i));
for (size_type l = 0; l < i; ++l)
Apply_Givens_rotation_left(H(l,i), H(l+1,i), c_rot[l], s_rot[l]);
Givens_rotation(H(i,i), H(i+1,i), c_rot[i], s_rot[i]);
Apply_Givens_rotation_left(H(i,i), H(i+1,i), c_rot[i], s_rot[i]);
H(i+1, i) = T(0);
Apply_Givens_rotation_left(s[i], s[i+1], c_rot[i], s_rot[i]);
++inner, ++outer, ++i;
} while (! inner.finished(gmm::abs(s[i])));
if (inner.converged()) {
gmm::copy(s, y);
upper_tri_solve(H, y, i, false);
combine(KS, y, x, i);
mult(A, gmm::scaled(x, T(-1)), b, w);
mult(M, w, r);
beta = gmm::vect_norm2(r); // + verif sur beta ... à faire
break;
}
gmm::clear(gam); gam[m] = s[i];
for (size_type l = m; l > 0; --l)
Apply_Givens_rotation_left(gam[l-1], gam[l], gmm::conj(c_rot[l-1]),
-s_rot[l-1]);
mult(KS.mat(), gam, r);
beta = gmm::vect_norm2(r);
mult(Hess, scaled(y, T(-1)), gamma, ztest);
// En fait, d'après Caroline qui s'y connait ztest et gam devrait
// être confondus
// Quand on aura vérifié que ça marche, il faudra utiliser gam à la
// place de ztest.
if (st.tb_def < p) {
T nss = H(m,m-1) / ztest[m];
nss /= gmm::abs(nss); // ns à calculer plus tard aussi
gmm::copy(KS.mat(), W); gmm::copy(scaled(r, nss /beta), mat_col(W, m));
// Computation of the oblique matrix
sub_interval SUBI(0, m);
add(scaled(sub_vector(ztest, SUBI), -Hobl(m, m-1) / ztest[m]),
sub_vector(mat_col(Hobl, m-1), SUBI));
Hobl(m, m-1) *= nss * beta / ztest[m];
/* **************************************************************** */
/* Locking */
/* **************************************************************** */
// Computation of the Ritz eigenpairs.
std::vector<std::complex<R> > eval(m);
dense_matrix<T> YB(m-st.tb_def, m-st.tb_def);
std::vector<char> pure(m-st.tb_def, 0);
gmm::clear(YB);
select_eval(Hobl, eval, YB, pure, st);
if (st.conv != 0) {
// DEFLATION using the QR Factorization of YB
T alpha = Lock(W, Hobl,
sub_matrix(YB, sub_interval(0, m-st.tb_def)),
sub_interval(st.tb_def, m-st.tb_def),
(st.tb_defwant < p));
// ns *= alpha; // à calculer plus tard ??
// V(:,m+1) = alpha*V(:, m+1); ça devait servir à qlq chose ...
// Clean the portions below the diagonal corresponding
// to the lock Schur vectors
for (size_type j = st.tb_def; j < st.tb_deftot; ++j) {
if ( pure[j-st.tb_def] == 0)
gmm::clear(sub_vector(mat_col(Hobl,j), sub_interval(j+1,m-j)));
else if (pure[j-st.tb_def] == 1) {
gmm::clear(sub_matrix(Hobl, sub_interval(j+2,m-j-1),
sub_interval(j, 2)));
++j;
}
else GMM_ASSERT3(false, "internal error");
}
if (!st.ok) {
// attention si m = 0;
size_type mm = std::min(k+st.nb_unwant+st.nb_nolong, m-1);
if (eval_sort[m-mm-1].second != R(0)
&& eval_sort[m-mm-1].second == -eval_sort[m-mm].second) ++mm;
std::vector<complex<R> > shifts(m-mm);
for (size_type i = 0; i < m-mm; ++i)
shifts[i] = eval_sort[i].second;
apply_shift_to_Arnoldi_factorization(W, Hobl, shifts, mm,
m-mm, true);
st.fin = mm;
}
else
st.fin = st.tb_deftot;
/* ************************************************************** */
/* Purge */
/* ************************************************************** */
if (st.nb_nolong + st.nb_unwant > 0) {
std::vector<std::complex<R> > eval(m);
dense_matrix<T> YB(st.fin, st.tb_deftot);
std::vector<char> pure(st.tb_deftot, 0);
gmm::clear(YB);
st.nb_un = st.nb_nolong + st.nb_unwant;
select_eval_for_purging(Hobl, eval, YB, pure, st);
T alpha = Lock(W, Hobl, YB, sub_interval(0, st.fin), ok);
// Clean the portions below the diagonal corresponding
// to the unwanted lock Schur vectors
for (size_type j = 0; j < st.tb_deftot; ++j) {
if ( pure[j] == 0)
gmm::clear(sub_vector(mat_col(Hobl,j), sub_interval(j+1,m-j)));
else if (pure[j] == 1) {
gmm::clear(sub_matrix(Hobl, sub_interval(j+2,m-j-1),
sub_interval(j, 2)));
++j;
}
else GMM_ASSERT3(false, "internal error");
}
gmm::dense_matrix<T> z(st.nb_un, st.fin - st.nb_un);
sub_interval SUBI(0, st.nb_un), SUBJ(st.nb_un, st.fin - st.nb_un);
sylvester(sub_matrix(Hobl, SUBI),
sub_matrix(Hobl, SUBJ),
sub_matrix(gmm::scaled(Hobl, -T(1)), SUBI, SUBJ), z);
}
}
}
}
}
template < typename Mat, typename Vec, typename VecB, typename Precond >
void idgmres(const Mat &A, Vec &x, const VecB &b,
const Precond &M, size_type m, iteration& outer) {
typedef typename linalg_traits<Mat>::value_type T;
modified_gram_schmidt<T> orth(m, vect_size(x));
gmres(A, x, b, M, m, outer, orth);
}
// Lock stage of an implicit restarted Arnoldi process.
// 1- QR factorization of YB through Householder matrices
// Q(Rl) = YB
// (0 )
// 2- Update of the Arnoldi factorization.
// H <- Q*HQ, W <- WQ
// 3- Restore the Hessemberg form of H.
template <typename T, typename MATYB>
void Lock(gmm::dense_matrix<T> &W, gmm::dense_matrix<T> &H,
const MATYB &YB, const sub_interval SUB,
bool restore, T &ns) {
size_type n = mat_nrows(W), m = mat_ncols(W) - 1;
size_type ncols = mat_ncols(YB), nrows = mat_nrows(YB);
size_type begin = min(SUB); end = max(SUB) - 1;
sub_interval SUBR(0, nrows), SUBC(0, ncols);
T alpha(1);
GMM_ASSERT2(((end-begin) == ncols) && (m == mat_nrows(H))
&& (m+1 == mat_ncols(H)), "dimensions mismatch");
// DEFLATION using the QR Factorization of YB
dense_matrix<T> QR(n_rows, n_rows);
gmmm::copy(YB, sub_matrix(QR, SUBR, SUBC));
gmm::clear(submatrix(QR, SUBR, sub_interval(ncols, nrows-ncols)));
qr_factor(QR);
apply_house_left(QR, sub_matrix(H, SUB));
apply_house_right(QR, sub_matrix(H, SUBR, SUB));
apply_house_right(QR, sub_matrix(W, sub_interval(0, n), SUB));
// Restore to the initial block hessenberg form
if (restore) {
// verifier quand m = 0 ...
gmm::dense_matrix tab_p(end - st.tb_deftot, end - st.tb_deftot);
gmm::copy(identity_matrix(), tab_p);
for (size_type j = end-1; j >= st.tb_deftot+2; --j) {
size_type jm = j-1;
std::vector<T> v(jm - st.tb_deftot);
sub_interval SUBtot(st.tb_deftot, jm - st.tb_deftot);
sub_interval SUBtot2(st.tb_deftot, end - st.tb_deftot);
gmm::copy(sub_vector(mat_row(H, j), SUBtot), v);
house_vector_last(v);
w.resize(end);
col_house_update(sub_matrix(H, SUBI, SUBtot), v, w);
w.resize(end - st.tb_deftot);
row_house_update(sub_matrix(H, SUBtot, SUBtot2), v, w);
gmm::clear(sub_vector(mat_row(H, j),
sub_interval(st.tb_deftot, j-1-st.tb_deftot)));
w.resize(end - st.tb_deftot);
col_house_update(sub_matrix(tab_p, sub_interval(0, end-st.tb_deftot),
sub_interval(0, jm-st.tb_deftot)), v, w);
w.resize(n);
col_house_update(sub_matrix(W, sub_interval(0, n), SUBtot), v, w);
}
// restore positive subdiagonal elements
std::vector<T> d(fin-st.tb_deftot); d[0] = T(1);
// We compute d[i+1] in order
// (d[i+1] * H(st.tb_deftot+i+1,st.tb_deftoti)) / d[i]
// be equal to |H(st.tb_deftot+i+1,st.tb_deftot+i))|.
for (size_type j = 0; j+1 < end-st.tb_deftot; ++j) {
T e = H(st.tb_deftot+j, st.tb_deftot+j-1);
d[j+1] = (e == T(0)) ? T(1) : d[j] * gmm::abs(e) / e;
scale(sub_vector(mat_row(H, st.tb_deftot+j+1),
sub_interval(st.tb_deftot, m-st.tb_deftot)), d[j+1]);
scale(mat_col(H, st.tb_deftot+j+1), T(1) / d[j+1]);
scale(mat_col(W, st.tb_deftot+j+1), T(1) / d[j+1]);
}
alpha = tab_p(end-st.tb_deftot-1, end-st.tb_deftot-1) / d[end-st.tb_deftot-1];
alpha /= gmm::abs(alpha);
scale(mat_col(W, m), alpha);
}
return alpha;
}
// Apply p implicit shifts to the Arnoldi factorization
// AV = VH+H(k+p+1,k+p) V(:,k+p+1) e_{k+p}*
// and produces the following new Arnoldi factorization
// A(VQ) = (VQ)(Q*HQ)+H(k+p+1,k+p) V(:,k+p+1) e_{k+p}* Q
// where only the first k columns are relevant.
//
// Dan Sorensen and Richard J. Radke, 11/95
template<typename T, typename C>
apply_shift_to_Arnoldi_factorization(dense_matrix<T> V, dense_matrix<T> H,
std::vector<C> Lambda, size_type &k,
size_type p, bool true_shift = false) {
size_type k1 = 0, num = 0, kend = k+p, kp1 = k + 1;
bool mark = false;
T c, s, x, y, z;
dense_matrix<T> q(1, kend);
gmm::clear(q); q(0,kend-1) = T(1);
std::vector<T> hv(3), w(std::max(kend, mat_nrows(V)));
for(size_type jj = 0; jj < p; ++jj) {
// compute and apply a bulge chase sweep initiated by the
// implicit shift held in w(jj)
if (abs(Lambda[jj].real()) == 0.0) {
// apply a real shift using 2 by 2 Givens rotations
for (size_type k1 = 0, k2 = 0; k2 != kend-1; k1 = k2+1) {
k2 = k1;
while (h(k2+1, k2) != T(0) && k2 < kend-1) ++k2;
Givens_rotation(H(k1, k1) - Lambda[jj], H(k1+1, k1), c, s);
for (i = k1; i <= k2; ++i) {
if (i > k1) Givens_rotation(H(i, i-1), H(i+1, i-1), c, s);
// Ne pas oublier de nettoyer H(i+1,i-1) (le mettre à zéro).
// Vérifier qu'au final H(i+1,i) est bien un réel positif.
// apply rotation from left to rows of H
row_rot(sub_matrix(H, sub_interval(i,2), sub_interval(i, kend-i)),
c, s, 0, 0);
// apply rotation from right to columns of H
size_type ip2 = std::min(i+2, kend);
col_rot(sub_matrix(H, sub_interval(0, ip2), sub_interval(i, 2))
c, s, 0, 0);
// apply rotation from right to columns of V
col_rot(V, c, s, i, i+1);
// accumulate e' Q so residual can be updated k+p
Apply_Givens_rotation_left(q(0,i), q(0,i+1), c, s);
// peut être que nous utilisons G au lieu de G* et que
// nous allons trop loin en k2.
}
}
num = num + 1;
}
else {
// Apply a double complex shift using 3 by 3 Householder
// transformations
if (jj == p || mark)
mark = false; // skip application of conjugate shift
else {
num = num + 2; // mark that a complex conjugate
mark = true; // pair has been applied
// Indices de fin de boucle à surveiller... de près !
for (size_type k1 = 0, k3 = 0; k3 != kend-2; k1 = k3+1) {
k3 = k1;
while (h(k3+1, k3) != T(0) && k3 < kend-2) ++k3;
size_type k2 = k1+1;
x = H(k1,k1) * H(k1,k1) + H(k1,k2) * H(k2,k1)
- 2.0*Lambda[jj].real() * H(k1,k1) + gmm::abs_sqr(Lambda[jj]);
y = H(k2,k1) * (H(k1,k1) + H(k2,k2) - 2.0*Lambda[jj].real());
z = H(k2+1,k2) * H(k2,k1);
for (size_type i = k1; i <= k3; ++i) {
if (i > k1) {
x = H(i, i-1);
y = H(i+1, i-1);
z = H(i+2, i-1);
// Ne pas oublier de nettoyer H(i+1,i-1) et H(i+2,i-1)
// (les mettre à zéro).
}
hv[0] = x; hv[1] = y; hv[2] = z;
house_vector(v);
// Vérifier qu'au final H(i+1,i) est bien un réel positif
// apply transformation from left to rows of H
w.resize(kend-i);
row_house_update(sub_matrix(H, sub_interval(i, 2),
sub_interval(i, kend-i)), v, w);
// apply transformation from right to columns of H
size_type ip3 = std::min(kend, i + 3);
w.resize(ip3);
col_house_update(sub_matrix(H, sub_interval(0, ip3),
sub_interval(i, 2)), v, w);
// apply transformation from right to columns of V
w.resize(mat_nrows(V));
col_house_update(sub_matrix(V, sub_interval(0, mat_nrows(V)),
sub_interval(i, 2)), v, w);
// accumulate e' Q so residual can be updated k+p
w.resize(1);
col_house_update(sub_matrix(q, sub_interval(0,1),
sub_interval(i,2)), v, w);
}
}
// clean up step with Givens rotation
i = kend-2;
c = x; s = y;
if (i > k1) Givens_rotation(H(i, i-1), H(i+1, i-1), c, s);
// Ne pas oublier de nettoyer H(i+1,i-1) (le mettre à zéro).
// Vérifier qu'au final H(i+1,i) est bien un réel positif.
// apply rotation from left to rows of H
row_rot(sub_matrix(H, sub_interval(i,2), sub_interval(i, kend-i)),
c, s, 0, 0);
// apply rotation from right to columns of H
size_type ip2 = std::min(i+2, kend);
col_rot(sub_matrix(H, sub_interval(0, ip2), sub_interval(i, 2))
c, s, 0, 0);
// apply rotation from right to columns of V
col_rot(V, c, s, i, i+1);
// accumulate e' Q so residual can be updated k+p
Apply_Givens_rotation_left(q(0,i), q(0,i+1), c, s);
}
}
}
// update residual and store in the k+1 -st column of v
k = kend - num;
scale(mat_col(V, kend), q(0, k));
if (k < mat_nrows(H)) {
if (true_shift)
gmm::copy(mat_col(V, kend), mat_col(V, k));
else
// v(:,k+1) = v(:,kend+1) + v(:,k+1)*h(k+1,k);
// v(:,k+1) = v(:,kend+1) ;
gmm::add(scaled(mat_col(V, kend), H(kend, kend-1)),
scaled(mat_col(V, k), H(k, k-1)), mat_col(V, k));
}
H(k, k-1) = vect_norm2(mat_col(V, k));
scale(mat_col(V, kend), T(1) / H(k, k-1));
}
template<typename MAT, typename EVAL, typename PURE>
void select_eval(const MAT &Hobl, EVAL &eval, MAT &YB, PURE &pure,
idgmres_state &st) {
typedef typename linalg_traits<MAT>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type m = st.m;
// Computation of the Ritz eigenpairs.
col_matrix< std::vector<T> > evect(m-st.tb_def, m-st.tb_def);
// std::vector<std::complex<R> > eval(m);
std::vector<R> ritznew(m, T(-1));
// dense_matrix<T> evect_lock(st.tb_def, st.tb_def);
sub_interval SUB1(st.tb_def, m-st.tb_def);
implicit_qr_algorithm(sub_matrix(Hobl, SUB1),
sub_vector(eval, SUB1), evect);
sub_interval SUB2(0, st.tb_def);
implicit_qr_algorithm(sub_matrix(Hobl, SUB2),
sub_vector(eval, SUB2), /* evect_lock */);
for (size_type l = st.tb_def; l < m; ++l)
ritznew[l] = gmm::abs(evect(m-st.tb_def-1, l-st.tb_def) * Hobl(m, m-1));
std::vector< std::pair<T, size_type> > eval_sort(m);
for (size_type l = 0; l < m; ++l)
eval_sort[l] = std::pair<T, size_type>(eval[l], l);
std::sort(eval_sort.begin(), eval_sort.end(), compare_vp());
std::vector<size_type> index(m);
for (size_type l = 0; l < m; ++l) index[l] = eval_sort[l].second;
std::vector<bool> kept(m, false);
std::fill(kept.begin(), kept.begin()+st.tb_def, true);
apply_permutation(eval, index);
apply_permutation(evect, index);
apply_permutation(ritznew, index);
apply_permutation(kept, index);
// Which are the eigenvalues that converged ?
//
// nb_want is the number of eigenvalues of
// Hess(tb_def+1:n,tb_def+1:n) that converged and are WANTED
//
// nb_unwant is the number of eigenvalues of
// Hess(tb_def+1:n,tb_def+1:n) that converged and are UNWANTED
//
// nb_nolong is the number of eigenvalues of
// Hess(1:tb_def,1:tb_def) that are NO LONGER WANTED.
//
// tb_deftot is the number of the deflated eigenvalues
// that is tb_def + nb_want + nb_unwant
//
// tb_defwant is the number of the wanted deflated eigenvalues
// that is tb_def + nb_want - nb_nolong
st.nb_want = 0, st.nb_unwant = 0, st.nb_nolong = 0;
size_type j, ind;
for (j = 0, ind = 0; j < m-p; ++j) {
if (ritznew[j] == R(-1)) {
if (std::imag(eval[j]) != R(0)) {
st.nb_nolong += 2; ++j; // à adapter dans le cas complexe ...
}
else st.nb_nolong++;
}
else {
if (ritznew[j]
< tol_vp * gmm::abs(eval[j])) {
for (size_type l = 0, l < m-st.tb_def; ++l)
YB(l, ind) = std::real(evect(l, j));
kept[j] = true;
++j; ++st.nb_unwant; ind++;
if (std::imag(eval[j]) != R(0)) {
for (size_type l = 0, l < m-st.tb_def; ++l)
YB(l, ind) = std::imag(evect(l, j));
pure[ind-1] = 1;
pure[ind] = 2;
kept[j] = true;
st.nb_unwant++;
++ind;
}
}
}
}
for (; j < m; ++j) {
if (ritznew[j] != R(-1)) {
for (size_type l = 0, l < m-st.tb_def; ++l)
YB(l, ind) = std::real(evect(l, j));
pure[ind] = 1;
++ind;
kept[j] = true;
++st.nb_want;
if (ritznew[j]
< tol_vp * gmm::abs(eval[j])) {
for (size_type l = 0, l < m-st.tb_def; ++l)
YB(l, ind) = std::imag(evect(l, j));
pure[ind] = 2;
j++;
kept[j] = true;
st.nb_want++;
++ind;
}
}
}
std::vector<T> shift(m - st.tb_def - st.nb_want - st.nb_unwant);
for (size_type j = 0, i = 0; j < m; ++j)
if (!kept[j]) shift[i++] = eval[j];
// st.conv (st.nb_want+st.nb_unwant) is the number of eigenpairs that
// have just converged.
// st.tb_deftot is the total number of eigenpairs that have converged.
size_type st.conv = ind;
size_type st.tb_deftot = st.tb_def + st.conv;
size_type st.tb_defwant = st.tb_def + st.nb_want - st.nb_nolong;
sub_interval SUBYB(0, st.conv);
if ( st.tb_defwant >= p ) { // An invariant subspace has been found.
st.nb_unwant = 0;
st.nb_want = p + st.nb_nolong - st.tb_def;
st.tb_defwant = p;
if ( pure[st.conv - st.nb_want + 1] == 2 ) {
++st.nb_want; st.tb_defwant = ++p;// il faudrait que ce soit un p local
}
SUBYB = sub_interval(st.conv - st.nb_want, st.nb_want);
// YB = YB(:, st.conv-st.nb_want+1 : st.conv); // On laisse en suspend ..
// pure = pure(st.conv-st.nb_want+1 : st.conv,1); // On laisse suspend ..
st.conv = st.nb_want;
st.tb_deftot = st.tb_def + st.conv;
st.ok = true;
}
}
template<typename MAT, typename EVAL, typename PURE>
void select_eval_for_purging(const MAT &Hobl, EVAL &eval, MAT &YB,
PURE &pure, idgmres_state &st) {
typedef typename linalg_traits<MAT>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
size_type m = st.m;
// Computation of the Ritz eigenpairs.
col_matrix< std::vector<T> > evect(st.tb_deftot, st.tb_deftot);
sub_interval SUB1(0, st.tb_deftot);
implicit_qr_algorithm(sub_matrix(Hobl, SUB1),
sub_vector(eval, SUB1), evect);
std::fill(eval.begin() + st.tb_deftot, eval.end(), std::complex<R>(0));
std::vector< std::pair<T, size_type> > eval_sort(m);
for (size_type l = 0; l < m; ++l)
eval_sort[l] = std::pair<T, size_type>(eval[l], l);
std::sort(eval_sort.begin(), eval_sort.end(), compare_vp());
std::vector<bool> sorted(m);
std::fill(sorted.begin(), sorted.end(), false);
std::vector<size_type> ind(m);
for (size_type l = 0; l < m; ++l) ind[l] = eval_sort[l].second;
std::vector<bool> kept(m, false);
std::fill(kept.begin(), kept.begin()+st.tb_def, true);
apply_permutation(eval, ind);
apply_permutation(evect, ind);
size_type j;
for (j = 0; j < st.tb_deftot; ++j) {
for (size_type l = 0, l < st.tb_deftot; ++l)
YB(l, j) = std::real(evect(l, j));
if (std::imag(eval[j]) != R(0)) {
for (size_type l = 0, l < m-st.tb_def; ++l)
YB(l, j+1) = std::imag(evect(l, j));
pure[j] = 1;
pure[j+1] = 2;
j += 2;
}
else ++j;
}
}
}
#endif

210
gmm/gmm_solver_qmr.h Normal file
View File

@ -0,0 +1,210 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
// This file is a modified version of qmr.h from ITL.
// See http://osl.iu.edu/research/itl/
// Following the corresponding Copyright notice.
//===========================================================================
//
// Copyright (c) 1997-2001, The Trustees of Indiana University.
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the University of Notre Dame nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE TRUSTEES OF INDIANA UNIVERSITY AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
// OF INDIANA UNIVERSITY AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//===========================================================================
/**@file gmm_solver_qmr.h
@author Andrew Lumsdaine <lums@osl.iu.edu>
@author Lie-Quan Lee <llee@osl.iu.edu>
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date October 13, 2002.
@brief Quasi-Minimal Residual iterative solver.
*/
#ifndef GMM_QMR_H
#define GMM_QMR_H
#include "gmm_kernel.h"
#include "gmm_iter.h"
namespace gmm {
/** Quasi-Minimal Residual.
This routine solves the unsymmetric linear system Ax = b using
the Quasi-Minimal Residual method.
See: R. W. Freund and N. M. Nachtigal, A quasi-minimal residual
method for non-Hermitian linear systems, Numerical Math.,
60(1991), pp. 315-339
Preconditioner - Incomplete LU, Incomplete LU with threshold,
SSOR or identity_preconditioner.
*/
template <typename Matrix, typename Vector, typename VectorB,
typename Precond1>
void qmr(const Matrix &A, Vector &x, const VectorB &b, const Precond1 &M1,
iteration& iter) {
typedef typename linalg_traits<Vector>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
T delta(0), ep(0), beta(0), theta_1(0), gamma_1(0);
T theta(0), gamma(1), eta(-1);
R rho_1(0), rho, xi;
typedef typename temporary_vector<Vector>::vector_type TmpVec;
size_type nn = vect_size(x);
TmpVec r(nn), v_tld(nn), y(nn), w_tld(nn), z(nn), v(nn), w(nn);
TmpVec y_tld(nn), z_tld(nn), p(nn), q(nn), p_tld(nn), d(nn), s(nn);
iter.set_rhsnorm(double(gmm::vect_norm2(b)));
if (iter.get_rhsnorm() == 0.0) { clear(x); return; }
gmm::mult(A, gmm::scaled(x, T(-1)), b, r);
gmm::copy(r, v_tld);
gmm::left_mult(M1, v_tld, y);
rho = gmm::vect_norm2(y);
gmm::copy(r, w_tld);
gmm::transposed_right_mult(M1, w_tld, z);
xi = gmm::vect_norm2(z);
while (! iter.finished_vect(r)) {
if (rho == R(0) || xi == R(0)) {
if (iter.get_maxiter() == size_type(-1))
{ GMM_ASSERT1(false, "QMR failed to converge"); }
else { GMM_WARNING1("QMR failed to converge"); return; }
}
gmm::copy(gmm::scaled(v_tld, T(R(1)/rho)), v);
gmm::scale(y, T(R(1)/rho));
gmm::copy(gmm::scaled(w_tld, T(R(1)/xi)), w);
gmm::scale(z, T(R(1)/xi));
delta = gmm::vect_sp(z, y);
if (delta == T(0)) {
if (iter.get_maxiter() == size_type(-1))
{ GMM_ASSERT1(false, "QMR failed to converge"); }
else { GMM_WARNING1("QMR failed to converge"); return; }
}
gmm::right_mult(M1, y, y_tld);
gmm::transposed_left_mult(M1, z, z_tld);
if (iter.first()) {
gmm::copy(y_tld, p);
gmm::copy(z_tld, q);
} else {
gmm::add(y_tld, gmm::scaled(p, -(T(xi * delta) / ep)), p);
gmm::add(z_tld, gmm::scaled(q, -(T(rho * delta) / ep)), q);
}
gmm::mult(A, p, p_tld);
ep = gmm::vect_sp(q, p_tld);
if (ep == T(0)) {
if (iter.get_maxiter() == size_type(-1))
{ GMM_ASSERT1(false, "QMR failed to converge"); }
else { GMM_WARNING1("QMR failed to converge"); return; }
}
beta = ep / delta;
if (beta == T(0)) {
if (iter.get_maxiter() == size_type(-1))
{ GMM_ASSERT1(false, "QMR failed to converge"); }
else { GMM_WARNING1("QMR failed to converge"); return; }
}
gmm::add(p_tld, gmm::scaled(v, -beta), v_tld);
gmm::left_mult(M1, v_tld, y);
rho_1 = rho;
rho = gmm::vect_norm2(y);
gmm::mult(gmm::transposed(A), q, w_tld);
gmm::add(w_tld, gmm::scaled(w, -beta), w_tld);
gmm::transposed_right_mult(M1, w_tld, z);
xi = gmm::vect_norm2(z);
gamma_1 = gamma;
theta_1 = theta;
theta = rho / (gamma_1 * beta);
gamma = T(1) / gmm::sqrt(T(1) + gmm::sqr(theta));
if (gamma == T(0)) {
if (iter.get_maxiter() == size_type(-1))
{ GMM_ASSERT1(false, "QMR failed to converge"); }
else { GMM_WARNING1("QMR failed to converge"); return; }
}
eta = -eta * T(rho_1) * gmm::sqr(gamma) / (beta * gmm::sqr(gamma_1));
if (iter.first()) {
gmm::copy(gmm::scaled(p, eta), d);
gmm::copy(gmm::scaled(p_tld, eta), s);
} else {
T tmp = gmm::sqr(theta_1 * gamma);
gmm::add(gmm::scaled(p, eta), gmm::scaled(d, tmp), d);
gmm::add(gmm::scaled(p_tld, eta), gmm::scaled(s, tmp), s);
}
gmm::add(d, x);
gmm::add(gmm::scaled(s, T(-1)), r);
++iter;
}
}
}
#endif

424
gmm/gmm_std.h Normal file
View File

@ -0,0 +1,424 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_std.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>,
@author Julien Pommier <Julien.Pommier@insa-toulouse.fr>
@date June 01, 1995.
@brief basic setup for gmm (includes, typedefs etc.)
*/
#ifndef GMM_STD_H__
#define GMM_STD_H__
//#include <getfem/getfem_arch_config.h>
#ifndef __USE_STD_IOSTREAM
# define __USE_STD_IOSTREAM
#endif
#ifndef __USE_BSD
# define __USE_BSD
#endif
#ifndef __USE_ISOC99
# define __USE_ISOC99
#endif
#if defined(_MSC_VER) && _MSC_VER >= 1400 // Secure versions for VC++
# define GMM_SECURE_CRT
# define SECURE_NONCHAR_SSCANF sscanf_s
# define SECURE_NONCHAR_FSCANF fscanf_s
# define SECURE_STRNCPY(a, la, b, lb) strncpy_s(a, la, b, lb)
# define SECURE_FOPEN(F, filename, mode) (*(F) = 0, fopen_s(F, filename, mode))
# define SECURE_SPRINTF1(S, l, st, p1) sprintf_s(S, l, st, p1)
# define SECURE_SPRINTF2(S, l, st, p1, p2) sprintf_s(S, l, st, p1, p2)
# define SECURE_SPRINTF4(S, l, st, p1, p2, p3, p4) sprintf_s(S, l, st, p1, p2, p3, p4)
# define SECURE_STRDUP(s) _strdup(s)
# ifndef _SCL_SECURE_NO_DEPRECATE
# error Add the option /D_SCL_SECURE_NO_DEPRECATE to the compilation command
# endif
#else
# define SECURE_NONCHAR_SSCANF sscanf
# define SECURE_NONCHAR_FSCANF fscanf
# define SECURE_STRNCPY(a, la, b, lb) strncpy(a, b, lb)
# define SECURE_FOPEN(F, filename, mode) ((*(F)) = fopen(filename, mode))
# define SECURE_SPRINTF1(S, l, st, p1) sprintf(S, st, p1)
# define SECURE_SPRINTF2(S, l, st, p1, p2) sprintf(S, st, p1, p2)
# define SECURE_SPRINTF4(S, l, st, p1, p2, p3, p4) sprintf(S, st, p1, p2, p3, p4)
# define SECURE_STRDUP(s) strdup(s)
#endif
inline void GMM_NOPERATION_(int) { }
#define GMM_NOPERATION(a) { GMM_NOPERATION_(abs(&(a) != &(a))); }
/* ********************************************************************** */
/* Compilers detection. */
/* ********************************************************************** */
/* for sun CC 5.0 ...
#if defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x500
# include <stdcomp.h>
# undef _RWSTD_NO_CLASS_PARTIAL_SPEC
# undef _RWSTD_NO_NAMESPACE
#endif
*/
/* for VISUAL C++ ...
#if defined(_MSC_VER) // && !defined(__MWERKS__)
#define _GETFEM_MSVCPP_ _MSC_VER
#endif
*/
#if defined(__GNUC__)
# if (__GNUC__ < 4)
# error : PLEASE UPDATE g++ TO AT LEAST 4.8 VERSION
# endif
#endif
/* ********************************************************************** */
/* C++ Standard Headers. */
/* ********************************************************************** */
#include <clocale>
#include <cstdlib>
#include <cstddef>
#include <cmath>
#include <cstring>
#include <cctype>
#include <cassert>
#include <climits>
#include <iostream>
//#include <ios>
#include <fstream>
#include <ctime>
#include <exception>
#include <typeinfo>
#include <stdexcept>
#include <iterator>
#include <algorithm>
#include <vector>
#include <deque>
#include <string>
#include <complex>
#include <limits>
#include <sstream>
#include <numeric>
#include <memory>
#include <array>
#include <locale.h>
namespace std {
#if defined(__GNUC__) && (__cplusplus <= 201103L)
template<typename _Tp>
struct _MakeUniq
{ typedef unique_ptr<_Tp> __single_object; };
template<typename _Tp>
struct _MakeUniq<_Tp[]>
{ typedef unique_ptr<_Tp[]> __array; };
template<typename _Tp, size_t _Bound>
struct _MakeUniq<_Tp[_Bound]>
{ struct __invalid_type { }; };
/// std::make_unique for single objects
template<typename _Tp, typename... _Args>
inline typename _MakeUniq<_Tp>::__single_object
make_unique(_Args&&... __args)
{ return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
/// std::make_unique for arrays of unknown bound
template<typename _Tp>
inline typename _MakeUniq<_Tp>::__array
make_unique(size_t __num)
{ return unique_ptr<_Tp>(new typename remove_extent<_Tp>::type[__num]()); }
/// Disable std::make_unique for arrays of known bound
template<typename _Tp, typename... _Args>
inline typename _MakeUniq<_Tp>::__invalid_type
make_unique(_Args&&...) = delete;
#endif
// Should simply be replaced by std::shared_ptr<T[]> when it will be supported
// by the STL
template <typename T> class shared_array_ptr : shared_ptr<T> {
public:
shared_array_ptr() {}
shared_array_ptr(T *q) : std::shared_ptr<T>(q, default_delete<T[]>()) {}
template <typename Y> shared_array_ptr(const std::shared_ptr<Y> &p, T *q)
: std::shared_ptr<T>(p, q) {}
T *get() const { return shared_ptr<T>::get(); }
T& operator*() const { return shared_ptr<T>::operator*(); }
T* operator->() const { return shared_ptr<T>::operator->(); }
};
template <typename T> shared_array_ptr<T> make_shared_array(size_t num)
{ return shared_array_ptr<T>(new T[num]); }
}
#ifdef GETFEM_HAVE_OPENMP
#include <omp.h>
/**number of OpenMP threads*/
inline size_t num_threads(){return omp_get_max_threads();}
/**index of the current thread*/
inline size_t this_thread() {return omp_get_thread_num();}
/**is the program running in the parallel section*/
inline bool me_is_multithreaded_now(){return static_cast<bool>(omp_in_parallel());}
#else
inline size_t num_threads(){return size_t(1);}
inline size_t this_thread() {return size_t(0);}
inline bool me_is_multithreaded_now(){return false;}
#endif
namespace gmm {
using std::endl; using std::cout; using std::cerr;
using std::ends; using std::cin; using std::isnan;
#ifdef _WIN32
class standard_locale {
std::string cloc;
std::locale cinloc;
public :
inline standard_locale(void) : cinloc(cin.getloc())
{
if (!me_is_multithreaded_now()){
cloc=setlocale(LC_NUMERIC, 0);
setlocale(LC_NUMERIC,"C");
}
}
inline ~standard_locale() {
if (!me_is_multithreaded_now())
setlocale(LC_NUMERIC, cloc.c_str());
}
};
#else
/**this is the above solutions for linux, but I still needs to be tested.*/
//class standard_locale {
// locale_t oldloc;
// locale_t temploc;
//public :
// inline standard_locale(void) : oldloc(uselocale((locale_t)0))
// {
// temploc = newlocale(LC_NUMERIC, "C", NULL);
// uselocale(temploc);
// }
// inline ~standard_locale()
// {
// uselocale(oldloc);
// freelocale(temploc);
// }
//};
class standard_locale {
std::string cloc;
std::locale cinloc;
public :
inline standard_locale(void)
: cloc(setlocale(LC_NUMERIC, 0)), cinloc(cin.getloc())
{ setlocale(LC_NUMERIC,"C"); cin.imbue(std::locale("C")); }
inline ~standard_locale()
{ setlocale(LC_NUMERIC, cloc.c_str()); cin.imbue(cinloc); }
};
#endif
class stream_standard_locale {
std::locale cloc;
std::ios &io;
public :
inline stream_standard_locale(std::ios &i)
: cloc(i.getloc()), io(i) { io.imbue(std::locale("C")); }
inline ~stream_standard_locale() { io.imbue(cloc); }
};
/* ******************************************************************* */
/* Clock functions. */
/* ******************************************************************* */
# if defined(HAVE_SYS_TIMES)
inline double uclock_sec(void) {
static double ttclk = 0.;
if (ttclk == 0.) ttclk = sysconf(_SC_CLK_TCK);
tms t; times(&t); return double(t.tms_utime) / ttclk;
}
# else
inline double uclock_sec(void)
{ return double(clock())/double(CLOCKS_PER_SEC); }
# endif
/* ******************************************************************** */
/* Fixed size integer types. */
/* ******************************************************************** */
// Remark : the test program dynamic_array tests the length of
// resulting integers
template <size_t s> struct fixed_size_integer_generator {
typedef void int_base_type;
typedef void uint_base_type;
};
template <> struct fixed_size_integer_generator<sizeof(char)> {
typedef signed char int_base_type;
typedef unsigned char uint_base_type;
};
template <> struct fixed_size_integer_generator<sizeof(short int)
- ((sizeof(short int) == sizeof(char)) ? 78 : 0)> {
typedef signed short int int_base_type;
typedef unsigned short int uint_base_type;
};
template <> struct fixed_size_integer_generator<sizeof(int)
- ((sizeof(int) == sizeof(short int)) ? 59 : 0)> {
typedef signed int int_base_type;
typedef unsigned int uint_base_type;
};
template <> struct fixed_size_integer_generator<sizeof(long)
- ((sizeof(int) == sizeof(long)) ? 93 : 0)> {
typedef signed long int_base_type;
typedef unsigned long uint_base_type;
};
template <> struct fixed_size_integer_generator<sizeof(long long)
- ((sizeof(long long) == sizeof(long)) ? 99 : 0)> {
typedef signed long long int_base_type;
typedef unsigned long long uint_base_type;
};
typedef fixed_size_integer_generator<1>::int_base_type int8_type;
typedef fixed_size_integer_generator<1>::uint_base_type uint8_type;
typedef fixed_size_integer_generator<2>::int_base_type int16_type;
typedef fixed_size_integer_generator<2>::uint_base_type uint16_type;
typedef fixed_size_integer_generator<4>::int_base_type int32_type;
typedef fixed_size_integer_generator<4>::uint_base_type uint32_type;
typedef fixed_size_integer_generator<8>::int_base_type int64_type;
typedef fixed_size_integer_generator<8>::uint_base_type uint64_type;
// #if INT_MAX == 32767
// typedef signed int int16_type;
// typedef unsigned int uint16_type;
// #elif SHRT_MAX == 32767
// typedef signed short int int16_type;
// typedef unsigned short int uint16_type;
// #else
// # error "impossible to build a 16 bits integer"
// #endif
// #if INT_MAX == 2147483647
// typedef signed int int32_type;
// typedef unsigned int uint32_type;
// #elif SHRT_MAX == 2147483647
// typedef signed short int int32_type;
// typedef unsigned short int uint32_type;
// #elif LONG_MAX == 2147483647
// typedef signed long int int32_type;
// typedef unsigned long int uint32_type;
// #else
// # error "impossible to build a 32 bits integer"
// #endif
// #if INT_MAX == 9223372036854775807L || INT_MAX == 9223372036854775807
// typedef signed int int64_type;
// typedef unsigned int uint64_type;
// #elif LONG_MAX == 9223372036854775807L || LONG_MAX == 9223372036854775807
// typedef signed long int int64_type;
// typedef unsigned long int uint64_type;
// #elif LLONG_MAX == 9223372036854775807LL || LLONG_MAX == 9223372036854775807L || LLONG_MAX == 9223372036854775807
// typedef signed long long int int64_type;
// typedef unsigned long long int uint64_type;
// #else
// # error "impossible to build a 64 bits integer"
// #endif
#if defined(__GNUC__) && !defined(__ICC)
/*
g++ can issue a warning at each usage of a function declared with this special attribute
(also works with typedefs and variable declarations)
*/
# define IS_DEPRECATED __attribute__ ((__deprecated__))
/*
the specified function is inlined at any optimization level
*/
# define ALWAYS_INLINE __attribute__((always_inline))
#else
# define IS_DEPRECATED
# define ALWAYS_INLINE
#endif
}
/* ******************************************************************** */
/* Import/export classes and interfaces from a shared library */
/* ******************************************************************** */
#if defined(EXPORTED_TO_SHARED_LIB)
# if defined(_MSC_VER) || defined(__INTEL_COMPILER)
# define APIDECL __declspec(dllexport)
# elif defined(__GNUC__)
# define __attribute__((visibility("default")))
# else
# define APIDECL
# endif
# if defined(IMPORTED_FROM_SHARED_LIB)
# error INTENTIONAL COMPILCATION ERROR, DLL IMPORT AND EXPORT ARE INCOMPITABLE
# endif
#endif
#if defined(IMPORTED_FROM_SHARED_LIB)
# if defined(_MSC_VER) || defined(__INTEL_COMPILER)
# define APIDECL __declspec(dllimport)
# else
# define APIDECL
# endif
# if defined(EXPORTED_TO_SHARED_LIB)
# error INTENTIONAL COMPILCATION ERROR, DLL IMPORT AND EXPORT ARE INCOMPITABLE
# endif
#endif
#ifndef EXPORTED_TO_SHARED_LIB
# ifndef IMPORTED_FROM_SHARED_LIB
# define APIDECL //empty, used during static linking
# endif
#endif
#endif /* GMM_STD_H__ */

224
gmm/gmm_sub_index.h Normal file
View File

@ -0,0 +1,224 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_sub_index.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date October 13, 2002.
@brief sub-indices.
*/
#ifndef GMM_SUB_INDEX_H__
#define GMM_SUB_INDEX_H__
#include "gmm_def.h"
namespace gmm {
/* ******************************************************************** */
/* sub indices */
/* ******************************************************************** */
struct basic_index : public std::vector<size_t> {
mutable size_type nb_ref;
// size_type key1; faire la somme des composantes
// const basic_index *rind; rindex s'il existe
size_t operator[](size_type i) const {
return (i < size()) ? std::vector<size_t>::operator[](i) : size_type(-1);
}
basic_index() : nb_ref(1) {}
basic_index(size_type j) : std::vector<size_t>(j), nb_ref(1) {}
template <typename IT> basic_index(IT b, IT e)
: std::vector<size_t>(e-b), nb_ref(1) { std::copy(b, e, begin()); }
basic_index(const basic_index *pbi) : nb_ref(1) {
const_iterator it = pbi->begin(), ite = pbi->end();
size_type i = 0;
for ( ; it != ite; ++it) i = std::max(i, *it);
resize(i+1); std::fill(begin(), end(), size_type(-1));
for (it = pbi->begin(), i = 0; it != ite; ++it, ++i)
std::vector<size_t>::operator[](*it) = i;
}
void swap(size_type i, size_type j) {
std::swap(std::vector<size_t>::operator[](i),
std::vector<size_t>::operator[](j));
}
};
typedef basic_index *pbasic_index;
struct index_generator {
template <typename IT> static pbasic_index create_index(IT begin, IT end)
{ return new basic_index(begin, end); }
static pbasic_index create_rindex(pbasic_index pbi)
{ return new basic_index(pbi); }
static void attach(pbasic_index pbi) { if (pbi) pbi->nb_ref++; }
static void unattach(pbasic_index pbi)
{ if (pbi && --(pbi->nb_ref) == 0) delete pbi; }
};
struct sub_index {
size_type first_, last_;
typedef basic_index base_type;
typedef base_type::const_iterator const_iterator;
mutable pbasic_index ind;
mutable pbasic_index rind;
void comp_extr(void) {
std::vector<size_t>::const_iterator it = ind->begin(), ite = ind->end();
if (it != ite) { first_=last_= *it; ++it; } else { first_=last_= 0; }
for (; it != ite; ++it)
{ first_ = std::min(first_, *it); last_ = std::max(last_, *it); }
}
inline void test_rind(void) const
{ if (!rind) rind = index_generator::create_rindex(ind); }
size_type size(void) const { return ind->size(); }
size_type first(void) const { return first_; }
size_type last(void) const { return last_; }
size_type index(size_type i) const { return (*ind)[i]; }
size_type rindex(size_type i) const {
test_rind();
if (i < rind->size()) return (*rind)[i]; else return size_type(-1);
}
const_iterator begin(void) const { return ind->begin(); }
const_iterator end(void) const { return ind->end(); }
const_iterator rbegin(void) const { test_rind(); return rind->begin(); }
const_iterator rend(void) const { test_rind(); return rind->end(); }
sub_index() : ind(0), rind(0) {}
template <typename IT> sub_index(IT it, IT ite)
: ind(index_generator::create_index(it, ite)),
rind(0) { comp_extr(); }
template <typename CONT> sub_index(const CONT &c)
: ind(index_generator::create_index(c.begin(), c.end())),
rind(0) { comp_extr(); }
~sub_index() {
index_generator::unattach(rind);
index_generator::unattach(ind);
}
sub_index(const sub_index &si) : first_(si.first_), last_(si.last_),
ind(si.ind), rind(si.rind)
{ index_generator::attach(rind); index_generator::attach(ind); }
sub_index &operator =(const sub_index &si) {
index_generator::unattach(rind);
index_generator::unattach(ind);
ind = si.ind; rind = si.rind;
index_generator::attach(rind);
index_generator::attach(ind);
first_ = si.first_; last_ = si.last_;
return *this;
}
};
struct unsorted_sub_index : public sub_index {
typedef basic_index base_type;
typedef base_type::const_iterator const_iterator;
template <typename IT> unsorted_sub_index(IT it, IT ite)
: sub_index(it, ite) {}
template <typename CONT> unsorted_sub_index(const CONT &c)
: sub_index(c) {}
unsorted_sub_index() {}
unsorted_sub_index(const unsorted_sub_index &si) : sub_index((const sub_index &)(si)) { }
unsorted_sub_index &operator =(const unsorted_sub_index &si)
{ sub_index::operator =(si); return *this; }
void swap(size_type i, size_type j) {
GMM_ASSERT2(ind->nb_ref <= 1, "Operation not allowed on this index");
if (rind) rind->swap((*ind)[i], (*ind)[j]);
ind->swap(i, j);
}
};
inline std::ostream &operator << (std::ostream &o, const sub_index &si) {
o << "sub_index(";
if (si.size() != 0) o << si.index(0);
for (size_type i = 1; i < si.size(); ++i) o << ", " << si.index(i);
o << ")";
return o;
}
struct sub_interval {
size_type min, max;
size_type size(void) const { return max - min; }
size_type first(void) const { return min; }
size_type last(void) const { return max; }
size_type index(size_type i) const { return min + i; }
size_type step(void) const { return 1; }
size_type rindex(size_type i) const
{ if (i >= min && i < max) return i - min; return size_type(-1); }
sub_interval(size_type mi, size_type l) : min(mi), max(mi+l) {}
sub_interval() {}
};
inline std::ostream &operator << (std::ostream &o, const sub_interval &si)
{ o << "sub_interval(" << si.min << ", " << si.size() << ")"; return o; }
struct sub_slice {
size_type min, max, N;
size_type size(void) const { return (max - min) / N; }
size_type first(void) const { return min; }
size_type last(void) const { return (min == max) ? max : max+1-N; }
size_type step(void) const { return N; }
size_type index(size_type i) const { return min + N * i; }
size_type rindex(size_type i) const {
if (i >= min && i < max)
{ size_type j = (i - min); if (j % N == 0) return j / N; }
return size_type(-1);
}
sub_slice(size_type mi, size_type l, size_type n)
: min(mi), max(mi+l*n), N(n) {}
sub_slice(void) {}
};
inline std::ostream &operator << (std::ostream &o, const sub_slice &si) {
o << "sub_slice(" << si.min << ", " << si.size() << ", " << si.step()
<< ")"; return o;
}
template<class SUBI> struct index_is_sorted
{ typedef linalg_true bool_type; };
template<> struct index_is_sorted<unsorted_sub_index>
{ typedef linalg_false bool_type; };
}
#endif // GMM_SUB_INDEX_H__

406
gmm/gmm_sub_matrix.h Normal file
View File

@ -0,0 +1,406 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_sub_matrix.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date October 13, 2002.
@brief Generic sub-matrices.
*/
#ifndef GMM_SUB_MATRIX_H__
#define GMM_SUB_MATRIX_H__
#include "gmm_sub_vector.h"
namespace gmm {
/* ********************************************************************* */
/* sub row matrices type */
/* ********************************************************************* */
template <typename PT, typename SUBI1, typename SUBI2>
struct gen_sub_row_matrix {
typedef gen_sub_row_matrix<PT, SUBI1, SUBI2> this_type;
typedef typename std::iterator_traits<PT>::value_type M;
typedef M * CPT;
typedef typename std::iterator_traits<PT>::reference ref_M;
typedef typename select_ref<typename linalg_traits<M>
::const_row_iterator, typename linalg_traits<M>::row_iterator,
PT>::ref_type iterator;
typedef typename linalg_traits<this_type>::reference reference;
typedef typename linalg_traits<this_type>::porigin_type porigin_type;
SUBI1 si1;
SUBI2 si2;
iterator begin_;
porigin_type origin;
reference operator()(size_type i, size_type j) const
{ return linalg_traits<M>::access(begin_ + si1.index(i), si2.index(j)); }
size_type nrows(void) const { return si1.size(); }
size_type ncols(void) const { return si2.size(); }
gen_sub_row_matrix(ref_M m, const SUBI1 &s1, const SUBI2 &s2)
: si1(s1), si2(s2), begin_(mat_row_begin(m)),
origin(linalg_origin(m)) {}
gen_sub_row_matrix() {}
gen_sub_row_matrix(const gen_sub_row_matrix<CPT, SUBI1, SUBI2> &cr) :
si1(cr.si1), si2(cr.si2), begin_(cr.begin_),origin(cr.origin) {}
};
template <typename PT, typename SUBI1, typename SUBI2>
struct gen_sub_row_matrix_iterator {
typedef gen_sub_row_matrix<PT, SUBI1, SUBI2> this_type;
typedef typename modifiable_pointer<PT>::pointer MPT;
typedef typename std::iterator_traits<PT>::value_type M;
typedef typename select_ref<typename linalg_traits<M>
::const_row_iterator, typename linalg_traits<M>::row_iterator,
PT>::ref_type ITER;
typedef ITER value_type;
typedef ITER *pointer;
typedef ITER &reference;
typedef ptrdiff_t difference_type;
typedef size_t size_type;
typedef std::random_access_iterator_tag iterator_category;
typedef gen_sub_row_matrix_iterator<PT, SUBI1, SUBI2> iterator;
ITER it;
SUBI1 si1;
SUBI2 si2;
size_type ii;
iterator operator ++(int) { iterator tmp = *this; ii++; return tmp; }
iterator operator --(int) { iterator tmp = *this; ii--; return tmp; }
iterator &operator ++() { ii++; return *this; }
iterator &operator --() { ii--; return *this; }
iterator &operator +=(difference_type i) { ii += i; return *this; }
iterator &operator -=(difference_type i) { ii -= i; return *this; }
iterator operator +(difference_type i) const
{ iterator itt = *this; return (itt += i); }
iterator operator -(difference_type i) const
{ iterator itt = *this; return (itt -= i); }
difference_type operator -(const iterator &i) const { return ii - i.ii; }
ITER operator *() const { return it + si1.index(ii); }
ITER operator [](int i) { return it + si1.index(ii+i); }
bool operator ==(const iterator &i) const { return (ii == i.ii); }
bool operator !=(const iterator &i) const { return !(i == *this); }
bool operator < (const iterator &i) const { return (ii < i.ii); }
gen_sub_row_matrix_iterator(void) {}
gen_sub_row_matrix_iterator(const
gen_sub_row_matrix_iterator<MPT, SUBI1, SUBI2> &itm)
: it(itm.it), si1(itm.si1), si2(itm.si2), ii(itm.ii) {}
gen_sub_row_matrix_iterator(const ITER &iter, const SUBI1 &s1,
const SUBI2 &s2, size_type i)
: it(iter), si1(s1), si2(s2), ii(i) { }
};
template <typename PT, typename SUBI1, typename SUBI2>
struct linalg_traits<gen_sub_row_matrix<PT, SUBI1, SUBI2> > {
typedef gen_sub_row_matrix<PT, SUBI1, SUBI2> this_type;
typedef typename std::iterator_traits<PT>::value_type M;
typedef typename which_reference<PT>::is_reference is_reference;
typedef abstract_matrix linalg_type;
typedef typename linalg_traits<M>::origin_type origin_type;
typedef typename select_ref<const origin_type *, origin_type *,
PT>::ref_type porigin_type;
typedef typename linalg_traits<M>::value_type value_type;
typedef typename select_ref<value_type,
typename linalg_traits<M>::reference, PT>::ref_type reference;
typedef abstract_null_type sub_col_type;
typedef abstract_null_type col_iterator;
typedef abstract_null_type const_sub_col_type;
typedef abstract_null_type const_col_iterator;
typedef typename sub_vector_type<const typename org_type<typename
linalg_traits<M>::const_sub_row_type>::t *, SUBI2>::vector_type
const_sub_row_type;
typedef typename select_ref<abstract_null_type,
typename sub_vector_type<typename org_type<typename linalg_traits<M>::sub_row_type>::t *,
SUBI2>::vector_type, PT>::ref_type sub_row_type;
typedef gen_sub_row_matrix_iterator<typename const_pointer<PT>::pointer,
SUBI1, SUBI2> const_row_iterator;
typedef typename select_ref<abstract_null_type,
gen_sub_row_matrix_iterator<PT, SUBI1, SUBI2>, PT>::ref_type
row_iterator;
typedef typename linalg_traits<const_sub_row_type>::storage_type
storage_type;
typedef row_major sub_orientation;
typedef linalg_true index_sorted;
static size_type nrows(const this_type &m) { return m.nrows(); }
static size_type ncols(const this_type &m) { return m.ncols(); }
static const_sub_row_type row(const const_row_iterator &it)
{ return const_sub_row_type(linalg_traits<M>::row(*it), it.si2); }
static sub_row_type row(const row_iterator &it)
{ return sub_row_type(linalg_traits<M>::row(*it), it.si2); }
static const_row_iterator row_begin(const this_type &m)
{ return const_row_iterator(m.begin_, m.si1, m.si2, 0); }
static row_iterator row_begin(this_type &m)
{ return row_iterator(m.begin_, m.si1, m.si2, 0); }
static const_row_iterator row_end(const this_type &m)
{ return const_row_iterator(m.begin_, m.si1, m.si2, m.nrows()); }
static row_iterator row_end(this_type &m)
{ return row_iterator(m.begin_, m.si1, m.si2, m.nrows()); }
static origin_type* origin(this_type &v) { return v.origin; }
static const origin_type* origin(const this_type &v) { return v.origin; }
static void do_clear(this_type &m) {
row_iterator it = mat_row_begin(m), ite = mat_row_end(m);
for (; it != ite; ++it) clear(row(it));
}
static value_type access(const const_row_iterator &itrow, size_type i)
{ return linalg_traits<M>::access(*itrow, itrow.si2.index(i)); }
static reference access(const row_iterator &itrow, size_type i)
{ return linalg_traits<M>::access(*itrow, itrow.si2.index(i)); }
};
template <typename PT, typename SUBI1, typename SUBI2>
std::ostream &operator <<(std::ostream &o,
const gen_sub_row_matrix<PT, SUBI1, SUBI2>& m)
{ gmm::write(o,m); return o; }
/* ********************************************************************* */
/* sub column matrices type */
/* ********************************************************************* */
template <typename PT, typename SUBI1, typename SUBI2>
struct gen_sub_col_matrix {
typedef gen_sub_col_matrix<PT, SUBI1, SUBI2> this_type;
typedef typename std::iterator_traits<PT>::value_type M;
typedef M * CPT;
typedef typename std::iterator_traits<PT>::reference ref_M;
typedef typename select_ref<typename linalg_traits<M>
::const_col_iterator, typename linalg_traits<M>::col_iterator,
PT>::ref_type iterator;
typedef typename linalg_traits<this_type>::reference reference;
typedef typename linalg_traits<this_type>::porigin_type porigin_type;
SUBI1 si1;
SUBI2 si2;
iterator begin_;
porigin_type origin;
reference operator()(size_type i, size_type j) const
{ return linalg_traits<M>::access(begin_ + si2.index(j), si1.index(i)); }
size_type nrows(void) const { return si1.size(); }
size_type ncols(void) const { return si2.size(); }
gen_sub_col_matrix(ref_M m, const SUBI1 &s1, const SUBI2 &s2)
: si1(s1), si2(s2), begin_(mat_col_begin(m)),
origin(linalg_origin(m)) {}
gen_sub_col_matrix() {}
gen_sub_col_matrix(const gen_sub_col_matrix<CPT, SUBI1, SUBI2> &cr) :
si1(cr.si1), si2(cr.si2), begin_(cr.begin_),origin(cr.origin) {}
};
template <typename PT, typename SUBI1, typename SUBI2>
struct gen_sub_col_matrix_iterator {
typedef gen_sub_col_matrix<PT, SUBI1, SUBI2> this_type;
typedef typename modifiable_pointer<PT>::pointer MPT;
typedef typename std::iterator_traits<PT>::value_type M;
typedef typename select_ref<typename linalg_traits<M>::const_col_iterator,
typename linalg_traits<M>::col_iterator,
PT>::ref_type ITER;
typedef ITER value_type;
typedef ITER *pointer;
typedef ITER &reference;
typedef ptrdiff_t difference_type;
typedef size_t size_type;
typedef std::random_access_iterator_tag iterator_category;
typedef gen_sub_col_matrix_iterator<PT, SUBI1, SUBI2> iterator;
ITER it;
SUBI1 si1;
SUBI2 si2;
size_type ii;
iterator operator ++(int) { iterator tmp = *this; ii++; return tmp; }
iterator operator --(int) { iterator tmp = *this; ii--; return tmp; }
iterator &operator ++() { ii++; return *this; }
iterator &operator --() { ii--; return *this; }
iterator &operator +=(difference_type i) { ii += i; return *this; }
iterator &operator -=(difference_type i) { ii -= i; return *this; }
iterator operator +(difference_type i) const
{ iterator itt = *this; return (itt += i); }
iterator operator -(difference_type i) const
{ iterator itt = *this; return (itt -= i); }
difference_type operator -(const iterator &i) const { return ii - i.ii; }
ITER operator *() const { return it + si2.index(ii); }
ITER operator [](int i) { return it + si2.index(ii+i); }
bool operator ==(const iterator &i) const { return (ii == i.ii); }
bool operator !=(const iterator &i) const { return !(i == *this); }
bool operator < (const iterator &i) const { return (ii < i.ii); }
gen_sub_col_matrix_iterator(void) {}
gen_sub_col_matrix_iterator(const
gen_sub_col_matrix_iterator<MPT, SUBI1, SUBI2> &itm)
: it(itm.it), si1(itm.si1), si2(itm.si2), ii(itm.ii) {}
gen_sub_col_matrix_iterator(const ITER &iter, const SUBI1 &s1,
const SUBI2 &s2, size_type i)
: it(iter), si1(s1), si2(s2), ii(i) { }
};
template <typename PT, typename SUBI1, typename SUBI2>
struct linalg_traits<gen_sub_col_matrix<PT, SUBI1, SUBI2> > {
typedef gen_sub_col_matrix<PT, SUBI1, SUBI2> this_type;
typedef typename std::iterator_traits<PT>::value_type M;
typedef typename linalg_traits<M>::origin_type origin_type;
typedef typename select_ref<const origin_type *, origin_type *,
PT>::ref_type porigin_type;
typedef typename which_reference<PT>::is_reference is_reference;
typedef abstract_matrix linalg_type;
typedef typename linalg_traits<M>::value_type value_type;
typedef typename select_ref<value_type,
typename linalg_traits<M>::reference, PT>::ref_type reference;
typedef abstract_null_type sub_row_type;
typedef abstract_null_type row_iterator;
typedef abstract_null_type const_sub_row_type;
typedef abstract_null_type const_row_iterator;
typedef typename sub_vector_type<const typename org_type<typename linalg_traits<M>::const_sub_col_type>::t *, SUBI1>::vector_type const_sub_col_type;
typedef typename select_ref<abstract_null_type, typename sub_vector_type<typename org_type<typename linalg_traits<M>::sub_col_type>::t *, SUBI1>::vector_type, PT>::ref_type sub_col_type;
typedef gen_sub_col_matrix_iterator<typename const_pointer<PT>::pointer,
SUBI1, SUBI2> const_col_iterator;
typedef typename select_ref<abstract_null_type,
gen_sub_col_matrix_iterator<PT, SUBI1, SUBI2>, PT>::ref_type
col_iterator;
typedef col_major sub_orientation;
typedef linalg_true index_sorted;
typedef typename linalg_traits<const_sub_col_type>::storage_type
storage_type;
static size_type nrows(const this_type &m) { return m.nrows(); }
static size_type ncols(const this_type &m) { return m.ncols(); }
static const_sub_col_type col(const const_col_iterator &it)
{ return const_sub_col_type(linalg_traits<M>::col(*it), it.si1); }
static sub_col_type col(const col_iterator &it)
{ return sub_col_type(linalg_traits<M>::col(*it), it.si1); }
static const_col_iterator col_begin(const this_type &m)
{ return const_col_iterator(m.begin_, m.si1, m.si2, 0); }
static col_iterator col_begin(this_type &m)
{ return col_iterator(m.begin_, m.si1, m.si2, 0); }
static const_col_iterator col_end(const this_type &m)
{ return const_col_iterator(m.begin_, m.si1, m.si2, m.ncols()); }
static col_iterator col_end(this_type &m)
{ return col_iterator(m.begin_, m.si1, m.si2, m.ncols()); }
static origin_type* origin(this_type &v) { return v.origin; }
static const origin_type* origin(const this_type &v) { return v.origin; }
static void do_clear(this_type &m) {
col_iterator it = mat_col_begin(m), ite = mat_col_end(m);
for (; it != ite; ++it) clear(col(it));
}
static value_type access(const const_col_iterator &itcol, size_type i)
{ return linalg_traits<M>::access(*itcol, itcol.si1.index(i)); }
static reference access(const col_iterator &itcol, size_type i)
{ return linalg_traits<M>::access(*itcol, itcol.si1.index(i)); }
};
template <typename PT, typename SUBI1, typename SUBI2> std::ostream &operator <<
(std::ostream &o, const gen_sub_col_matrix<PT, SUBI1, SUBI2>& m)
{ gmm::write(o,m); return o; }
/* ******************************************************************** */
/* sub matrices */
/* ******************************************************************** */
template <typename PT, typename SUBI1, typename SUBI2, typename ST>
struct sub_matrix_type_ {
typedef abstract_null_type return_type;
};
template <typename PT, typename SUBI1, typename SUBI2>
struct sub_matrix_type_<PT, SUBI1, SUBI2, col_major>
{ typedef gen_sub_col_matrix<PT, SUBI1, SUBI2> matrix_type; };
template <typename PT, typename SUBI1, typename SUBI2>
struct sub_matrix_type_<PT, SUBI1, SUBI2, row_major>
{ typedef gen_sub_row_matrix<PT, SUBI1, SUBI2> matrix_type; };
template <typename PT, typename SUBI1, typename SUBI2>
struct sub_matrix_type {
typedef typename std::iterator_traits<PT>::value_type M;
typedef typename sub_matrix_type_<PT, SUBI1, SUBI2,
typename principal_orientation_type<typename
linalg_traits<M>::sub_orientation>::potype>::matrix_type matrix_type;
};
template <typename M, typename SUBI1, typename SUBI2> inline
typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI2>
::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI2>::matrix_type,
M *>::return_type
sub_matrix(M &m, const SUBI1 &si1, const SUBI2 &si2) {
GMM_ASSERT2(si1.last() <= mat_nrows(m) && si2.last() <= mat_ncols(m),
"sub matrix too large");
return typename select_return<typename sub_matrix_type<const M *, SUBI1,
SUBI2>::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI2>
::matrix_type, M *>::return_type(linalg_cast(m), si1, si2);
}
template <typename M, typename SUBI1, typename SUBI2> inline
typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI2>
::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI2>::matrix_type,
const M *>::return_type
sub_matrix(const M &m, const SUBI1 &si1, const SUBI2 &si2) {
GMM_ASSERT2(si1.last() <= mat_nrows(m) && si2.last() <= mat_ncols(m),
"sub matrix too large");
return typename select_return<typename sub_matrix_type<const M *, SUBI1,
SUBI2>::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI2>
::matrix_type, const M *>::return_type(linalg_cast(m), si1, si2);
}
template <typename M, typename SUBI1> inline
typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI1>
::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI1>::matrix_type,
M *>::return_type
sub_matrix(M &m, const SUBI1 &si1) {
GMM_ASSERT2(si1.last() <= mat_nrows(m) && si1.last() <= mat_ncols(m),
"sub matrix too large");
return typename select_return<typename sub_matrix_type<const M *, SUBI1,
SUBI1>::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI1>
::matrix_type, M *>::return_type(linalg_cast(m), si1, si1);
}
template <typename M, typename SUBI1> inline
typename select_return<typename sub_matrix_type<const M *, SUBI1, SUBI1>
::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI1>::matrix_type,
const M *>::return_type
sub_matrix(const M &m, const SUBI1 &si1) {
GMM_ASSERT2(si1.last() <= mat_nrows(m) && si1.last() <= mat_ncols(m),
"sub matrix too large");
return typename select_return<typename sub_matrix_type<const M *, SUBI1,
SUBI1>::matrix_type, typename sub_matrix_type<M *, SUBI1, SUBI1>
::matrix_type, const M *>::return_type(linalg_cast(m), si1, si1);
}
}
#endif // GMM_SUB_MATRIX_H__

560
gmm/gmm_sub_vector.h Normal file
View File

@ -0,0 +1,560 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_sub_vector.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date October 13, 2002.
@brief Generic sub-vectors.
*/
#ifndef GMM_SUB_VECTOR_H__
#define GMM_SUB_VECTOR_H__
#include "gmm_interface.h"
#include "gmm_sub_index.h"
namespace gmm {
/* ********************************************************************* */
/* sparse sub-vectors */
/* ********************************************************************* */
template <typename IT, typename MIT, typename SUBI>
struct sparse_sub_vector_iterator {
IT itb, itbe;
SUBI si;
typedef std::iterator_traits<IT> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::pointer pointer;
typedef typename traits_type::reference reference;
typedef typename traits_type::difference_type difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
typedef size_t size_type;
typedef sparse_sub_vector_iterator<IT, MIT, SUBI> iterator;
size_type index(void) const { return si.rindex(itb.index()); }
void forward(void);
void backward(void);
iterator &operator ++()
{ ++itb; forward(); return *this; }
iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
iterator &operator --()
{ --itb; backward(); return *this; }
iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
reference operator *() const { return *itb; }
bool operator ==(const iterator &i) const { return itb == i.itb; }
bool operator !=(const iterator &i) const { return !(i == *this); }
sparse_sub_vector_iterator(void) {}
sparse_sub_vector_iterator(const IT &it, const IT &ite, const SUBI &s)
: itb(it), itbe(ite), si(s) { forward(); }
sparse_sub_vector_iterator(const sparse_sub_vector_iterator<MIT, MIT,
SUBI> &it) : itb(it.itb), itbe(it.itbe), si(it.si) {}
};
template <typename IT, typename MIT, typename SUBI>
void sparse_sub_vector_iterator<IT, MIT, SUBI>::forward(void)
{ while(itb!=itbe && index()==size_type(-1)) { ++itb; } }
template <typename IT, typename MIT, typename SUBI>
void sparse_sub_vector_iterator<IT, MIT, SUBI>::backward(void)
{ while(itb!=itbe && index()==size_type(-1)) --itb; }
template <typename PT, typename SUBI> struct sparse_sub_vector {
typedef sparse_sub_vector<PT, SUBI> this_type;
typedef typename std::iterator_traits<PT>::value_type V;
typedef V * CPT;
typedef typename select_ref<typename linalg_traits<V>::const_iterator,
typename linalg_traits<V>::iterator, PT>::ref_type iterator;
typedef typename linalg_traits<this_type>::reference reference;
typedef typename linalg_traits<this_type>::porigin_type porigin_type;
iterator begin_, end_;
porigin_type origin;
SUBI si;
size_type size(void) const { return si.size(); }
reference operator[](size_type i) const
{ return linalg_traits<V>::access(origin, begin_, end_, si.index(i)); }
sparse_sub_vector(V &v, const SUBI &s) : begin_(vect_begin(v)),
end_(vect_end(v)), origin(linalg_origin(v)), si(s) {}
sparse_sub_vector(const V &v, const SUBI &s)
: begin_(vect_begin(const_cast<V &>(v))),
end_(vect_end(const_cast<V &>(v))),
origin(linalg_origin(const_cast<V &>(v))), si(s) {}
sparse_sub_vector() {}
sparse_sub_vector(const sparse_sub_vector<CPT, SUBI> &cr)
: begin_(cr.begin_),end_(cr.end_),origin(cr.origin), si(cr.si) {}
};
template <typename IT, typename MIT, typename SUBI, typename ORG,
typename PT> inline
void set_to_begin(sparse_sub_vector_iterator<IT, MIT, SUBI> &it,
ORG o, sparse_sub_vector<PT, SUBI> *,
linalg_modifiable) {
typedef sparse_sub_vector<PT, SUBI> VECT;
typedef typename linalg_traits<VECT>::V_reference ref_t;
set_to_begin(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
set_to_end(it.itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
it.forward();
}
template <typename IT, typename MIT, typename SUBI, typename ORG,
typename PT> inline
void set_to_begin(sparse_sub_vector_iterator<IT, MIT, SUBI> &it,
ORG o, const sparse_sub_vector<PT, SUBI> *,
linalg_modifiable) {
typedef sparse_sub_vector<PT, SUBI> VECT;
typedef typename linalg_traits<VECT>::V_reference ref_t;
set_to_begin(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
set_to_end(it.itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
it.forward();
}
template <typename IT, typename MIT, typename SUBI, typename ORG,
typename PT> inline
void set_to_end(sparse_sub_vector_iterator<IT, MIT, SUBI> &it,
ORG o, sparse_sub_vector<PT, SUBI> *, linalg_modifiable) {
typedef sparse_sub_vector<PT, SUBI> VECT;
typedef typename linalg_traits<VECT>::V_reference ref_t;
set_to_end(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
set_to_end(it.itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
it.forward();
}
template <typename IT, typename MIT, typename SUBI, typename ORG,
typename PT> inline
void set_to_end(sparse_sub_vector_iterator<IT, MIT, SUBI> &it,
ORG o, const sparse_sub_vector<PT, SUBI> *,
linalg_modifiable) {
typedef sparse_sub_vector<PT, SUBI> VECT;
typedef typename linalg_traits<VECT>::V_reference ref_t;
set_to_end(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
set_to_end(it.itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
it.forward();
}
template <typename PT, typename SUBI>
struct linalg_traits<sparse_sub_vector<PT, SUBI> > {
typedef sparse_sub_vector<PT, SUBI> this_type;
typedef this_type * pthis_type;
typedef PT pV;
typedef typename std::iterator_traits<PT>::value_type V;
typedef typename linalg_and<typename index_is_sorted<SUBI>::bool_type,
typename linalg_traits<V>::index_sorted>::bool_type index_sorted;
typedef typename linalg_traits<V>::is_reference V_reference;
typedef typename linalg_traits<V>::origin_type origin_type;
typedef typename select_ref<const origin_type *, origin_type *,
PT>::ref_type porigin_type;
typedef typename which_reference<PT>::is_reference is_reference;
typedef abstract_vector linalg_type;
typedef typename linalg_traits<V>::value_type value_type;
typedef typename select_ref<value_type, typename
linalg_traits<V>::reference, PT>::ref_type reference;
typedef typename select_ref<typename linalg_traits<V>::const_iterator,
typename linalg_traits<V>::iterator, PT>::ref_type pre_iterator;
typedef typename select_ref<abstract_null_type,
sparse_sub_vector_iterator<pre_iterator, pre_iterator, SUBI>,
PT>::ref_type iterator;
typedef sparse_sub_vector_iterator<typename linalg_traits<V>
::const_iterator, pre_iterator, SUBI> const_iterator;
typedef abstract_sparse storage_type;
static size_type size(const this_type &v) { return v.size(); }
static iterator begin(this_type &v) {
iterator it;
it.itb = v.begin_; it.itbe = v.end_; it.si = v.si;
if (!is_const_reference(is_reference()))
set_to_begin(it, v.origin, pthis_type(), is_reference());
else it.forward();
return it;
}
static const_iterator begin(const this_type &v) {
const_iterator it; it.itb = v.begin_; it.itbe = v.end_; it.si = v.si;
if (!is_const_reference(is_reference()))
{ set_to_begin(it, v.origin, pthis_type(), is_reference()); }
else it.forward();
return it;
}
static iterator end(this_type &v) {
iterator it;
it.itb = v.end_; it.itbe = v.end_; it.si = v.si;
if (!is_const_reference(is_reference()))
set_to_end(it, v.origin, pthis_type(), is_reference());
else it.forward();
return it;
}
static const_iterator end(const this_type &v) {
const_iterator it; it.itb = v.end_; it.itbe = v.end_; it.si = v.si;
if (!is_const_reference(is_reference()))
set_to_end(it, v.origin, pthis_type(), is_reference());
else it.forward();
return it;
}
static origin_type* origin(this_type &v) { return v.origin; }
static const origin_type* origin(const this_type &v) { return v.origin; }
static void clear(origin_type* o, const iterator &begin_,
const iterator &end_) {
std::deque<size_type> ind;
iterator it = begin_;
for (; it != end_; ++it) ind.push_front(it.index());
for (; !(ind.empty()); ind.pop_back())
access(o, begin_, end_, ind.back()) = value_type(0);
}
static void do_clear(this_type &v) { clear(v.origin, begin(v), end(v)); }
static value_type access(const origin_type *o, const const_iterator &it,
const const_iterator &ite, size_type i)
{ return linalg_traits<V>::access(o, it.itb, ite.itb, it.si.index(i)); }
static reference access(origin_type *o, const iterator &it,
const iterator &ite, size_type i)
{ return linalg_traits<V>::access(o, it.itb, ite.itb, it.si.index(i)); }
};
template <typename PT, typename SUBI> std::ostream &operator <<
(std::ostream &o, const sparse_sub_vector<PT, SUBI>& m)
{ gmm::write(o,m); return o; }
/* ********************************************************************* */
/* skyline sub-vectors */
/* ********************************************************************* */
template <typename IT, typename MIT, typename SUBI>
struct skyline_sub_vector_iterator {
IT itb;
SUBI si;
typedef std::iterator_traits<IT> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::pointer pointer;
typedef typename traits_type::reference reference;
typedef typename traits_type::difference_type difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
typedef size_t size_type;
typedef skyline_sub_vector_iterator<IT, MIT, SUBI> iterator;
size_type index(void) const
{ return (itb.index() - si.min + si.step() - 1) / si.step(); }
void backward(void);
iterator &operator ++()
{ itb += si.step(); return *this; }
iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
iterator &operator --()
{ itb -= si.step(); return *this; }
iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
iterator &operator +=(difference_type i)
{ itb += si.step() * i; return *this; }
iterator &operator -=(difference_type i)
{ itb -= si.step() * i; return *this; }
iterator operator +(difference_type i) const
{ iterator ii = *this; return (ii += i); }
iterator operator -(difference_type i) const
{ iterator ii = *this; return (ii -= i); }
difference_type operator -(const iterator &i) const
{ return (itb - i.itb) / si.step(); }
reference operator *() const { return *itb; }
reference operator [](int ii) { return *(itb + ii * si.step()); }
bool operator ==(const iterator &i) const { return index() == i.index();}
bool operator !=(const iterator &i) const { return !(i == *this); }
bool operator < (const iterator &i) const { return index() < i.index();}
skyline_sub_vector_iterator(void) {}
skyline_sub_vector_iterator(const IT &it, const SUBI &s)
: itb(it), si(s) {}
skyline_sub_vector_iterator(const skyline_sub_vector_iterator<MIT, MIT,
SUBI> &it) : itb(it.itb), si(it.si) {}
};
template <typename IT, typename SUBI>
void update_for_sub_skyline(IT &it, IT &ite, const SUBI &si) {
if (it.index() >= si.max || ite.index() <= si.min) { it = ite; return; }
ptrdiff_t dec1 = si.min - it.index(), dec2 = ite.index() - si.max;
it += (dec1 < 0) ? ((si.step()-((-dec1) % si.step())) % si.step()) : dec1;
ite -= (dec2 < 0) ? -((-dec2) % si.step()) : dec2;
}
template <typename PT, typename SUBI> struct skyline_sub_vector {
typedef skyline_sub_vector<PT, SUBI> this_type;
typedef typename std::iterator_traits<PT>::value_type V;
typedef V * pV;
typedef typename select_ref<typename linalg_traits<V>::const_iterator,
typename linalg_traits<V>::iterator, PT>::ref_type iterator;
typedef typename linalg_traits<this_type>::reference reference;
typedef typename linalg_traits<this_type>::porigin_type porigin_type;
iterator begin_, end_;
porigin_type origin;
SUBI si;
size_type size(void) const { return si.size(); }
reference operator[](size_type i) const
{ return linalg_traits<V>::access(origin, begin_, end_, si.index(i)); }
skyline_sub_vector(V &v, const SUBI &s) : begin_(vect_begin(v)),
end_(vect_end(v)), origin(linalg_origin(v)), si(s) {
update_for_sub_skyline(begin_, end_, si);
}
skyline_sub_vector(const V &v, const SUBI &s)
: begin_(vect_begin(const_cast<V &>(v))),
end_(vect_end(const_cast<V &>(v))),
origin(linalg_origin(const_cast<V &>(v))), si(s) {
update_for_sub_skyline(begin_, end_, si);
}
skyline_sub_vector() {}
skyline_sub_vector(const skyline_sub_vector<pV, SUBI> &cr)
: begin_(cr.begin_),end_(cr.end_),origin(cr.origin), si(cr.si) {}
};
template <typename IT, typename MIT, typename SUBI, typename ORG,
typename PT> inline
void set_to_begin(skyline_sub_vector_iterator<IT, MIT, SUBI> &it,
ORG o, skyline_sub_vector<PT, SUBI> *,
linalg_modifiable) {
typedef skyline_sub_vector<PT, SUBI> VECT;
typedef typename linalg_traits<VECT>::V_reference ref_t;
IT itbe = it.itb;
set_to_begin(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
set_to_end(itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
update_for_sub_skyline(it.itb, itbe, it.si);
}
template <typename IT, typename MIT, typename SUBI, typename ORG,
typename PT> inline
void set_to_begin(skyline_sub_vector_iterator<IT, MIT, SUBI> &it,
ORG o, const skyline_sub_vector<PT, SUBI> *,
linalg_modifiable) {
typedef skyline_sub_vector<PT, SUBI> VECT;
typedef typename linalg_traits<VECT>::V_reference ref_t;
IT itbe = it.itb;
set_to_begin(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
set_to_end(itbe, o, typename linalg_traits<VECT>::pV(), ref_t());
update_for_sub_skyline(it.itb, itbe, it.si);
}
template <typename IT, typename MIT, typename SUBI, typename ORG,
typename PT> inline
void set_to_end(skyline_sub_vector_iterator<IT, MIT, SUBI> &it,
ORG o, skyline_sub_vector<PT, SUBI> *,
linalg_modifiable) {
typedef skyline_sub_vector<PT, SUBI> VECT;
typedef typename linalg_traits<VECT>::V_reference ref_t;
IT itb = it.itb;
set_to_begin(itb, o, typename linalg_traits<VECT>::pV(), ref_t());
set_to_end(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
update_for_sub_skyline(itb, it.itb, it.si);
}
template <typename IT, typename MIT, typename SUBI, typename ORG,
typename PT> inline
void set_to_end(skyline_sub_vector_iterator<IT, MIT, SUBI> &it,
ORG o, const skyline_sub_vector<PT, SUBI> *,
linalg_modifiable) {
typedef skyline_sub_vector<PT, SUBI> VECT;
typedef typename linalg_traits<VECT>::V_reference ref_t;
IT itb = it.itb;
set_to_begin(itb, o, typename linalg_traits<VECT>::pV(), ref_t());
set_to_end(it.itb, o, typename linalg_traits<VECT>::pV(), ref_t());
update_for_sub_skyline(itb, it.itb, it.si);
}
template <typename PT, typename SUBI>
struct linalg_traits<skyline_sub_vector<PT, SUBI> > {
typedef skyline_sub_vector<PT, SUBI> this_type;
typedef this_type *pthis_type;
typedef typename std::iterator_traits<PT>::value_type V;
typedef typename linalg_traits<V>::is_reference V_reference;
typedef typename linalg_traits<V>::origin_type origin_type;
typedef typename select_ref<const origin_type *, origin_type *,
PT>::ref_type porigin_type;
typedef V * pV;
typedef typename which_reference<PT>::is_reference is_reference;
typedef abstract_vector linalg_type;
typedef typename linalg_traits<V>::value_type value_type;
typedef typename select_ref<value_type, typename
linalg_traits<V>::reference, PT>::ref_type reference;
typedef typename linalg_traits<V>::const_iterator const_V_iterator;
typedef typename linalg_traits<V>::iterator V_iterator;
typedef typename select_ref<const_V_iterator, V_iterator,
PT>::ref_type pre_iterator;
typedef typename select_ref<abstract_null_type,
skyline_sub_vector_iterator<pre_iterator, pre_iterator, SUBI>,
PT>::ref_type iterator;
typedef skyline_sub_vector_iterator<const_V_iterator, pre_iterator, SUBI>
const_iterator;
typedef abstract_skyline storage_type;
typedef linalg_true index_sorted;
static size_type size(const this_type &v) { return v.size(); }
static iterator begin(this_type &v) {
iterator it;
it.itb = v.begin_; it.si = v.si;
if (!is_const_reference(is_reference()))
set_to_begin(it, v.origin, pthis_type(), is_reference());
return it;
}
static const_iterator begin(const this_type &v) {
const_iterator it; it.itb = v.begin_; it.si = v.si;
if (!is_const_reference(is_reference()))
{ set_to_begin(it, v.origin, pthis_type(), is_reference()); }
return it;
}
static iterator end(this_type &v) {
iterator it;
it.itb = v.end_; it.si = v.si;
if (!is_const_reference(is_reference()))
set_to_end(it, v.origin, pthis_type(), is_reference());
return it;
}
static const_iterator end(const this_type &v) {
const_iterator it; it.itb = v.end_; it.si = v.si;
if (!is_const_reference(is_reference()))
set_to_end(it, v.origin, pthis_type(), is_reference());
return it;
}
static origin_type* origin(this_type &v) { return v.origin; }
static const origin_type* origin(const this_type &v) { return v.origin; }
static void clear(origin_type*, const iterator &it, const iterator &ite)
{ std::fill(it, ite, value_type(0)); }
static void do_clear(this_type &v) { clear(v.origin, begin(v), end(v)); }
static value_type access(const origin_type *o, const const_iterator &it,
const const_iterator &ite, size_type i)
{ return linalg_traits<V>::access(o, it.itb, ite.itb, it.si.index(i)); }
static reference access(origin_type *o, const iterator &it,
const iterator &ite, size_type i)
{ return linalg_traits<V>::access(o, it.itb, ite.itb, it.si.index(i)); }
};
template <typename PT, typename SUBI> std::ostream &operator <<
(std::ostream &o, const skyline_sub_vector<PT, SUBI>& m)
{ gmm::write(o,m); return o; }
/* ******************************************************************** */
/* sub vector. */
/* ******************************************************************** */
/* sub_vector_type<PT, SUBI>::vector_type is the sub vector type */
/* returned by sub_vector(v, sub_index) */
/************************************************************************/
template <typename PT, typename SUBI, typename st_type> struct svrt_ir {
typedef abstract_null_type vector_type;
};
template <typename PT>
struct svrt_ir<PT, sub_index, abstract_dense> {
typedef typename std::iterator_traits<PT>::value_type V;
typedef typename vect_ref_type<PT, V>::iterator iterator;
typedef tab_ref_index_ref_with_origin<iterator,
sub_index::const_iterator, V> vector_type;
};
template <typename PT>
struct svrt_ir<PT, unsorted_sub_index, abstract_dense> {
typedef typename std::iterator_traits<PT>::value_type V;
typedef typename vect_ref_type<PT, V>::iterator iterator;
typedef tab_ref_index_ref_with_origin<iterator,
unsorted_sub_index::const_iterator, V> vector_type;
};
template <typename PT>
struct svrt_ir<PT, sub_interval, abstract_dense> {
typedef typename std::iterator_traits<PT>::value_type V;
typedef typename vect_ref_type<PT, V>::iterator iterator;
typedef tab_ref_with_origin<iterator, V> vector_type;
};
template <typename PT>
struct svrt_ir<PT, sub_slice, abstract_dense> {
typedef typename std::iterator_traits<PT>::value_type V;
typedef typename vect_ref_type<PT, V>::iterator iterator;
typedef tab_ref_reg_spaced_with_origin<iterator, V> vector_type;
};
template <typename PT, typename SUBI>
struct svrt_ir<PT, SUBI, abstract_skyline> {
typedef skyline_sub_vector<PT, SUBI> vector_type;
};
template <typename PT>
struct svrt_ir<PT, sub_index, abstract_skyline> {
typedef sparse_sub_vector<PT, sub_index> vector_type;
};
template <typename PT>
struct svrt_ir<PT, unsorted_sub_index, abstract_skyline> {
typedef sparse_sub_vector<PT, unsorted_sub_index> vector_type;
};
template <typename PT, typename SUBI>
struct svrt_ir<PT, SUBI, abstract_sparse> {
typedef sparse_sub_vector<PT, SUBI> vector_type;
};
template <typename PT, typename SUBI>
struct sub_vector_type {
typedef typename std::iterator_traits<PT>::value_type V;
typedef typename svrt_ir<PT, SUBI,
typename linalg_traits<V>::storage_type>::vector_type vector_type;
};
template <typename V, typename SUBI>
typename select_return<
typename sub_vector_type<const V *, SUBI>::vector_type,
typename sub_vector_type<V *, SUBI>::vector_type, const V *>::return_type
sub_vector(const V &v, const SUBI &si) {
GMM_ASSERT2(si.last() <= vect_size(v),
"sub vector too large, " << si.last() << " > " << vect_size(v));
return typename select_return<
typename sub_vector_type<const V *, SUBI>::vector_type,
typename sub_vector_type<V *, SUBI>::vector_type, const V *>::return_type
(linalg_cast(v), si);
}
template <typename V, typename SUBI>
typename select_return<
typename sub_vector_type<const V *, SUBI>::vector_type,
typename sub_vector_type<V *, SUBI>::vector_type, V *>::return_type
sub_vector(V &v, const SUBI &si) {
GMM_ASSERT2(si.last() <= vect_size(v),
"sub vector too large, " << si.last() << " > " << vect_size(v));
return typename select_return<
typename sub_vector_type<const V *, SUBI>::vector_type,
typename sub_vector_type<V *, SUBI>::vector_type, V *>::return_type
(linalg_cast(v), si);
}
}
#endif // GMM_SUB_VECTOR_H__

410
gmm/gmm_superlu_interface.h Normal file
View File

@ -0,0 +1,410 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2003-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_superlu_interface.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date October 17, 2003.
@brief Interface with SuperLU (LU direct solver for sparse matrices).
*/
#if defined(GMM_USES_SUPERLU) && !defined(GETFEM_VERSION)
#ifndef GMM_SUPERLU_INTERFACE_H
#define GMM_SUPERLU_INTERFACE_H
#include "gmm_kernel.h"
typedef int int_t;
/* because SRC/util.h defines TRUE and FALSE ... */
#ifdef TRUE
# undef TRUE
#endif
#ifdef FALSE
# undef FALSE
#endif
#include "superlu/slu_Cnames.h"
#include "superlu/supermatrix.h"
#include "superlu/slu_util.h"
namespace SuperLU_S {
#include "superlu/slu_sdefs.h"
}
namespace SuperLU_D {
#include "superlu/slu_ddefs.h"
}
namespace SuperLU_C {
#include "superlu/slu_cdefs.h"
}
namespace SuperLU_Z {
#include "superlu/slu_zdefs.h"
}
namespace gmm {
/* interface for Create_CompCol_Matrix */
inline void Create_CompCol_Matrix(SuperMatrix *A, int m, int n, int nnz,
float *a, int *ir, int *jc) {
SuperLU_S::sCreate_CompCol_Matrix(A, m, n, nnz, a, ir, jc,
SLU_NC, SLU_S, SLU_GE);
}
inline void Create_CompCol_Matrix(SuperMatrix *A, int m, int n, int nnz,
double *a, int *ir, int *jc) {
SuperLU_D::dCreate_CompCol_Matrix(A, m, n, nnz, a, ir, jc,
SLU_NC, SLU_D, SLU_GE);
}
inline void Create_CompCol_Matrix(SuperMatrix *A, int m, int n, int nnz,
std::complex<float> *a, int *ir, int *jc) {
SuperLU_C::cCreate_CompCol_Matrix(A, m, n, nnz, (SuperLU_C::complex *)(a),
ir, jc, SLU_NC, SLU_C, SLU_GE);
}
inline void Create_CompCol_Matrix(SuperMatrix *A, int m, int n, int nnz,
std::complex<double> *a, int *ir, int *jc) {
SuperLU_Z::zCreate_CompCol_Matrix(A, m, n, nnz,
(SuperLU_Z::doublecomplex *)(a), ir, jc,
SLU_NC, SLU_Z, SLU_GE);
}
/* interface for Create_Dense_Matrix */
inline void Create_Dense_Matrix(SuperMatrix *A, int m, int n, float *a, int k)
{ SuperLU_S::sCreate_Dense_Matrix(A, m, n, a, k, SLU_DN, SLU_S, SLU_GE); }
inline void Create_Dense_Matrix(SuperMatrix *A, int m, int n, double *a, int k)
{ SuperLU_D::dCreate_Dense_Matrix(A, m, n, a, k, SLU_DN, SLU_D, SLU_GE); }
inline void Create_Dense_Matrix(SuperMatrix *A, int m, int n,
std::complex<float> *a, int k) {
SuperLU_C::cCreate_Dense_Matrix(A, m, n, (SuperLU_C::complex *)(a),
k, SLU_DN, SLU_C, SLU_GE);
}
inline void Create_Dense_Matrix(SuperMatrix *A, int m, int n,
std::complex<double> *a, int k) {
SuperLU_Z::zCreate_Dense_Matrix(A, m, n, (SuperLU_Z::doublecomplex *)(a),
k, SLU_DN, SLU_Z, SLU_GE);
}
/* interface for gssv */
#define DECL_GSSV(NAMESPACE,FNAME,FLOATTYPE,KEYTYPE) \
inline void SuperLU_gssv(superlu_options_t *options, SuperMatrix *A, int *p, \
int *q, SuperMatrix *L, SuperMatrix *U, SuperMatrix *B, \
SuperLUStat_t *stats, int *info, KEYTYPE) { \
NAMESPACE::FNAME(options, A, p, q, L, U, B, stats, info); \
}
DECL_GSSV(SuperLU_S,sgssv,float,float)
DECL_GSSV(SuperLU_C,cgssv,float,std::complex<float>)
DECL_GSSV(SuperLU_D,dgssv,double,double)
DECL_GSSV(SuperLU_Z,zgssv,double,std::complex<double>)
/* interface for gssvx */
#define DECL_GSSVX(NAMESPACE,FNAME,FLOATTYPE,KEYTYPE) \
inline float SuperLU_gssvx(superlu_options_t *options, SuperMatrix *A, \
int *perm_c, int *perm_r, int *etree, char *equed, \
FLOATTYPE *R, FLOATTYPE *C, SuperMatrix *L, \
SuperMatrix *U, void *work, int lwork, \
SuperMatrix *B, SuperMatrix *X, \
FLOATTYPE *recip_pivot_growth, \
FLOATTYPE *rcond, FLOATTYPE *ferr, FLOATTYPE *berr, \
SuperLUStat_t *stats, int *info, KEYTYPE) { \
NAMESPACE::mem_usage_t mem_usage; \
NAMESPACE::FNAME(options, A, perm_c, perm_r, etree, equed, R, C, L, \
U, work, lwork, B, X, recip_pivot_growth, rcond, \
ferr, berr, &mem_usage, stats, info); \
return mem_usage.for_lu; /* bytes used by the factor storage */ \
}
DECL_GSSVX(SuperLU_S,sgssvx,float,float)
DECL_GSSVX(SuperLU_C,cgssvx,float,std::complex<float>)
DECL_GSSVX(SuperLU_D,dgssvx,double,double)
DECL_GSSVX(SuperLU_Z,zgssvx,double,std::complex<double>)
/* ********************************************************************* */
/* SuperLU solve interface */
/* ********************************************************************* */
template <typename MAT, typename VECTX, typename VECTB>
int SuperLU_solve(const MAT &A, const VECTX &X_, const VECTB &B,
double& rcond_, int permc_spec = 3) {
VECTX &X = const_cast<VECTX &>(X_);
/*
* Get column permutation vector perm_c[], according to permc_spec:
* permc_spec = 0: use the natural ordering
* permc_spec = 1: use minimum degree ordering on structure of A'*A
* permc_spec = 2: use minimum degree ordering on structure of A'+A
* permc_spec = 3: use approximate minimum degree column ordering
*/
typedef typename linalg_traits<MAT>::value_type T;
typedef typename number_traits<T>::magnitude_type R;
int m = mat_nrows(A), n = mat_ncols(A), nrhs = 1, info = 0;
csc_matrix<T> csc_A(m, n); gmm::copy(A, csc_A);
std::vector<T> rhs(m), sol(m);
gmm::copy(B, rhs);
int nz = nnz(csc_A);
if ((2 * nz / n) >= m)
GMM_WARNING2("CAUTION : it seems that SuperLU has a problem"
" for nearly dense sparse matrices");
superlu_options_t options;
set_default_options(&options);
options.ColPerm = NATURAL;
options.PrintStat = NO;
options.ConditionNumber = YES;
switch (permc_spec) {
case 1 : options.ColPerm = MMD_ATA; break;
case 2 : options.ColPerm = MMD_AT_PLUS_A; break;
case 3 : options.ColPerm = COLAMD; break;
}
SuperLUStat_t stat;
StatInit(&stat);
SuperMatrix SA, SL, SU, SB, SX; // SuperLU format.
Create_CompCol_Matrix(&SA, m, n, nz, (double *)(&(csc_A.pr[0])),
(int *)(&(csc_A.ir[0])), (int *)(&(csc_A.jc[0])));
Create_Dense_Matrix(&SB, m, nrhs, &rhs[0], m);
Create_Dense_Matrix(&SX, m, nrhs, &sol[0], m);
memset(&SL,0,sizeof SL);
memset(&SU,0,sizeof SU);
std::vector<int> etree(n);
char equed[] = "B";
std::vector<R> Rscale(m),Cscale(n); // row scale factors
std::vector<R> ferr(nrhs), berr(nrhs);
R recip_pivot_gross, rcond;
std::vector<int> perm_r(m), perm_c(n);
SuperLU_gssvx(&options, &SA, &perm_c[0], &perm_r[0],
&etree[0] /* output */, equed /* output */,
&Rscale[0] /* row scale factors (output) */,
&Cscale[0] /* col scale factors (output) */,
&SL /* fact L (output)*/, &SU /* fact U (output)*/,
NULL /* work */,
0 /* lwork: superlu auto allocates (input) */,
&SB /* rhs */, &SX /* solution */,
&recip_pivot_gross /* reciprocal pivot growth */
/* factor max_j( norm(A_j)/norm(U_j) ). */,
&rcond /*estimate of the reciprocal condition */
/* number of the matrix A after equilibration */,
&ferr[0] /* estimated forward error */,
&berr[0] /* relative backward error */,
&stat, &info, T());
rcond_ = rcond;
Destroy_SuperMatrix_Store(&SB);
Destroy_SuperMatrix_Store(&SX);
Destroy_SuperMatrix_Store(&SA);
Destroy_SuperNode_Matrix(&SL);
Destroy_CompCol_Matrix(&SU);
StatFree(&stat);
GMM_ASSERT1(info >= 0, "SuperLU solve failed: info =" << info);
if (info > 0) GMM_WARNING1("SuperLU solve failed: info =" << info);
gmm::copy(sol, X);
return info;
}
template <class T> class SuperLU_factor {
typedef typename number_traits<T>::magnitude_type R;
csc_matrix<T> csc_A;
mutable SuperMatrix SA, SL, SB, SU, SX;
mutable SuperLUStat_t stat;
mutable superlu_options_t options;
float memory_used;
mutable std::vector<int> etree, perm_r, perm_c;
mutable std::vector<R> Rscale, Cscale;
mutable std::vector<R> ferr, berr;
mutable std::vector<T> rhs;
mutable std::vector<T> sol;
mutable bool is_init;
mutable char equed;
public :
enum { LU_NOTRANSP, LU_TRANSP, LU_CONJUGATED };
void free_supermatrix(void);
template <class MAT> void build_with(const MAT &A, int permc_spec = 3);
template <typename VECTX, typename VECTB>
/* transp = LU_NOTRANSP -> solves Ax = B
transp = LU_TRANSP -> solves A'x = B
transp = LU_CONJUGATED -> solves conj(A)X = B */
void solve(const VECTX &X_, const VECTB &B, int transp=LU_NOTRANSP) const;
SuperLU_factor(void) { is_init = false; }
SuperLU_factor(const SuperLU_factor& other) {
GMM_ASSERT2(!(other.is_init),
"copy of initialized SuperLU_factor is forbidden");
is_init = false;
}
SuperLU_factor& operator=(const SuperLU_factor& other) {
GMM_ASSERT2(!(other.is_init) && !is_init,
"assignment of initialized SuperLU_factor is forbidden");
return *this;
}
~SuperLU_factor() { free_supermatrix(); }
float memsize() { return memory_used; }
};
template <class T> void SuperLU_factor<T>::free_supermatrix(void) {
if (is_init) {
if (SB.Store) Destroy_SuperMatrix_Store(&SB);
if (SX.Store) Destroy_SuperMatrix_Store(&SX);
if (SA.Store) Destroy_SuperMatrix_Store(&SA);
if (SL.Store) Destroy_SuperNode_Matrix(&SL);
if (SU.Store) Destroy_CompCol_Matrix(&SU);
}
}
template <class T> template <class MAT>
void SuperLU_factor<T>::build_with(const MAT &A, int permc_spec) {
/*
* Get column permutation vector perm_c[], according to permc_spec:
* permc_spec = 0: use the natural ordering
* permc_spec = 1: use minimum degree ordering on structure of A'*A
* permc_spec = 2: use minimum degree ordering on structure of A'+A
* permc_spec = 3: use approximate minimum degree column ordering
*/
free_supermatrix();
int n = mat_nrows(A), m = mat_ncols(A), info = 0;
csc_A.init_with(A);
rhs.resize(m); sol.resize(m);
gmm::clear(rhs);
int nz = nnz(csc_A);
set_default_options(&options);
options.ColPerm = NATURAL;
options.PrintStat = NO;
options.ConditionNumber = NO;
switch (permc_spec) {
case 1 : options.ColPerm = MMD_ATA; break;
case 2 : options.ColPerm = MMD_AT_PLUS_A; break;
case 3 : options.ColPerm = COLAMD; break;
}
StatInit(&stat);
Create_CompCol_Matrix(&SA, m, n, nz, (double *)(&(csc_A.pr[0])),
(int *)(&(csc_A.ir[0])), (int *)(&(csc_A.jc[0])));
Create_Dense_Matrix(&SB, m, 0, &rhs[0], m);
Create_Dense_Matrix(&SX, m, 0, &sol[0], m);
memset(&SL,0,sizeof SL);
memset(&SU,0,sizeof SU);
equed = 'B';
Rscale.resize(m); Cscale.resize(n); etree.resize(n);
ferr.resize(1); berr.resize(1);
R recip_pivot_gross, rcond;
perm_r.resize(m); perm_c.resize(n);
memory_used = SuperLU_gssvx(&options, &SA, &perm_c[0], &perm_r[0],
&etree[0] /* output */, &equed /* output */,
&Rscale[0] /* row scale factors (output) */,
&Cscale[0] /* col scale factors (output) */,
&SL /* fact L (output)*/, &SU /* fact U (output)*/,
NULL /* work */,
0 /* lwork: superlu auto allocates (input) */,
&SB /* rhs */, &SX /* solution */,
&recip_pivot_gross /* reciprocal pivot growth */
/* factor max_j( norm(A_j)/norm(U_j) ). */,
&rcond /*estimate of the reciprocal condition */
/* number of the matrix A after equilibration */,
&ferr[0] /* estimated forward error */,
&berr[0] /* relative backward error */,
&stat, &info, T());
Destroy_SuperMatrix_Store(&SB);
Destroy_SuperMatrix_Store(&SX);
Create_Dense_Matrix(&SB, m, 1, &rhs[0], m);
Create_Dense_Matrix(&SX, m, 1, &sol[0], m);
StatFree(&stat);
GMM_ASSERT1(info == 0, "SuperLU solve failed: info=" << info);
is_init = true;
}
template <class T> template <typename VECTX, typename VECTB>
void SuperLU_factor<T>::solve(const VECTX &X_, const VECTB &B,
int transp) const {
VECTX &X = const_cast<VECTX &>(X_);
gmm::copy(B, rhs);
options.Fact = FACTORED;
options.IterRefine = NOREFINE;
switch (transp) {
case LU_NOTRANSP: options.Trans = NOTRANS; break;
case LU_TRANSP: options.Trans = TRANS; break;
case LU_CONJUGATED: options.Trans = CONJ; break;
default: GMM_ASSERT1(false, "invalid value for transposition option");
}
StatInit(&stat);
int info = 0;
R recip_pivot_gross, rcond;
SuperLU_gssvx(&options, &SA, &perm_c[0], &perm_r[0],
&etree[0] /* output */, &equed /* output */,
&Rscale[0] /* row scale factors (output) */,
&Cscale[0] /* col scale factors (output) */,
&SL /* fact L (output)*/, &SU /* fact U (output)*/,
NULL /* work */,
0 /* lwork: superlu auto allocates (input) */,
&SB /* rhs */, &SX /* solution */,
&recip_pivot_gross /* reciprocal pivot growth */
/* factor max_j( norm(A_j)/norm(U_j) ). */,
&rcond /*estimate of the reciprocal condition */
/* number of the matrix A after equilibration */,
&ferr[0] /* estimated forward error */,
&berr[0] /* relative backward error */,
&stat, &info, T());
StatFree(&stat);
GMM_ASSERT1(info == 0, "SuperLU solve failed: info=" << info);
gmm::copy(sol, X);
}
template <typename T, typename V1, typename V2> inline
void mult(const SuperLU_factor<T>& P, const V1 &v1, const V2 &v2) {
P.solve(v2,v1);
}
template <typename T, typename V1, typename V2> inline
void transposed_mult(const SuperLU_factor<T>& P,const V1 &v1,const V2 &v2) {
P.solve(v2, v1, SuperLU_factor<T>::LU_TRANSP);
}
}
#endif // GMM_SUPERLU_INTERFACE_H
#endif // GMM_USES_SUPERLU

244
gmm/gmm_transposed.h Normal file
View File

@ -0,0 +1,244 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_transposed.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date November 10, 2002.
@brief Generic transposed matrices
*/
#ifndef GMM_TRANSPOSED_H__
#define GMM_TRANSPOSED_H__
#include "gmm_def.h"
namespace gmm {
/* ********************************************************************* */
/* transposed reference */
/* ********************************************************************* */
template <typename PT> struct transposed_row_ref {
typedef transposed_row_ref<PT> this_type;
typedef typename std::iterator_traits<PT>::value_type M;
typedef M * CPT;
typedef typename std::iterator_traits<PT>::reference ref_M;
typedef typename select_ref<typename linalg_traits<this_type>
::const_col_iterator, typename linalg_traits<this_type>
::col_iterator, PT>::ref_type iterator;
typedef typename linalg_traits<this_type>::reference reference;
typedef typename linalg_traits<this_type>::porigin_type porigin_type;
iterator begin_, end_;
porigin_type origin;
size_type nr, nc;
transposed_row_ref(ref_M m)
: begin_(mat_row_begin(m)), end_(mat_row_end(m)),
origin(linalg_origin(m)), nr(mat_ncols(m)), nc(mat_nrows(m)) {}
transposed_row_ref(const transposed_row_ref<CPT> &cr) :
begin_(cr.begin_),end_(cr.end_), origin(cr.origin),nr(cr.nr),nc(cr.nc) {}
reference operator()(size_type i, size_type j) const
{ return linalg_traits<M>::access(begin_+j, i); }
};
template <typename PT> struct linalg_traits<transposed_row_ref<PT> > {
typedef transposed_row_ref<PT> this_type;
typedef typename std::iterator_traits<PT>::value_type M;
typedef typename linalg_traits<M>::origin_type origin_type;
typedef typename select_ref<const origin_type *, origin_type *,
PT>::ref_type porigin_type;
typedef typename which_reference<PT>::is_reference is_reference;
typedef abstract_matrix linalg_type;
typedef typename linalg_traits<M>::value_type value_type;
typedef typename select_ref<value_type,
typename linalg_traits<M>::reference, PT>::ref_type reference;
typedef typename linalg_traits<M>::storage_type storage_type;
typedef abstract_null_type sub_row_type;
typedef abstract_null_type const_sub_row_type;
typedef abstract_null_type row_iterator;
typedef abstract_null_type const_row_iterator;
typedef typename linalg_traits<M>::const_sub_row_type const_sub_col_type;
typedef typename select_ref<abstract_null_type, typename
linalg_traits<M>::sub_row_type, PT>::ref_type sub_col_type;
typedef typename linalg_traits<M>::const_row_iterator const_col_iterator;
typedef typename select_ref<abstract_null_type, typename
linalg_traits<M>::row_iterator, PT>::ref_type col_iterator;
typedef col_major sub_orientation;
typedef typename linalg_traits<M>::index_sorted index_sorted;
static size_type ncols(const this_type &v) { return v.nc; }
static size_type nrows(const this_type &v) { return v.nr; }
static const_sub_col_type col(const const_col_iterator &it)
{ return linalg_traits<M>::row(it); }
static sub_col_type col(const col_iterator &it)
{ return linalg_traits<M>::row(it); }
static col_iterator col_begin(this_type &m) { return m.begin_; }
static col_iterator col_end(this_type &m) { return m.end_; }
static const_col_iterator col_begin(const this_type &m)
{ return m.begin_; }
static const_col_iterator col_end(const this_type &m) { return m.end_; }
static origin_type* origin(this_type &v) { return v.origin; }
static const origin_type* origin(const this_type &v) { return v.origin; }
static void do_clear(this_type &v);
static value_type access(const const_col_iterator &itcol, size_type i)
{ return linalg_traits<M>::access(itcol, i); }
static reference access(const col_iterator &itcol, size_type i)
{ return linalg_traits<M>::access(itcol, i); }
};
template <typename PT>
void linalg_traits<transposed_row_ref<PT> >::do_clear(this_type &v) {
col_iterator it = mat_col_begin(v), ite = mat_col_end(v);
for (; it != ite; ++it) clear(col(it));
}
template<typename PT> std::ostream &operator <<
(std::ostream &o, const transposed_row_ref<PT>& m)
{ gmm::write(o,m); return o; }
template <typename PT> struct transposed_col_ref {
typedef transposed_col_ref<PT> this_type;
typedef typename std::iterator_traits<PT>::value_type M;
typedef M * CPT;
typedef typename std::iterator_traits<PT>::reference ref_M;
typedef typename select_ref<typename linalg_traits<this_type>
::const_row_iterator, typename linalg_traits<this_type>
::row_iterator, PT>::ref_type iterator;
typedef typename linalg_traits<this_type>::reference reference;
typedef typename linalg_traits<this_type>::porigin_type porigin_type;
iterator begin_, end_;
porigin_type origin;
size_type nr, nc;
transposed_col_ref(ref_M m)
: begin_(mat_col_begin(m)), end_(mat_col_end(m)),
origin(linalg_origin(m)), nr(mat_ncols(m)), nc(mat_nrows(m)) {}
transposed_col_ref(const transposed_col_ref<CPT> &cr) :
begin_(cr.begin_),end_(cr.end_), origin(cr.origin),nr(cr.nr),nc(cr.nc) {}
reference operator()(size_type i, size_type j) const
{ return linalg_traits<M>::access(begin_+i, j); }
};
template <typename PT> struct linalg_traits<transposed_col_ref<PT> > {
typedef transposed_col_ref<PT> this_type;
typedef typename std::iterator_traits<PT>::value_type M;
typedef typename linalg_traits<M>::origin_type origin_type;
typedef typename select_ref<const origin_type *, origin_type *,
PT>::ref_type porigin_type;
typedef typename which_reference<PT>::is_reference is_reference;
typedef abstract_matrix linalg_type;
typedef typename linalg_traits<M>::value_type value_type;
typedef typename select_ref<value_type,
typename linalg_traits<M>::reference, PT>::ref_type reference;
typedef typename linalg_traits<M>::storage_type storage_type;
typedef abstract_null_type sub_col_type;
typedef abstract_null_type const_sub_col_type;
typedef abstract_null_type col_iterator;
typedef abstract_null_type const_col_iterator;
typedef typename linalg_traits<M>::const_sub_col_type const_sub_row_type;
typedef typename select_ref<abstract_null_type, typename
linalg_traits<M>::sub_col_type, PT>::ref_type sub_row_type;
typedef typename linalg_traits<M>::const_col_iterator const_row_iterator;
typedef typename select_ref<abstract_null_type, typename
linalg_traits<M>::col_iterator, PT>::ref_type row_iterator;
typedef row_major sub_orientation;
typedef typename linalg_traits<M>::index_sorted index_sorted;
static size_type nrows(const this_type &v)
{ return v.nr; }
static size_type ncols(const this_type &v)
{ return v.nc; }
static const_sub_row_type row(const const_row_iterator &it)
{ return linalg_traits<M>::col(it); }
static sub_row_type row(const row_iterator &it)
{ return linalg_traits<M>::col(it); }
static row_iterator row_begin(this_type &m) { return m.begin_; }
static row_iterator row_end(this_type &m) { return m.end_; }
static const_row_iterator row_begin(const this_type &m)
{ return m.begin_; }
static const_row_iterator row_end(const this_type &m) { return m.end_; }
static origin_type* origin(this_type &v) { return v.origin; }
static const origin_type* origin(const this_type &v) { return v.origin; }
static void do_clear(this_type &m);
static value_type access(const const_row_iterator &itrow, size_type i)
{ return linalg_traits<M>::access(itrow, i); }
static reference access(const row_iterator &itrow, size_type i)
{ return linalg_traits<M>::access(itrow, i); }
};
template <typename PT>
void linalg_traits<transposed_col_ref<PT> >::do_clear(this_type &v) {
row_iterator it = mat_row_begin(v), ite = mat_row_end(v);
for (; it != ite; ++it) clear(row(it));
}
template<typename PT> std::ostream &operator <<
(std::ostream &o, const transposed_col_ref<PT>& m)
{ gmm::write(o,m); return o; }
template <typename TYPE, typename PT> struct transposed_return_ {
typedef abstract_null_type return_type;
};
template <typename PT> struct transposed_return_<row_major, PT> {
typedef typename std::iterator_traits<PT>::value_type L;
typedef typename select_return<transposed_row_ref<const L *>,
transposed_row_ref< L *>, PT>::return_type return_type;
};
template <typename PT> struct transposed_return_<col_major, PT> {
typedef typename std::iterator_traits<PT>::value_type L;
typedef typename select_return<transposed_col_ref<const L *>,
transposed_col_ref< L *>, PT>::return_type return_type;
};
template <typename PT> struct transposed_return {
typedef typename std::iterator_traits<PT>::value_type L;
typedef typename transposed_return_<typename principal_orientation_type<
typename linalg_traits<L>::sub_orientation>::potype,
PT>::return_type return_type;
};
template <typename L> inline
typename transposed_return<const L *>::return_type transposed(const L &l) {
return typename transposed_return<const L *>::return_type
(linalg_cast(const_cast<L &>(l)));
}
template <typename L> inline
typename transposed_return<L *>::return_type transposed(L &l)
{ return typename transposed_return<L *>::return_type(linalg_cast(l)); }
}
#endif // GMM_TRANSPOSED_H__

222
gmm/gmm_tri_solve.h Normal file
View File

@ -0,0 +1,222 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2002-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_tri_solve.h
@author Yves Renard
@date October 13, 2002.
@brief Solve triangular linear system for dense matrices.
*/
#ifndef GMM_TRI_SOLVE_H__
#define GMM_TRI_SOLVE_H__
#include "gmm_interface.h"
namespace gmm {
template <typename TriMatrix, typename VecX>
void upper_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
col_major, abstract_sparse, bool is_unit) {
typename linalg_traits<TriMatrix>::value_type x_j;
for (int j = int(k) - 1; j >= 0; --j) {
typedef typename linalg_traits<TriMatrix>::const_sub_col_type COL;
COL c = mat_const_col(T, j);
typename linalg_traits<typename org_type<COL>::t>::const_iterator
it = vect_const_begin(c), ite = vect_const_end(c);
if (!is_unit) x[j] /= c[j];
for (x_j = x[j]; it != ite ; ++it)
if (int(it.index()) < j) x[it.index()] -= x_j * (*it);
}
}
template <typename TriMatrix, typename VecX>
void upper_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
col_major, abstract_dense, bool is_unit) {
typename linalg_traits<TriMatrix>::value_type x_j;
for (int j = int(k) - 1; j >= 0; --j) {
typedef typename linalg_traits<TriMatrix>::const_sub_col_type COL;
COL c = mat_const_col(T, j);
typename linalg_traits<typename org_type<COL>::t>::const_iterator
it = vect_const_begin(c), ite = it + j;
typename linalg_traits<VecX>::iterator itx = vect_begin(x);
if (!is_unit) x[j] /= c[j];
for (x_j = x[j]; it != ite ; ++it, ++itx) *itx -= x_j * (*it);
}
}
template <typename TriMatrix, typename VecX>
void lower_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
col_major, abstract_sparse, bool is_unit) {
typename linalg_traits<TriMatrix>::value_type x_j;
// cout << "(lower col)The Tri Matrix = " << T << endl;
// cout << "k = " << endl;
for (int j = 0; j < int(k); ++j) {
typedef typename linalg_traits<TriMatrix>::const_sub_col_type COL;
COL c = mat_const_col(T, j);
typename linalg_traits<typename org_type<COL>::t>::const_iterator
it = vect_const_begin(c), ite = vect_const_end(c);
if (!is_unit) x[j] /= c[j];
for (x_j = x[j]; it != ite ; ++it)
if (int(it.index()) > j && it.index() < k) x[it.index()] -= x_j*(*it);
}
}
template <typename TriMatrix, typename VecX>
void lower_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
col_major, abstract_dense, bool is_unit) {
typename linalg_traits<TriMatrix>::value_type x_j;
for (int j = 0; j < int(k); ++j) {
typedef typename linalg_traits<TriMatrix>::const_sub_col_type COL;
COL c = mat_const_col(T, j);
typename linalg_traits<typename org_type<COL>::t>::const_iterator
it = vect_const_begin(c) + (j+1), ite = vect_const_begin(c) + k;
typename linalg_traits<VecX>::iterator itx = vect_begin(x) + (j+1);
if (!is_unit) x[j] /= c[j];
for (x_j = x[j]; it != ite ; ++it, ++itx) *itx -= x_j * (*it);
}
}
template <typename TriMatrix, typename VecX>
void upper_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
row_major, abstract_sparse, bool is_unit) {
typedef typename linalg_traits<TriMatrix>::const_sub_row_type ROW;
typename linalg_traits<TriMatrix>::value_type t;
typename linalg_traits<TriMatrix>::const_row_iterator
itr = mat_row_const_end(T);
for (int i = int(k) - 1; i >= 0; --i) {
--itr;
ROW c = linalg_traits<TriMatrix>::row(itr);
typename linalg_traits<typename org_type<ROW>::t>::const_iterator
it = vect_const_begin(c), ite = vect_const_end(c);
for (t = x[i]; it != ite; ++it)
if (int(it.index()) > i && it.index() < k) t -= (*it) * x[it.index()];
if (!is_unit) x[i] = t / c[i]; else x[i] = t;
}
}
template <typename TriMatrix, typename VecX>
void upper_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
row_major, abstract_dense, bool is_unit) {
typename linalg_traits<TriMatrix>::value_type t;
for (int i = int(k) - 1; i >= 0; --i) {
typedef typename linalg_traits<TriMatrix>::const_sub_row_type ROW;
ROW c = mat_const_row(T, i);
typename linalg_traits<typename org_type<ROW>::t>::const_iterator
it = vect_const_begin(c) + (i + 1), ite = vect_const_begin(c) + k;
typename linalg_traits<VecX>::iterator itx = vect_begin(x) + (i+1);
for (t = x[i]; it != ite; ++it, ++itx) t -= (*it) * (*itx);
if (!is_unit) x[i] = t / c[i]; else x[i] = t;
}
}
template <typename TriMatrix, typename VecX>
void lower_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
row_major, abstract_sparse, bool is_unit) {
typename linalg_traits<TriMatrix>::value_type t;
for (int i = 0; i < int(k); ++i) {
typedef typename linalg_traits<TriMatrix>::const_sub_row_type ROW;
ROW c = mat_const_row(T, i);
typename linalg_traits<typename org_type<ROW>::t>::const_iterator
it = vect_const_begin(c), ite = vect_const_end(c);
for (t = x[i]; it != ite; ++it)
if (int(it.index()) < i) t -= (*it) * x[it.index()];
if (!is_unit) x[i] = t / c[i]; else x[i] = t;
}
}
template <typename TriMatrix, typename VecX>
void lower_tri_solve__(const TriMatrix& T, VecX& x, size_t k,
row_major, abstract_dense, bool is_unit) {
typename linalg_traits<TriMatrix>::value_type t;
for (int i = 0; i < int(k); ++i) {
typedef typename linalg_traits<TriMatrix>::const_sub_row_type ROW;
ROW c = mat_const_row(T, i);
typename linalg_traits<typename org_type<ROW>::t>::const_iterator
it = vect_const_begin(c), ite = it + i;
typename linalg_traits<VecX>::iterator itx = vect_begin(x);
for (t = x[i]; it != ite; ++it, ++itx) t -= (*it) * (*itx);
if (!is_unit) x[i] = t / c[i]; else x[i] = t;
}
}
// Triangular Solve: x <-- T^{-1} * x
template <typename TriMatrix, typename VecX> inline
void upper_tri_solve(const TriMatrix& T, VecX &x_, bool is_unit = false)
{ upper_tri_solve(T, x_, mat_nrows(T), is_unit); }
template <typename TriMatrix, typename VecX> inline
void lower_tri_solve(const TriMatrix& T, VecX &x_, bool is_unit = false)
{ lower_tri_solve(T, x_, mat_nrows(T), is_unit); }
template <typename TriMatrix, typename VecX> inline
void upper_tri_solve(const TriMatrix& T, VecX &x_, size_t k,
bool is_unit) {
VecX& x = const_cast<VecX&>(x_);
GMM_ASSERT2(mat_nrows(T) >= k && vect_size(x) >= k
&& mat_ncols(T) >= k && !is_sparse(x_), "dimensions mismatch");
upper_tri_solve__(T, x, k,
typename principal_orientation_type<typename
linalg_traits<TriMatrix>::sub_orientation>::potype(),
typename linalg_traits<TriMatrix>::storage_type(),
is_unit);
}
template <typename TriMatrix, typename VecX> inline
void lower_tri_solve(const TriMatrix& T, VecX &x_, size_t k,
bool is_unit) {
VecX& x = const_cast<VecX&>(x_);
GMM_ASSERT2(mat_nrows(T) >= k && vect_size(x) >= k
&& mat_ncols(T) >= k && !is_sparse(x_), "dimensions mismatch");
lower_tri_solve__(T, x, k,
typename principal_orientation_type<typename
linalg_traits<TriMatrix>::sub_orientation>::potype(),
typename linalg_traits<TriMatrix>::storage_type(),
is_unit);
}
}
#endif // GMM_TRI_SOLVE_H__

1571
gmm/gmm_vector.h Normal file

File diff suppressed because it is too large Load Diff

340
gmm/gmm_vector_to_matrix.h Normal file
View File

@ -0,0 +1,340 @@
/* -*- c++ -*- (enables emacs c++ mode) */
/*===========================================================================
Copyright (C) 2003-2017 Yves Renard
This file is a part of GetFEM++
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, you may use this file as it is a part of a free
software library without restriction. Specifically, if other files
instantiate templates or use macros or inline functions from this file,
or you compile this file and link it with other files to produce an
executable, this file does not by itself cause the resulting executable
to be covered by the GNU Lesser General Public License. This exception
does not however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
===========================================================================*/
/**@file gmm_vector_to_matrix.h
@author Yves Renard <Yves.Renard@insa-lyon.fr>
@date December 6, 2003.
@brief View vectors as row or column matrices. */
#ifndef GMM_VECTOR_TO_MATRIX_H__
#define GMM_VECTOR_TO_MATRIX_H__
#include "gmm_interface.h"
namespace gmm {
/* ********************************************************************* */
/* row vector -> transform a vector in a (1, n) matrix. */
/* ********************************************************************* */
template <typename PT> struct gen_row_vector {
typedef gen_row_vector<PT> this_type;
typedef typename std::iterator_traits<PT>::value_type V;
typedef V * CPT;
typedef typename std::iterator_traits<PT>::reference ref_V;
typedef typename linalg_traits<this_type>::reference reference;
simple_vector_ref<PT> vec;
reference operator()(size_type, size_type j) const { return vec[j]; }
size_type nrows(void) const { return 1; }
size_type ncols(void) const { return vect_size(vec); }
gen_row_vector(ref_V v) : vec(v) {}
gen_row_vector() {}
gen_row_vector(const gen_row_vector<CPT> &cr) : vec(cr.vec) {}
};
template <typename PT>
struct gen_row_vector_iterator {
typedef gen_row_vector<PT> this_type;
typedef typename modifiable_pointer<PT>::pointer MPT;
typedef typename std::iterator_traits<PT>::value_type V;
typedef simple_vector_ref<PT> value_type;
typedef const simple_vector_ref<PT> *pointer;
typedef const simple_vector_ref<PT> &reference;
typedef ptrdiff_t difference_type;
typedef size_t size_type;
typedef std::random_access_iterator_tag iterator_category;
typedef gen_row_vector_iterator<PT> iterator;
simple_vector_ref<PT> vec;
bool isend;
iterator &operator ++() { isend = true; return *this; }
iterator &operator --() { isend = false; return *this; }
iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
iterator &operator +=(difference_type i)
{ if (i) isend = false; return *this; }
iterator &operator -=(difference_type i)
{ if (i) isend = true; return *this; }
iterator operator +(difference_type i) const
{ iterator itt = *this; return (itt += i); }
iterator operator -(difference_type i) const
{ iterator itt = *this; return (itt -= i); }
difference_type operator -(const iterator &i) const {
return (isend == true) ? ((i.isend == true) ? 0 : 1)
: ((i.isend == true) ? -1 : 0);
}
const simple_vector_ref<PT>& operator *() const { return vec; }
const simple_vector_ref<PT>& operator [](int i) { return vec; }
bool operator ==(const iterator &i) const { return (isend == i.isend); }
bool operator !=(const iterator &i) const { return !(i == *this); }
bool operator < (const iterator &i) const { return (*this - i < 0); }
gen_row_vector_iterator(void) {}
gen_row_vector_iterator(const gen_row_vector_iterator<MPT> &itm)
: vec(itm.vec), isend(itm.isend) {}
gen_row_vector_iterator(const gen_row_vector<PT> &m, bool iis_end)
: vec(m.vec), isend(iis_end) { }
};
template <typename PT>
struct linalg_traits<gen_row_vector<PT> > {
typedef gen_row_vector<PT> this_type;
typedef typename std::iterator_traits<PT>::value_type V;
typedef typename which_reference<PT>::is_reference is_reference;
typedef abstract_matrix linalg_type;
typedef typename linalg_traits<V>::origin_type origin_type;
typedef typename select_ref<const origin_type *, origin_type *,
PT>::ref_type porigin_type;
typedef typename linalg_traits<V>::value_type value_type;
typedef typename select_ref<value_type,
typename linalg_traits<V>::reference, PT>::ref_type reference;
typedef abstract_null_type sub_col_type;
typedef abstract_null_type col_iterator;
typedef abstract_null_type const_sub_col_type;
typedef abstract_null_type const_col_iterator;
typedef simple_vector_ref<const V *> const_sub_row_type;
typedef typename select_ref<abstract_null_type,
simple_vector_ref<V *>, PT>::ref_type sub_row_type;
typedef gen_row_vector_iterator<typename const_pointer<PT>::pointer>
const_row_iterator;
typedef typename select_ref<abstract_null_type,
gen_row_vector_iterator<PT>, PT>::ref_type row_iterator;
typedef typename linalg_traits<V>::storage_type storage_type;
typedef row_major sub_orientation;
typedef typename linalg_traits<V>::index_sorted index_sorted;
static size_type nrows(const this_type &) { return 1; }
static size_type ncols(const this_type &m) { return m.ncols(); }
static const_sub_row_type row(const const_row_iterator &it) { return *it; }
static sub_row_type row(const row_iterator &it) { return *it; }
static const_row_iterator row_begin(const this_type &m)
{ return const_row_iterator(m, false); }
static row_iterator row_begin(this_type &m)
{ return row_iterator(m, false); }
static const_row_iterator row_end(const this_type &m)
{ return const_row_iterator(m, true); }
static row_iterator row_end(this_type &m)
{ return row_iterator(m, true); }
static origin_type* origin(this_type &m) { return m.vec.origin; }
static const origin_type* origin(const this_type &m)
{ return m.vec.origin; }
static void do_clear(this_type &m)
{ clear(row(mat_row_begin(m))); }
static value_type access(const const_row_iterator &itrow, size_type i)
{ return itrow.vec[i]; }
static reference access(const row_iterator &itrow, size_type i)
{ return itrow.vec[i]; }
};
template <typename PT>
std::ostream &operator <<(std::ostream &o, const gen_row_vector<PT>& m)
{ gmm::write(o,m); return o; }
/* ********************************************************************* */
/* col vector -> transform a vector in a (n, 1) matrix. */
/* ********************************************************************* */
template <typename PT> struct gen_col_vector {
typedef gen_col_vector<PT> this_type;
typedef typename std::iterator_traits<PT>::value_type V;
typedef V * CPT;
typedef typename std::iterator_traits<PT>::reference ref_V;
typedef typename linalg_traits<this_type>::reference reference;
simple_vector_ref<PT> vec;
reference operator()(size_type i, size_type) const { return vec[i]; }
size_type ncols(void) const { return 1; }
size_type nrows(void) const { return vect_size(vec); }
gen_col_vector(ref_V v) : vec(v) {}
gen_col_vector() {}
gen_col_vector(const gen_col_vector<CPT> &cr) : vec(cr.vec) {}
};
template <typename PT>
struct gen_col_vector_iterator {
typedef gen_col_vector<PT> this_type;
typedef typename modifiable_pointer<PT>::pointer MPT;
typedef typename std::iterator_traits<PT>::value_type V;
typedef simple_vector_ref<PT> value_type;
typedef const simple_vector_ref<PT> *pointer;
typedef const simple_vector_ref<PT> &reference;
typedef ptrdiff_t difference_type;
typedef size_t size_type;
typedef std::random_access_iterator_tag iterator_category;
typedef gen_col_vector_iterator<PT> iterator;
simple_vector_ref<PT> vec;
bool isend;
iterator &operator ++() { isend = true; return *this; }
iterator &operator --() { isend = false; return *this; }
iterator operator ++(int) { iterator tmp = *this; ++(*this); return tmp; }
iterator operator --(int) { iterator tmp = *this; --(*this); return tmp; }
iterator &operator +=(difference_type i)
{ if (i) isend = false; return *this; }
iterator &operator -=(difference_type i)
{ if (i) isend = true; return *this; }
iterator operator +(difference_type i) const
{ iterator itt = *this; return (itt += i); }
iterator operator -(difference_type i) const
{ iterator itt = *this; return (itt -= i); }
difference_type operator -(const iterator &i) const {
return (isend == true) ? ((i.isend == true) ? 0 : 1)
: ((i.isend == true) ? -1 : 0);
}
const simple_vector_ref<PT>& operator *() const { return vec; }
const simple_vector_ref<PT>& operator [](int i) { return vec; }
bool operator ==(const iterator &i) const { return (isend == i.isend); }
bool operator !=(const iterator &i) const { return !(i == *this); }
bool operator < (const iterator &i) const { return (*this - i < 0); }
gen_col_vector_iterator(void) {}
gen_col_vector_iterator(const gen_col_vector_iterator<MPT> &itm)
: vec(itm.vec), isend(itm.isend) {}
gen_col_vector_iterator(const gen_col_vector<PT> &m, bool iis_end)
: vec(m.vec), isend(iis_end) { }
};
template <typename PT>
struct linalg_traits<gen_col_vector<PT> > {
typedef gen_col_vector<PT> this_type;
typedef typename std::iterator_traits<PT>::value_type V;
typedef typename which_reference<PT>::is_reference is_reference;
typedef abstract_matrix linalg_type;
typedef typename linalg_traits<V>::origin_type origin_type;
typedef typename select_ref<const origin_type *, origin_type *,
PT>::ref_type porigin_type;
typedef typename linalg_traits<V>::value_type value_type;
typedef typename select_ref<value_type,
typename linalg_traits<V>::reference, PT>::ref_type reference;
typedef abstract_null_type sub_row_type;
typedef abstract_null_type row_iterator;
typedef abstract_null_type const_sub_row_type;
typedef abstract_null_type const_row_iterator;
typedef simple_vector_ref<const V *> const_sub_col_type;
typedef typename select_ref<abstract_null_type,
simple_vector_ref<V *>, PT>::ref_type sub_col_type;
typedef gen_col_vector_iterator<typename const_pointer<PT>::pointer>
const_col_iterator;
typedef typename select_ref<abstract_null_type,
gen_col_vector_iterator<PT>, PT>::ref_type col_iterator;
typedef typename linalg_traits<V>::storage_type storage_type;
typedef col_major sub_orientation;
typedef typename linalg_traits<V>::index_sorted index_sorted;
static size_type ncols(const this_type &) { return 1; }
static size_type nrows(const this_type &m) { return m.nrows(); }
static const_sub_col_type col(const const_col_iterator &it) { return *it; }
static sub_col_type col(const col_iterator &it) { return *it; }
static const_col_iterator col_begin(const this_type &m)
{ return const_col_iterator(m, false); }
static col_iterator col_begin(this_type &m)
{ return col_iterator(m, false); }
static const_col_iterator col_end(const this_type &m)
{ return const_col_iterator(m, true); }
static col_iterator col_end(this_type &m)
{ return col_iterator(m, true); }
static origin_type* origin(this_type &m) { return m.vec.origin; }
static const origin_type* origin(const this_type &m)
{ return m.vec.origin; }
static void do_clear(this_type &m)
{ clear(col(mat_col_begin(m))); }
static value_type access(const const_col_iterator &itcol, size_type i)
{ return itcol.vec[i]; }
static reference access(const col_iterator &itcol, size_type i)
{ return itcol.vec[i]; }
};
template <typename PT>
std::ostream &operator <<(std::ostream &o, const gen_col_vector<PT>& m)
{ gmm::write(o,m); return o; }
/* ******************************************************************** */
/* col and row vectors */
/* ******************************************************************** */
template <class V> inline
typename select_return< gen_row_vector<const V *>, gen_row_vector<V *>,
const V *>::return_type
row_vector(const V& v) {
return typename select_return< gen_row_vector<const V *>,
gen_row_vector<V *>, const V *>::return_type(linalg_cast(v));
}
template <class V> inline
typename select_return< gen_row_vector<const V *>, gen_row_vector<V *>,
V *>::return_type
row_vector(V& v) {
return typename select_return< gen_row_vector<const V *>,
gen_row_vector<V *>, V *>::return_type(linalg_cast(v));
}
template <class V> inline gen_row_vector<const V *>
const_row_vector(V& v)
{ return gen_row_vector<const V *>(v); }
template <class V> inline
typename select_return< gen_col_vector<const V *>, gen_col_vector<V *>,
const V *>::return_type
col_vector(const V& v) {
return typename select_return< gen_col_vector<const V *>,
gen_col_vector<V *>, const V *>::return_type(linalg_cast(v));
}
template <class V> inline
typename select_return< gen_col_vector<const V *>, gen_col_vector<V *>,
V *>::return_type
col_vector(V& v) {
return typename select_return< gen_col_vector<const V *>,
gen_col_vector<V *>, V *>::return_type(linalg_cast(v));
}
template <class V> inline gen_col_vector<const V *>
const_col_vector(V& v)
{ return gen_col_vector<const V *>(v); }
}
#endif // GMM_VECTOR_TO_MATRIX_H__

2
hecl

@ -1 +1 @@
Subproject commit 34e28fe18c77efe661e04742f9b3350eba880267
Subproject commit f949aabf5c4632df97746c273cab27a1ea1bffe4