mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-09-12 09:23:12 +08:00
Merge
This commit is contained in:
commit
2008f76120
613
COPYING.LGPL
613
COPYING.LGPL
@ -1,165 +1,502 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
Preamble
|
||||
|
||||
0. Additional Definitions.
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
4. Combined Works.
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library 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 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
@ -5,6 +5,9 @@ Eigen is primarily MPL2 licensed. See COPYING.MPL2 and these links:
|
||||
Some files contain third-party code under BSD or LGPL licenses, whence the other
|
||||
COPYING.* files here.
|
||||
|
||||
All the LGPL code is either LGPL 2.1-only, or LGPL 2.1-or-later.
|
||||
For this reason, the COPYING.LGPL file contains the LGPL 2.1 text.
|
||||
|
||||
If you want to guarantee that the Eigen code that you are #including is licensed
|
||||
under the MPL2 and possibly more permissive licenses (like BSD), #define this
|
||||
preprocessor symbol:
|
||||
|
32
Eigen/Core
32
Eigen/Core
@ -87,19 +87,25 @@
|
||||
// so, to avoid compile errors when windows.h is included after Eigen/Core, ensure intrinsics are extern "C" here too.
|
||||
// notice that since these are C headers, the extern "C" is theoretically needed anyways.
|
||||
extern "C" {
|
||||
#include <emmintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
#ifdef EIGEN_VECTORIZE_SSE3
|
||||
#include <pmmintrin.h>
|
||||
#endif
|
||||
#ifdef EIGEN_VECTORIZE_SSSE3
|
||||
#include <tmmintrin.h>
|
||||
#endif
|
||||
#ifdef EIGEN_VECTORIZE_SSE4_1
|
||||
#include <smmintrin.h>
|
||||
#endif
|
||||
#ifdef EIGEN_VECTORIZE_SSE4_2
|
||||
#include <nmmintrin.h>
|
||||
// In theory we should only include immintrin.h and not the other *mmintrin.h header files directly.
|
||||
// Doing so triggers some issues with ICC. However old gcc versions seems to not have this file, thus:
|
||||
#ifdef __INTEL_COMPILER
|
||||
#include <immintrin.h>
|
||||
#else
|
||||
#include <emmintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
#ifdef EIGEN_VECTORIZE_SSE3
|
||||
#include <pmmintrin.h>
|
||||
#endif
|
||||
#ifdef EIGEN_VECTORIZE_SSSE3
|
||||
#include <tmmintrin.h>
|
||||
#endif
|
||||
#ifdef EIGEN_VECTORIZE_SSE4_1
|
||||
#include <smmintrin.h>
|
||||
#endif
|
||||
#ifdef EIGEN_VECTORIZE_SSE4_2
|
||||
#include <nmmintrin.h>
|
||||
#endif
|
||||
#endif
|
||||
} // end extern "C"
|
||||
#elif defined __ALTIVEC__
|
||||
|
26
Eigen/MetisSupport
Normal file
26
Eigen/MetisSupport
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef EIGEN_METISSUPPORT_MODULE_H
|
||||
#define EIGEN_METISSUPPORT_MODULE_H
|
||||
|
||||
#include "SparseCore"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
extern "C" {
|
||||
#include <metis.h>
|
||||
}
|
||||
|
||||
|
||||
/** \ingroup Support_modules
|
||||
* \defgroup MetisSupport_Module MetisSupport module
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/MetisSupport>
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
|
||||
#include "src/MetisSupport/MetisSupport.h"
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_METISSUPPORT_MODULE_H
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
#include "src/OrderingMethods/Amd.h"
|
||||
|
||||
#include "src/OrderingMethods/Ordering.h"
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_ORDERINGMETHODS_MODULE_H
|
||||
|
17
Eigen/SparseLU
Normal file
17
Eigen/SparseLU
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef EIGEN_SPARSELU_MODULE_H
|
||||
#define EIGEN_SPARSELU_MODULE_H
|
||||
|
||||
#include "SparseCore"
|
||||
|
||||
|
||||
/** \ingroup Sparse_modules
|
||||
* \defgroup SparseLU_Module SparseLU module
|
||||
*
|
||||
*/
|
||||
|
||||
// Ordering interface
|
||||
#include "OrderingMethods"
|
||||
|
||||
#include "src/SparseLU/SparseLU.h"
|
||||
|
||||
#endif // EIGEN_SPARSELU_MODULE_H
|
@ -20,6 +20,7 @@ class DiagonalBase : public EigenBase<Derived>
|
||||
public:
|
||||
typedef typename internal::traits<Derived>::DiagonalVectorType DiagonalVectorType;
|
||||
typedef typename DiagonalVectorType::Scalar Scalar;
|
||||
typedef typename DiagonalVectorType::RealScalar RealScalar;
|
||||
typedef typename internal::traits<Derived>::StorageKind StorageKind;
|
||||
typedef typename internal::traits<Derived>::Index Index;
|
||||
|
||||
@ -65,6 +66,17 @@ class DiagonalBase : public EigenBase<Derived>
|
||||
return diagonal().cwiseInverse();
|
||||
}
|
||||
|
||||
inline const DiagonalWrapper<const CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const DiagonalVectorType> >
|
||||
operator*(const Scalar& scalar) const
|
||||
{
|
||||
return diagonal() * scalar;
|
||||
}
|
||||
friend inline const DiagonalWrapper<const CwiseUnaryOp<internal::scalar_multiple_op<Scalar>, const DiagonalVectorType> >
|
||||
operator*(const Scalar& scalar, const DiagonalBase& other)
|
||||
{
|
||||
return other.diagonal() * scalar;
|
||||
}
|
||||
|
||||
#ifdef EIGEN2_SUPPORT
|
||||
template<typename OtherDerived>
|
||||
bool isApprox(const DiagonalBase<OtherDerived>& other, typename NumTraits<Scalar>::Real precision = NumTraits<Scalar>::dummy_precision()) const
|
||||
|
@ -454,7 +454,7 @@ struct functor_traits<scalar_log_op<Scalar> >
|
||||
* indeed it seems better to declare m_other as a Packet and do the pset1() once
|
||||
* in the constructor. However, in practice:
|
||||
* - GCC does not like m_other as a Packet and generate a load every time it needs it
|
||||
* - on the other hand GCC is able to moves the pset1() away the loop :)
|
||||
* - on the other hand GCC is able to moves the pset1() outside the loop :)
|
||||
* - simpler code ;)
|
||||
* (ICC and gcc 4.4 seems to perform well in both cases, the issue is visible with y = a*x + b*y)
|
||||
*/
|
||||
@ -485,33 +485,6 @@ template<typename Scalar1,typename Scalar2>
|
||||
struct functor_traits<scalar_multiple2_op<Scalar1,Scalar2> >
|
||||
{ enum { Cost = NumTraits<Scalar1>::MulCost, PacketAccess = false }; };
|
||||
|
||||
template<typename Scalar, bool IsInteger>
|
||||
struct scalar_quotient1_impl {
|
||||
typedef typename packet_traits<Scalar>::type Packet;
|
||||
// FIXME default copy constructors seems bugged with std::complex<>
|
||||
EIGEN_STRONG_INLINE scalar_quotient1_impl(const scalar_quotient1_impl& other) : m_other(other.m_other) { }
|
||||
EIGEN_STRONG_INLINE scalar_quotient1_impl(const Scalar& other) : m_other(static_cast<Scalar>(1) / other) {}
|
||||
EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a * m_other; }
|
||||
EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const
|
||||
{ return internal::pmul(a, pset1<Packet>(m_other)); }
|
||||
const Scalar m_other;
|
||||
};
|
||||
template<typename Scalar>
|
||||
struct functor_traits<scalar_quotient1_impl<Scalar,false> >
|
||||
{ enum { Cost = NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasMul }; };
|
||||
|
||||
template<typename Scalar>
|
||||
struct scalar_quotient1_impl<Scalar,true> {
|
||||
// FIXME default copy constructors seems bugged with std::complex<>
|
||||
EIGEN_STRONG_INLINE scalar_quotient1_impl(const scalar_quotient1_impl& other) : m_other(other.m_other) { }
|
||||
EIGEN_STRONG_INLINE scalar_quotient1_impl(const Scalar& other) : m_other(other) {}
|
||||
EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a / m_other; }
|
||||
typename add_const_on_value_type<typename NumTraits<Scalar>::Nested>::type m_other;
|
||||
};
|
||||
template<typename Scalar>
|
||||
struct functor_traits<scalar_quotient1_impl<Scalar,true> >
|
||||
{ enum { Cost = 2 * NumTraits<Scalar>::MulCost, PacketAccess = false }; };
|
||||
|
||||
/** \internal
|
||||
* \brief Template functor to divide a scalar by a fixed other one
|
||||
*
|
||||
@ -521,14 +494,19 @@ struct functor_traits<scalar_quotient1_impl<Scalar,true> >
|
||||
* \sa class CwiseUnaryOp, MatrixBase::operator/
|
||||
*/
|
||||
template<typename Scalar>
|
||||
struct scalar_quotient1_op : scalar_quotient1_impl<Scalar, NumTraits<Scalar>::IsInteger > {
|
||||
EIGEN_STRONG_INLINE scalar_quotient1_op(const Scalar& other)
|
||||
: scalar_quotient1_impl<Scalar, NumTraits<Scalar>::IsInteger >(other) {}
|
||||
struct scalar_quotient1_op {
|
||||
typedef typename packet_traits<Scalar>::type Packet;
|
||||
// FIXME default copy constructors seems bugged with std::complex<>
|
||||
EIGEN_STRONG_INLINE scalar_quotient1_op(const scalar_quotient1_op& other) : m_other(other.m_other) { }
|
||||
EIGEN_STRONG_INLINE scalar_quotient1_op(const Scalar& other) : m_other(other) {}
|
||||
EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a / m_other; }
|
||||
EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const
|
||||
{ return internal::pdiv(a, pset1<Packet>(m_other)); }
|
||||
typename add_const_on_value_type<typename NumTraits<Scalar>::Nested>::type m_other;
|
||||
};
|
||||
template<typename Scalar>
|
||||
struct functor_traits<scalar_quotient1_op<Scalar> >
|
||||
: functor_traits<scalar_quotient1_impl<Scalar, NumTraits<Scalar>::IsInteger> >
|
||||
{};
|
||||
{ enum { Cost = 2 * NumTraits<Scalar>::MulCost, PacketAccess = packet_traits<Scalar>::HasDiv }; };
|
||||
|
||||
// nullary functors
|
||||
|
||||
|
@ -240,7 +240,7 @@ template<typename Derived> class MatrixBase
|
||||
|
||||
// huuuge hack. make Eigen2's matrix.part<Diagonal>() work in eigen3. Problem: Diagonal is now a class template instead
|
||||
// of an integer constant. Solution: overload the part() method template wrt template parameters list.
|
||||
template<template<typename T, int n> class U>
|
||||
template<template<typename T, int N> class U>
|
||||
const DiagonalWrapper<ConstDiagonalReturnType> part() const
|
||||
{ return diagonal().asDiagonal(); }
|
||||
#endif // EIGEN2_SUPPORT
|
||||
|
@ -195,12 +195,12 @@ template<typename PlainObjectType, int Options, typename StrideType> class Ref
|
||||
Base::construct(expr);
|
||||
}
|
||||
template<typename Derived>
|
||||
inline Ref(const MatrixBase<Derived>& expr,
|
||||
inline Ref(const DenseBase<Derived>& expr,
|
||||
typename internal::enable_if<bool(internal::is_lvalue<Derived>::value&&bool(Traits::template match<Derived>::MatchAtCompileTime)),Derived>::type* = 0,
|
||||
int = Derived::ThisConstantIsPrivateInPlainObjectBase)
|
||||
#else
|
||||
template<typename Derived>
|
||||
inline Ref(MatrixBase<Derived>& expr)
|
||||
inline Ref(DenseBase<Derived>& expr)
|
||||
#endif
|
||||
{
|
||||
Base::construct(expr.const_cast_derived());
|
||||
@ -221,7 +221,7 @@ template<typename PlainObjectType, int Options, typename StrideType> class Ref<c
|
||||
EIGEN_DENSE_PUBLIC_INTERFACE(Ref)
|
||||
|
||||
template<typename Derived>
|
||||
inline Ref(const MatrixBase<Derived>& expr)
|
||||
inline Ref(const DenseBase<Derived>& expr)
|
||||
{
|
||||
// std::cout << match_helper<Derived>::HasDirectAccess << "," << match_helper<Derived>::OuterStrideMatch << "," << match_helper<Derived>::InnerStrideMatch << "\n";
|
||||
// std::cout << int(StrideType::OuterStrideAtCompileTime) << " - " << int(Derived::OuterStrideAtCompileTime) << "\n";
|
||||
|
@ -131,7 +131,6 @@ MatrixBase<Derived>::blueNorm() const
|
||||
abig = internal::sqrt(abig);
|
||||
if(abig > overfl)
|
||||
{
|
||||
eigen_assert(false && "overflow");
|
||||
return rbig;
|
||||
}
|
||||
if(amed > RealScalar(0))
|
||||
|
@ -511,6 +511,7 @@ template<typename Derived1, typename Derived2, bool ClearOpposite>
|
||||
struct triangular_assignment_selector<Derived1, Derived2, StrictlyUpper, Dynamic, ClearOpposite>
|
||||
{
|
||||
typedef typename Derived1::Index Index;
|
||||
typedef typename Derived1::Scalar Scalar;
|
||||
static inline void run(Derived1 &dst, const Derived2 &src)
|
||||
{
|
||||
for(Index j = 0; j < dst.cols(); ++j)
|
||||
@ -520,7 +521,7 @@ struct triangular_assignment_selector<Derived1, Derived2, StrictlyUpper, Dynamic
|
||||
dst.copyCoeff(i, j, src);
|
||||
if (ClearOpposite)
|
||||
for(Index i = maxi; i < dst.rows(); ++i)
|
||||
dst.coeffRef(i, j) = 0;
|
||||
dst.coeffRef(i, j) = Scalar(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -81,7 +81,7 @@ EIGEN_DONT_INLINE static void run(
|
||||
const Index peels = 2;
|
||||
const Index LhsPacketAlignedMask = LhsPacketSize-1;
|
||||
const Index ResPacketAlignedMask = ResPacketSize-1;
|
||||
const Index PeelAlignedMask = ResPacketSize*peels-1;
|
||||
// const Index PeelAlignedMask = ResPacketSize*peels-1;
|
||||
const Index size = rows;
|
||||
|
||||
// How many coeffs of the result do we have to skip to be aligned.
|
||||
@ -335,7 +335,7 @@ EIGEN_DONT_INLINE static void run(
|
||||
const Index peels = 2;
|
||||
const Index RhsPacketAlignedMask = RhsPacketSize-1;
|
||||
const Index LhsPacketAlignedMask = LhsPacketSize-1;
|
||||
const Index PeelAlignedMask = RhsPacketSize*peels-1;
|
||||
// const Index PeelAlignedMask = RhsPacketSize*peels-1;
|
||||
const Index depth = cols;
|
||||
|
||||
// How many coeffs of the result do we have to skip to be aligned.
|
||||
|
@ -322,9 +322,9 @@ template<typename T, int n=1, typename PlainObject = typename eval<T>::type> str
|
||||
// it's important that this value can still be squared without integer overflowing.
|
||||
DynamicAsInteger = 10000,
|
||||
ScalarReadCost = NumTraits<typename traits<T>::Scalar>::ReadCost,
|
||||
ScalarReadCostAsInteger = ScalarReadCost == Dynamic ? DynamicAsInteger : ScalarReadCost,
|
||||
ScalarReadCostAsInteger = ScalarReadCost == Dynamic ? int(DynamicAsInteger) : int(ScalarReadCost),
|
||||
CoeffReadCost = traits<T>::CoeffReadCost,
|
||||
CoeffReadCostAsInteger = CoeffReadCost == Dynamic ? DynamicAsInteger : CoeffReadCost,
|
||||
CoeffReadCostAsInteger = CoeffReadCost == Dynamic ? int(DynamicAsInteger) : int(CoeffReadCost),
|
||||
NAsInteger = n == Dynamic ? int(DynamicAsInteger) : n,
|
||||
CostEvalAsInteger = (NAsInteger+1) * ScalarReadCostAsInteger + CoeffReadCostAsInteger,
|
||||
CostNoEvalAsInteger = NAsInteger * CoeffReadCostAsInteger
|
||||
|
@ -153,16 +153,21 @@ umeyama(const MatrixBase<Derived>& src, const MatrixBase<OtherDerived>& dst, boo
|
||||
Rt.block(0,0,m,m).noalias() = svd.matrixU() * S.asDiagonal() * svd.matrixV().transpose();
|
||||
}
|
||||
|
||||
// Eq. (42)
|
||||
const Scalar c = 1/src_var * svd.singularValues().dot(S);
|
||||
if (with_scaling)
|
||||
{
|
||||
// Eq. (42)
|
||||
const Scalar c = 1/src_var * svd.singularValues().dot(S);
|
||||
|
||||
// Eq. (41)
|
||||
// Note that we first assign dst_mean to the destination so that there no need
|
||||
// for a temporary.
|
||||
Rt.col(m).head(m) = dst_mean;
|
||||
Rt.col(m).head(m).noalias() -= c*Rt.topLeftCorner(m,m)*src_mean;
|
||||
|
||||
if (with_scaling) Rt.block(0,0,m,m) *= c;
|
||||
// Eq. (41)
|
||||
Rt.col(m).head(m) = dst_mean;
|
||||
Rt.col(m).head(m).noalias() -= c*Rt.topLeftCorner(m,m)*src_mean;
|
||||
Rt.block(0,0,m,m) *= c;
|
||||
}
|
||||
else
|
||||
{
|
||||
Rt.col(m).head(m) = dst_mean;
|
||||
Rt.col(m).head(m).noalias() -= Rt.topLeftCorner(m,m)*src_mean;
|
||||
}
|
||||
|
||||
return Rt;
|
||||
}
|
||||
|
@ -39,10 +39,11 @@ bool bicgstab(const MatrixType& mat, const Rhs& rhs, Dest& x,
|
||||
int maxIters = iters;
|
||||
|
||||
int n = mat.cols();
|
||||
x = precond.solve(x);
|
||||
VectorType r = rhs - mat * x;
|
||||
VectorType r0 = r;
|
||||
|
||||
RealScalar r0_sqnorm = r0.squaredNorm();
|
||||
RealScalar r0_sqnorm = rhs.squaredNorm();
|
||||
Scalar rho = 1;
|
||||
Scalar alpha = 1;
|
||||
Scalar w = 1;
|
||||
@ -223,7 +224,8 @@ public:
|
||||
template<typename Rhs,typename Dest>
|
||||
void _solve(const Rhs& b, Dest& x) const
|
||||
{
|
||||
x.setZero();
|
||||
// x.setZero();
|
||||
x = b;
|
||||
_solveWithGuess(b,x);
|
||||
}
|
||||
|
||||
|
@ -10,8 +10,56 @@
|
||||
#ifndef EIGEN_INCOMPLETE_LUT_H
|
||||
#define EIGEN_INCOMPLETE_LUT_H
|
||||
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
/**
|
||||
* Compute a quick-sort split of a vector
|
||||
* On output, the vector row is permuted such that its elements satisfy
|
||||
* abs(row(i)) >= abs(row(ncut)) if i<ncut
|
||||
* abs(row(i)) <= abs(row(ncut)) if i>ncut
|
||||
* \param row The vector of values
|
||||
* \param ind The array of index for the elements in @p row
|
||||
* \param ncut The number of largest elements to keep
|
||||
**/
|
||||
template <typename VectorV, typename VectorI>
|
||||
int QuickSplit(VectorV &row, VectorI &ind, int ncut)
|
||||
{
|
||||
typedef typename VectorV::RealScalar RealScalar;
|
||||
using std::swap;
|
||||
int mid;
|
||||
int n = row.size(); /* length of the vector */
|
||||
int first, last ;
|
||||
|
||||
ncut--; /* to fit the zero-based indices */
|
||||
first = 0;
|
||||
last = n-1;
|
||||
if (ncut < first || ncut > last ) return 0;
|
||||
|
||||
do {
|
||||
mid = first;
|
||||
RealScalar abskey = std::abs(row(mid));
|
||||
for (int j = first + 1; j <= last; j++) {
|
||||
if ( std::abs(row(j)) > abskey) {
|
||||
++mid;
|
||||
swap(row(mid), row(j));
|
||||
swap(ind(mid), ind(j));
|
||||
}
|
||||
}
|
||||
/* Interchange for the pivot element */
|
||||
swap(row(mid), row(first));
|
||||
swap(ind(mid), ind(first));
|
||||
|
||||
if (mid > ncut) last = mid - 1;
|
||||
else if (mid < ncut ) first = mid + 1;
|
||||
} while (mid != ncut );
|
||||
|
||||
return 0; /* mid is equal to ncut */
|
||||
}
|
||||
|
||||
}// end namespace internal
|
||||
/**
|
||||
* \brief Incomplete LU factorization with dual-threshold strategy
|
||||
* During the numerical factorization, two dropping rules are used :
|
||||
@ -126,10 +174,6 @@ class IncompleteLUT : internal::noncopyable
|
||||
|
||||
protected:
|
||||
|
||||
template <typename VectorV, typename VectorI>
|
||||
int QuickSplit(VectorV &row, VectorI &ind, int ncut);
|
||||
|
||||
|
||||
/** keeps off-diagonal entries; drops diagonal entries */
|
||||
struct keep_diag {
|
||||
inline bool operator() (const Index& row, const Index& col, const Scalar&) const
|
||||
@ -171,51 +215,6 @@ void IncompleteLUT<Scalar>::setFillfactor(int fillfactor)
|
||||
this->m_fillfactor = fillfactor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute a quick-sort split of a vector
|
||||
* On output, the vector row is permuted such that its elements satisfy
|
||||
* abs(row(i)) >= abs(row(ncut)) if i<ncut
|
||||
* abs(row(i)) <= abs(row(ncut)) if i>ncut
|
||||
* \param row The vector of values
|
||||
* \param ind The array of index for the elements in @p row
|
||||
* \param ncut The number of largest elements to keep
|
||||
**/
|
||||
template <typename Scalar>
|
||||
template <typename VectorV, typename VectorI>
|
||||
int IncompleteLUT<Scalar>::QuickSplit(VectorV &row, VectorI &ind, int ncut)
|
||||
{
|
||||
using std::swap;
|
||||
int mid;
|
||||
int n = row.size(); /* length of the vector */
|
||||
int first, last ;
|
||||
|
||||
ncut--; /* to fit the zero-based indices */
|
||||
first = 0;
|
||||
last = n-1;
|
||||
if (ncut < first || ncut > last ) return 0;
|
||||
|
||||
do {
|
||||
mid = first;
|
||||
RealScalar abskey = std::abs(row(mid));
|
||||
for (int j = first + 1; j <= last; j++) {
|
||||
if ( std::abs(row(j)) > abskey) {
|
||||
++mid;
|
||||
swap(row(mid), row(j));
|
||||
swap(ind(mid), ind(j));
|
||||
}
|
||||
}
|
||||
/* Interchange for the pivot element */
|
||||
swap(row(mid), row(first));
|
||||
swap(ind(mid), ind(first));
|
||||
|
||||
if (mid > ncut) last = mid - 1;
|
||||
else if (mid < ncut ) first = mid + 1;
|
||||
} while (mid != ncut );
|
||||
|
||||
return 0; /* mid is equal to ncut */
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
template<typename _MatrixType>
|
||||
void IncompleteLUT<Scalar>::analyzePattern(const _MatrixType& amat)
|
||||
@ -400,7 +399,7 @@ void IncompleteLUT<Scalar>::factorize(const _MatrixType& amat)
|
||||
len = (std::min)(sizel, nnzL);
|
||||
typename Vector::SegmentReturnType ul(u.segment(0, sizel));
|
||||
typename VectorXi::SegmentReturnType jul(ju.segment(0, sizel));
|
||||
QuickSplit(ul, jul, len);
|
||||
internal::QuickSplit(ul, jul, len);
|
||||
|
||||
// store the largest m_fill elements of the L part
|
||||
m_lu.startVec(ii);
|
||||
@ -429,7 +428,7 @@ void IncompleteLUT<Scalar>::factorize(const _MatrixType& amat)
|
||||
len = (std::min)(sizeu, nnzU);
|
||||
typename Vector::SegmentReturnType uu(u.segment(ii+1, sizeu-1));
|
||||
typename VectorXi::SegmentReturnType juu(ju.segment(ii+1, sizeu-1));
|
||||
QuickSplit(uu, juu, len);
|
||||
internal::QuickSplit(uu, juu, len);
|
||||
|
||||
// store the largest elements of the U part
|
||||
for(int k = ii + 1; k < ii + len; k++)
|
||||
|
6
Eigen/src/MetisSupport/CMakeLists.txt
Normal file
6
Eigen/src/MetisSupport/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
FILE(GLOB Eigen_MetisSupport_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_MetisSupport_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/MetisSupport COMPONENT Devel
|
||||
)
|
138
Eigen/src/MetisSupport/MetisSupport.h
Normal file
138
Eigen/src/MetisSupport/MetisSupport.h
Normal file
@ -0,0 +1,138 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef METIS_SUPPORT_H
|
||||
#define METIS_SUPPORT_H
|
||||
|
||||
namespace Eigen {
|
||||
/**
|
||||
* Get the fill-reducing ordering from the METIS package
|
||||
*
|
||||
* If A is the original matrix and Ap is the permuted matrix,
|
||||
* the fill-reducing permutation is defined as follows :
|
||||
* Row (column) i of A is the matperm(i) row (column) of Ap.
|
||||
* WARNING: As computed by METIS, this corresponds to the vector iperm (instead of perm)
|
||||
*/
|
||||
template <typename Index>
|
||||
class MetisOrdering
|
||||
{
|
||||
public:
|
||||
typedef PermutationMatrix<Dynamic,Dynamic,Index> PermutationType;
|
||||
typedef Matrix<Index,Dynamic,1> IndexVector;
|
||||
|
||||
template <typename MatrixType>
|
||||
void get_symmetrized_graph(const MatrixType& A)
|
||||
{
|
||||
Index m = A.cols();
|
||||
|
||||
// Get the transpose of the input matrix
|
||||
MatrixType At = A.transpose();
|
||||
// Get the number of nonzeros elements in each row/col of At+A
|
||||
Index TotNz = 0;
|
||||
IndexVector visited(m);
|
||||
visited.setConstant(-1);
|
||||
for (int j = 0; j < m; j++)
|
||||
{
|
||||
// Compute the union structure of of A(j,:) and At(j,:)
|
||||
visited(j) = j; // Do not include the diagonal element
|
||||
// Get the nonzeros in row/column j of A
|
||||
for (typename MatrixType::InnerIterator it(A, j); it; ++it)
|
||||
{
|
||||
Index idx = it.index(); // Get the row index (for column major) or column index (for row major)
|
||||
if (visited(idx) != j )
|
||||
{
|
||||
visited(idx) = j;
|
||||
++TotNz;
|
||||
}
|
||||
}
|
||||
//Get the nonzeros in row/column j of At
|
||||
for (typename MatrixType::InnerIterator it(At, j); it; ++it)
|
||||
{
|
||||
Index idx = it.index();
|
||||
if(visited(idx) != j)
|
||||
{
|
||||
visited(idx) = j;
|
||||
++TotNz;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Reserve place for A + At
|
||||
m_indexPtr.resize(m+1);
|
||||
m_innerIndices.resize(TotNz);
|
||||
|
||||
// Now compute the real adjacency list of each column/row
|
||||
visited.setConstant(-1);
|
||||
Index CurNz = 0;
|
||||
for (int j = 0; j < m; j++)
|
||||
{
|
||||
m_indexPtr(j) = CurNz;
|
||||
|
||||
visited(j) = j; // Do not include the diagonal element
|
||||
// Add the pattern of row/column j of A to A+At
|
||||
for (typename MatrixType::InnerIterator it(A,j); it; ++it)
|
||||
{
|
||||
Index idx = it.index(); // Get the row index (for column major) or column index (for row major)
|
||||
if (visited(idx) != j )
|
||||
{
|
||||
visited(idx) = j;
|
||||
m_innerIndices(CurNz) = idx;
|
||||
CurNz++;
|
||||
}
|
||||
}
|
||||
//Add the pattern of row/column j of At to A+At
|
||||
for (typename MatrixType::InnerIterator it(At, j); it; ++it)
|
||||
{
|
||||
Index idx = it.index();
|
||||
if(visited(idx) != j)
|
||||
{
|
||||
visited(idx) = j;
|
||||
m_innerIndices(CurNz) = idx;
|
||||
++CurNz;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_indexPtr(m) = CurNz;
|
||||
}
|
||||
|
||||
template <typename MatrixType>
|
||||
void operator() (const MatrixType& A, PermutationType& matperm)
|
||||
{
|
||||
Index m = A.cols();
|
||||
IndexVector perm(m),iperm(m);
|
||||
// First, symmetrize the matrix graph.
|
||||
get_symmetrized_graph(A);
|
||||
int output_error;
|
||||
|
||||
// Call the fill-reducing routine from METIS
|
||||
output_error = METIS_NodeND(&m, m_indexPtr.data(), m_innerIndices.data(), NULL, NULL, perm.data(), iperm.data());
|
||||
|
||||
if(output_error != METIS_OK)
|
||||
{
|
||||
//FIXME The ordering interface should define a class of possible errors
|
||||
std::cerr << "ERROR WHILE CALLING THE METIS PACKAGE \n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the fill-reducing permutation
|
||||
//NOTE: If Ap is the permuted matrix then perm and iperm vectors are defined as follows
|
||||
// Row (column) i of Ap is the perm(i) row(column) of A, and row (column) i of A is the iperm(i) row(column) of Ap
|
||||
|
||||
// To be consistent with the use of the permutation in SparseLU module, we thus keep the iperm vector
|
||||
matperm.resize(m);
|
||||
for (int j = 0; j < m; j++)
|
||||
matperm.indices()(j) = iperm(j);
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
IndexVector m_indexPtr; // Pointer to the adjacenccy list of each row/column
|
||||
IndexVector m_innerIndices; // Adjacency list
|
||||
};
|
||||
|
||||
}// end namespace eigen
|
||||
#endif
|
1849
Eigen/src/OrderingMethods/Eigen_Colamd.h
Normal file
1849
Eigen/src/OrderingMethods/Eigen_Colamd.h
Normal file
File diff suppressed because it is too large
Load Diff
158
Eigen/src/OrderingMethods/Ordering.h
Normal file
158
Eigen/src/OrderingMethods/Ordering.h
Normal file
@ -0,0 +1,158 @@
|
||||
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// Eigen 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.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen 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 or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_ORDERING_H
|
||||
#define EIGEN_ORDERING_H
|
||||
|
||||
#include "Amd.h"
|
||||
namespace Eigen {
|
||||
|
||||
#include "Eigen_Colamd.h"
|
||||
|
||||
namespace internal {
|
||||
|
||||
/**
|
||||
* Get the symmetric pattern A^T+A from the input matrix A.
|
||||
* FIXME: The values should not be considered here
|
||||
*/
|
||||
template<typename MatrixType>
|
||||
void ordering_helper_at_plus_a(const MatrixType& mat, MatrixType& symmat)
|
||||
{
|
||||
MatrixType C;
|
||||
C = mat.transpose(); // NOTE: Could be costly
|
||||
for (int i = 0; i < C.rows(); i++)
|
||||
{
|
||||
for (typename MatrixType::InnerIterator it(C, i); it; ++it)
|
||||
it.valueRef() = 0.0;
|
||||
}
|
||||
symmat = C + mat;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the approximate minimum degree ordering
|
||||
* If the matrix is not structurally symmetric, an ordering of A^T+A is computed
|
||||
* \tparam Index The type of indices of the matrix
|
||||
*/
|
||||
template <typename Index>
|
||||
class AMDOrdering
|
||||
{
|
||||
public:
|
||||
typedef PermutationMatrix<Dynamic, Dynamic, Index> PermutationType;
|
||||
|
||||
/** Compute the permutation vector from a sparse matrix
|
||||
* This routine is much faster if the input matrix is column-major
|
||||
*/
|
||||
template <typename MatrixType>
|
||||
void operator()(const MatrixType& mat, PermutationType& perm)
|
||||
{
|
||||
// Compute the symmetric pattern
|
||||
SparseMatrix<typename MatrixType::Scalar, ColMajor, Index> symm;
|
||||
internal::ordering_helper_at_plus_a(mat,symm);
|
||||
|
||||
// Call the AMD routine
|
||||
//m_mat.prune(keep_diag());
|
||||
internal::minimum_degree_ordering(symm, perm);
|
||||
}
|
||||
|
||||
/** Compute the permutation with a selfadjoint matrix */
|
||||
template <typename SrcType, unsigned int SrcUpLo>
|
||||
void operator()(const SparseSelfAdjointView<SrcType, SrcUpLo>& mat, PermutationType& perm)
|
||||
{
|
||||
SparseMatrix<typename SrcType::Scalar, ColMajor, Index> C = mat;
|
||||
|
||||
// Call the AMD routine
|
||||
// m_mat.prune(keep_diag()); //Remove the diagonal elements
|
||||
internal::minimum_degree_ordering(C, perm);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the natural ordering
|
||||
*
|
||||
*NOTE Returns an empty permutation matrix
|
||||
* \tparam Index The type of indices of the matrix
|
||||
*/
|
||||
template <typename Index>
|
||||
class NaturalOrdering
|
||||
{
|
||||
public:
|
||||
typedef PermutationMatrix<Dynamic, Dynamic, Index> PermutationType;
|
||||
|
||||
/** Compute the permutation vector from a column-major sparse matrix */
|
||||
template <typename MatrixType>
|
||||
void operator()(const MatrixType& mat, PermutationType& perm)
|
||||
{
|
||||
perm.resize(0);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the column approximate minimum degree ordering
|
||||
* The matrix should be in column-major format
|
||||
*/
|
||||
template<typename Index>
|
||||
class COLAMDOrdering;
|
||||
#include "Eigen_Colamd.h"
|
||||
|
||||
template<typename Index>
|
||||
class COLAMDOrdering
|
||||
{
|
||||
public:
|
||||
typedef PermutationMatrix<Dynamic, Dynamic, Index> PermutationType;
|
||||
typedef Matrix<Index, Dynamic, 1> IndexVector;
|
||||
/** Compute the permutation vector form a sparse matrix */
|
||||
template <typename MatrixType>
|
||||
void operator() (const MatrixType& mat, PermutationType& perm)
|
||||
{
|
||||
int m = mat.rows();
|
||||
int n = mat.cols();
|
||||
int nnz = mat.nonZeros();
|
||||
// Get the recommended value of Alen to be used by colamd
|
||||
int Alen = internal::colamd_recommended(nnz, m, n);
|
||||
// Set the default parameters
|
||||
double knobs [COLAMD_KNOBS];
|
||||
int stats [COLAMD_STATS];
|
||||
internal::colamd_set_defaults(knobs);
|
||||
|
||||
int info;
|
||||
IndexVector p(n+1), A(Alen);
|
||||
for(int i=0; i <= n; i++) p(i) = mat.outerIndexPtr()[i];
|
||||
for(int i=0; i < nnz; i++) A(i) = mat.innerIndexPtr()[i];
|
||||
// Call Colamd routine to compute the ordering
|
||||
info = internal::colamd(m, n, Alen, A.data(), p.data(), knobs, stats);
|
||||
eigen_assert( info && "COLAMD failed " );
|
||||
|
||||
perm.resize(n);
|
||||
for (int i = 0; i < n; i++) perm.indices()(p(i)) = i;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // end namespace Eigen
|
||||
#endif
|
@ -469,6 +469,18 @@ class SparseMatrix
|
||||
m_data.squeeze();
|
||||
}
|
||||
|
||||
/** Turns the matrix into the uncompressed mode */
|
||||
void uncompress()
|
||||
{
|
||||
if(m_innerNonZeros != 0)
|
||||
return;
|
||||
m_innerNonZeros = new Index[m_outerSize];
|
||||
for (int i = 0; i < m_outerSize; i++)
|
||||
{
|
||||
m_innerNonZeros[i] = m_outerIndex[i+1] - m_outerIndex[i];
|
||||
}
|
||||
}
|
||||
|
||||
/** Suppresses all nonzeros which are \b much \b smaller \b than \a reference under the tolerence \a epsilon */
|
||||
void prune(const Scalar& reference, const RealScalar& epsilon = NumTraits<RealScalar>::dummy_precision())
|
||||
{
|
||||
|
@ -113,9 +113,10 @@ template<typename T,int Rows> struct sparse_eval<T,Rows,1> {
|
||||
|
||||
template<typename T,int Rows,int Cols> struct sparse_eval {
|
||||
typedef typename traits<T>::Scalar _Scalar;
|
||||
enum { _Flags = traits<T>::Flags };
|
||||
typedef typename traits<T>::Index _Index;
|
||||
enum { _Options = ((traits<T>::Flags&RowMajorBit)==RowMajorBit) ? RowMajor : ColMajor };
|
||||
public:
|
||||
typedef SparseMatrix<_Scalar, _Flags> type;
|
||||
typedef SparseMatrix<_Scalar, _Options, _Index> type;
|
||||
};
|
||||
|
||||
template<typename T> struct sparse_eval<T,1,1> {
|
||||
|
6
Eigen/src/SparseLU/CMakeLists.txt
Normal file
6
Eigen/src/SparseLU/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
FILE(GLOB Eigen_SparseLU_SRCS "*.h")
|
||||
|
||||
INSTALL(FILES
|
||||
${Eigen_SparseLU_SRCS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/SparseLU COMPONENT Devel
|
||||
)
|
630
Eigen/src/SparseLU/SparseLU.h
Normal file
630
Eigen/src/SparseLU/SparseLU.h
Normal file
@ -0,0 +1,630 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
#ifndef EIGEN_SPARSE_LU_H
|
||||
#define EIGEN_SPARSE_LU_H
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
|
||||
// Data structure needed by all routines
|
||||
#include "SparseLU_Structs.h"
|
||||
#include "SparseLU_Matrix.h"
|
||||
|
||||
// Base structure containing all the factorization routines
|
||||
#include "SparseLUBase.h"
|
||||
/**
|
||||
* \ingroup SparseLU_Module
|
||||
* \brief Sparse supernodal LU factorization for general matrices
|
||||
*
|
||||
* This class implements the supernodal LU factorization for general matrices.
|
||||
* It uses the main techniques from the sequential SuperLU package
|
||||
* (http://crd-legacy.lbl.gov/~xiaoye/SuperLU/). It handles transparently real
|
||||
* and complex arithmetics with single and double precision, depending on the
|
||||
* scalar type of your input matrix.
|
||||
* The code has been optimized to provide BLAS-3 operations during supernode-panel updates.
|
||||
* It benefits directly from the built-in high-performant Eigen BLAS routines.
|
||||
* Moreover, when the size of a supernode is very small, the BLAS calls are avoided to
|
||||
* enable a better optimization from the compiler. For best performance,
|
||||
* you should compile it with NDEBUG flag to avoid the numerous bounds checking on vectors.
|
||||
*
|
||||
* An important parameter of this class is the ordering method. It is used to reorder the columns
|
||||
* (and eventually the rows) of the matrix to reduce the number of new elements that are created during
|
||||
* numerical factorization. The cheapest method available is COLAMD.
|
||||
* See \link Ordering_Modules the Ordering module \endlink for the list of
|
||||
* built-in and external ordering methods.
|
||||
*
|
||||
* Simple example with key steps
|
||||
* \code
|
||||
* VectorXd x(n), b(n);
|
||||
* SparseMatrix<double, ColMajor> A;
|
||||
* SparseLU<SparseMatrix<scalar, ColMajor>, COLAMDOrdering<int> > solver;
|
||||
* // fill A and b;
|
||||
* // Compute the ordering permutation vector from the structural pattern of A
|
||||
* solver.analyzePattern(A);
|
||||
* // Compute the numerical factorization
|
||||
* solver.factorize(A);
|
||||
* //Use the factors to solve the linear system
|
||||
* x = solver.solve(b);
|
||||
* \endcode
|
||||
*
|
||||
* \WARNING The input matrix A should be in a \b compressed and \b column-major form.
|
||||
* Otherwise an expensive copy will be made. You can call the inexpensive makeCompressed() to get a compressed matrix.
|
||||
*
|
||||
* \NOTE Unlike the initial SuperLU implementation, there is no step to equilibrate the matrix.
|
||||
* For badly scaled matrices, this step can be useful to reduce the pivoting during factorization.
|
||||
* If this is the case for your matrices, you can try the basic scaling method at
|
||||
* "unsupported/Eigen/src/IterativeSolvers/Scaling.h"
|
||||
*
|
||||
* \tparam _MatrixType The type of the sparse matrix. It must be a column-major SparseMatrix<>
|
||||
* \tparam _OrderingType The ordering method to use, either AMD, COLAMD or METIS
|
||||
*
|
||||
*
|
||||
* \sa \ref TutorialSparseDirectSolvers
|
||||
* \sa \ref Ordering_Modules
|
||||
*/
|
||||
template <typename _MatrixType, typename _OrderingType>
|
||||
class SparseLU
|
||||
{
|
||||
public:
|
||||
typedef _MatrixType MatrixType;
|
||||
typedef _OrderingType OrderingType;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
typedef typename MatrixType::Index Index;
|
||||
typedef SparseMatrix<Scalar,ColMajor,Index> NCMatrix;
|
||||
typedef SuperNodalMatrix<Scalar, Index> SCMatrix;
|
||||
typedef Matrix<Scalar,Dynamic,1> ScalarVector;
|
||||
typedef Matrix<Index,Dynamic,1> IndexVector;
|
||||
typedef PermutationMatrix<Dynamic, Dynamic, Index> PermutationType;
|
||||
|
||||
public:
|
||||
SparseLU():m_isInitialized(true),m_Ustore(0,0,0,0,0,0),m_symmetricmode(false),m_diagpivotthresh(1.0)
|
||||
{
|
||||
initperfvalues();
|
||||
}
|
||||
SparseLU(const MatrixType& matrix):m_isInitialized(true),m_Ustore(0,0,0,0,0,0),m_symmetricmode(false),m_diagpivotthresh(1.0)
|
||||
{
|
||||
initperfvalues();
|
||||
compute(matrix);
|
||||
}
|
||||
|
||||
~SparseLU()
|
||||
{
|
||||
// Free all explicit dynamic pointers
|
||||
}
|
||||
|
||||
void analyzePattern (const MatrixType& matrix);
|
||||
void factorize (const MatrixType& matrix);
|
||||
void simplicialfactorize(const MatrixType& matrix);
|
||||
|
||||
/**
|
||||
* Compute the symbolic and numeric factorization of the input sparse matrix.
|
||||
* The input matrix should be in column-major storage.
|
||||
*/
|
||||
void compute (const MatrixType& matrix)
|
||||
{
|
||||
// Analyze
|
||||
analyzePattern(matrix);
|
||||
//Factorize
|
||||
factorize(matrix);
|
||||
}
|
||||
|
||||
inline Index rows() const { return m_mat.rows(); }
|
||||
inline Index cols() const { return m_mat.cols(); }
|
||||
/** Indicate that the pattern of the input matrix is symmetric */
|
||||
void isSymmetric(bool sym)
|
||||
{
|
||||
m_symmetricmode = sym;
|
||||
}
|
||||
|
||||
/** Set the threshold used for a diagonal entry to be an acceptable pivot. */
|
||||
void diagPivotThresh(RealScalar thresh)
|
||||
{
|
||||
m_diagpivotthresh = thresh;
|
||||
}
|
||||
|
||||
/** Return the number of nonzero elements in the L factor */
|
||||
int nnzL()
|
||||
{
|
||||
if (m_factorizationIsOk)
|
||||
return m_nnzL;
|
||||
else
|
||||
{
|
||||
std::cerr<<"Numerical factorization should be done before\n";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/** Return the number of nonzero elements in the U factor */
|
||||
int nnzU()
|
||||
{
|
||||
if (m_factorizationIsOk)
|
||||
return m_nnzU;
|
||||
else
|
||||
{
|
||||
std::cerr<<"Numerical factorization should be done before\n";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/** \returns the solution X of \f$ A X = B \f$ using the current decomposition of A.
|
||||
*
|
||||
* \sa compute()
|
||||
*/
|
||||
template<typename Rhs>
|
||||
inline const internal::solve_retval<SparseLU, Rhs> solve(const MatrixBase<Rhs>& B) const
|
||||
{
|
||||
eigen_assert(m_factorizationIsOk && "SparseLU is not initialized.");
|
||||
eigen_assert(rows()==B.rows()
|
||||
&& "SparseLU::solve(): invalid number of rows of the right hand side matrix B");
|
||||
return internal::solve_retval<SparseLU, Rhs>(*this, B.derived());
|
||||
}
|
||||
|
||||
|
||||
/** \brief Reports whether previous computation was successful.
|
||||
*
|
||||
* \returns \c Success if computation was succesful,
|
||||
* \c NumericalIssue if the PaStiX reports a problem
|
||||
* \c InvalidInput if the input matrix is invalid
|
||||
*
|
||||
* \sa iparm()
|
||||
*/
|
||||
ComputationInfo info() const
|
||||
{
|
||||
eigen_assert(m_isInitialized && "Decomposition is not initialized.");
|
||||
return m_info;
|
||||
}
|
||||
|
||||
template<typename Rhs, typename Dest>
|
||||
bool _solve(const MatrixBase<Rhs> &B, MatrixBase<Dest> &_X) const
|
||||
{
|
||||
Dest& X(_X.derived());
|
||||
eigen_assert(m_factorizationIsOk && "The matrix should be factorized first");
|
||||
EIGEN_STATIC_ASSERT((Dest::Flags&RowMajorBit)==0,
|
||||
THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
|
||||
|
||||
|
||||
int nrhs = B.cols();
|
||||
Index n = B.rows();
|
||||
|
||||
// Permute the right hand side to form X = Pr*B
|
||||
// on return, X is overwritten by the computed solution
|
||||
X.resize(n,nrhs);
|
||||
for(int j = 0; j < nrhs; ++j)
|
||||
X.col(j) = m_perm_r * B.col(j);
|
||||
|
||||
//Forward substitution with L
|
||||
m_Lstore.solveInPlace(X);
|
||||
|
||||
// Backward solve with U
|
||||
for (int k = m_Lstore.nsuper(); k >= 0; k--)
|
||||
{
|
||||
Index fsupc = m_Lstore.supToCol()[k];
|
||||
Index istart = m_Lstore.rowIndexPtr()[fsupc];
|
||||
Index nsupr = m_Lstore.rowIndexPtr()[fsupc+1] - istart;
|
||||
Index nsupc = m_Lstore.supToCol()[k+1] - fsupc;
|
||||
Index luptr = m_Lstore.colIndexPtr()[fsupc];
|
||||
|
||||
if (nsupc == 1)
|
||||
{
|
||||
for (int j = 0; j < nrhs; j++)
|
||||
{
|
||||
X(fsupc, j) /= m_Lstore.valuePtr()[luptr];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Map<const Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > A( &(m_Lstore.valuePtr()[luptr]), nsupc, nsupc, OuterStride<>(nsupr) );
|
||||
Map< Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > U (&(X(fsupc,0)), nsupc, nrhs, OuterStride<>(n) );
|
||||
U = A.template triangularView<Upper>().solve(U);
|
||||
}
|
||||
|
||||
for (int j = 0; j < nrhs; ++j)
|
||||
{
|
||||
for (int jcol = fsupc; jcol < fsupc + nsupc; jcol++)
|
||||
{
|
||||
typename MappedSparseMatrix<Scalar>::InnerIterator it(m_Ustore, jcol);
|
||||
for ( ; it; ++it)
|
||||
{
|
||||
Index irow = it.index();
|
||||
X(irow, j) -= X(jcol, j) * it.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
} // End For U-solve
|
||||
|
||||
// Permute back the solution
|
||||
for (int j = 0; j < nrhs; ++j)
|
||||
X.col(j) = m_perm_c.inverse() * X.col(j);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Functions
|
||||
void initperfvalues()
|
||||
{
|
||||
m_perfv.panel_size = 12;
|
||||
m_perfv.relax = 1;
|
||||
m_perfv.maxsuper = 100;
|
||||
m_perfv.rowblk = 200;
|
||||
m_perfv.colblk = 60;
|
||||
m_perfv.fillfactor = 20;
|
||||
}
|
||||
|
||||
// Variables
|
||||
mutable ComputationInfo m_info;
|
||||
bool m_isInitialized;
|
||||
bool m_factorizationIsOk;
|
||||
bool m_analysisIsOk;
|
||||
NCMatrix m_mat; // The input (permuted ) matrix
|
||||
SCMatrix m_Lstore; // The lower triangular matrix (supernodal)
|
||||
MappedSparseMatrix<Scalar> m_Ustore; // The upper triangular matrix
|
||||
PermutationType m_perm_c; // Column permutation
|
||||
PermutationType m_perm_r ; // Row permutation
|
||||
IndexVector m_etree; // Column elimination tree
|
||||
|
||||
LU_GlobalLU_t<IndexVector, ScalarVector> m_glu;
|
||||
|
||||
// SuperLU/SparseLU options
|
||||
bool m_symmetricmode;
|
||||
|
||||
// values for performance
|
||||
LU_perfvalues m_perfv;
|
||||
RealScalar m_diagpivotthresh; // Specifies the threshold used for a diagonal entry to be an acceptable pivot
|
||||
int m_nnzL, m_nnzU; // Nonzeros in L and U factors
|
||||
|
||||
private:
|
||||
// Copy constructor
|
||||
SparseLU (SparseLU& ) {}
|
||||
|
||||
}; // End class SparseLU
|
||||
|
||||
|
||||
// Functions needed by the anaysis phase
|
||||
/**
|
||||
* Compute the column permutation to minimize the fill-in
|
||||
*
|
||||
* - Apply this permutation to the input matrix -
|
||||
*
|
||||
* - Compute the column elimination tree on the permuted matrix
|
||||
*
|
||||
* - Postorder the elimination tree and the column permutation
|
||||
*
|
||||
*/
|
||||
template <typename MatrixType, typename OrderingType>
|
||||
void SparseLU<MatrixType, OrderingType>::analyzePattern(const MatrixType& mat)
|
||||
{
|
||||
|
||||
//TODO It is possible as in SuperLU to compute row and columns scaling vectors to equilibrate the matrix mat.
|
||||
|
||||
OrderingType ord;
|
||||
ord(mat,m_perm_c);
|
||||
|
||||
// Apply the permutation to the column of the input matrix
|
||||
// m_mat = mat * m_perm_c.inverse(); //FIXME It should be less expensive here to permute only the structural pattern of the matrix
|
||||
|
||||
//First copy the whole input matrix.
|
||||
m_mat = mat;
|
||||
m_mat.uncompress(); //NOTE: The effect of this command is only to create the InnerNonzeros pointers. FIXME : This vector is filled but not subsequently used.
|
||||
//Then, permute only the column pointers
|
||||
for (int i = 0; i < mat.cols(); i++)
|
||||
{
|
||||
m_mat.outerIndexPtr()[m_perm_c.indices()(i)] = mat.outerIndexPtr()[i];
|
||||
m_mat.innerNonZeroPtr()[m_perm_c.indices()(i)] = mat.outerIndexPtr()[i+1] - mat.outerIndexPtr()[i];
|
||||
}
|
||||
|
||||
// Compute the column elimination tree of the permuted matrix
|
||||
/*if (m_etree.size() == 0) */m_etree.resize(m_mat.cols());
|
||||
|
||||
SparseLUBase<Scalar,Index>::LU_sp_coletree(m_mat, m_etree);
|
||||
|
||||
// In symmetric mode, do not do postorder here
|
||||
if (!m_symmetricmode) {
|
||||
IndexVector post, iwork;
|
||||
// Post order etree
|
||||
SparseLUBase<Scalar,Index>::LU_TreePostorder(m_mat.cols(), m_etree, post);
|
||||
|
||||
|
||||
// Renumber etree in postorder
|
||||
int m = m_mat.cols();
|
||||
iwork.resize(m+1);
|
||||
for (int i = 0; i < m; ++i) iwork(post(i)) = post(m_etree(i));
|
||||
m_etree = iwork;
|
||||
|
||||
// Postmultiply A*Pc by post, i.e reorder the matrix according to the postorder of the etree
|
||||
PermutationType post_perm(m); //FIXME Use directly a constructor with post
|
||||
for (int i = 0; i < m; i++)
|
||||
post_perm.indices()(i) = post(i);
|
||||
|
||||
// Combine the two permutations : postorder the permutation for future use
|
||||
m_perm_c = post_perm * m_perm_c;
|
||||
|
||||
} // end postordering
|
||||
|
||||
m_analysisIsOk = true;
|
||||
}
|
||||
|
||||
// Functions needed by the numerical factorization phase
|
||||
|
||||
|
||||
/**
|
||||
* - Numerical factorization
|
||||
* - Interleaved with the symbolic factorization
|
||||
* On exit, info is
|
||||
*
|
||||
* = 0: successful factorization
|
||||
*
|
||||
* > 0: if info = i, and i is
|
||||
*
|
||||
* <= A->ncol: U(i,i) is exactly zero. The factorization has
|
||||
* been completed, but the factor U is exactly singular,
|
||||
* and division by zero will occur if it is used to solve a
|
||||
* system of equations.
|
||||
*
|
||||
* > A->ncol: number of bytes allocated when memory allocation
|
||||
* failure occurred, plus A->ncol. If lwork = -1, it is
|
||||
* the estimated amount of space needed, plus A->ncol.
|
||||
*/
|
||||
template <typename MatrixType, typename OrderingType>
|
||||
void SparseLU<MatrixType, OrderingType>::factorize(const MatrixType& matrix)
|
||||
{
|
||||
|
||||
eigen_assert(m_analysisIsOk && "analyzePattern() should be called first");
|
||||
eigen_assert((matrix.rows() == matrix.cols()) && "Only for squared matrices");
|
||||
|
||||
typedef typename IndexVector::Scalar Index;
|
||||
|
||||
|
||||
// Apply the column permutation computed in analyzepattern()
|
||||
// m_mat = matrix * m_perm_c.inverse();
|
||||
m_mat = matrix;
|
||||
m_mat.uncompress(); //NOTE: The effect of this command is only to create the InnerNonzeros pointers.
|
||||
//Then, permute only the column pointers
|
||||
for (int i = 0; i < matrix.cols(); i++)
|
||||
{
|
||||
m_mat.outerIndexPtr()[m_perm_c.indices()(i)] = matrix.outerIndexPtr()[i];
|
||||
m_mat.innerNonZeroPtr()[m_perm_c.indices()(i)] = matrix.outerIndexPtr()[i+1] - matrix.outerIndexPtr()[i];
|
||||
}
|
||||
|
||||
int m = m_mat.rows();
|
||||
int n = m_mat.cols();
|
||||
int nnz = m_mat.nonZeros();
|
||||
int maxpanel = m_perfv.panel_size * m;
|
||||
// Allocate working storage common to the factor routines
|
||||
int lwork = 0;
|
||||
int info = SparseLUBase<Scalar,Index>::LUMemInit(m, n, nnz, lwork, m_perfv.fillfactor, m_perfv.panel_size, m_glu);
|
||||
if (info)
|
||||
{
|
||||
std::cerr << "UNABLE TO ALLOCATE WORKING MEMORY\n\n" ;
|
||||
m_factorizationIsOk = false;
|
||||
return ;
|
||||
}
|
||||
|
||||
// Set up pointers for integer working arrays
|
||||
IndexVector segrep(m); segrep.setZero();
|
||||
IndexVector parent(m); parent.setZero();
|
||||
IndexVector xplore(m); xplore.setZero();
|
||||
IndexVector repfnz(maxpanel);
|
||||
IndexVector panel_lsub(maxpanel);
|
||||
IndexVector xprune(n); xprune.setZero();
|
||||
IndexVector marker(m*LU_NO_MARKER); marker.setZero();
|
||||
|
||||
repfnz.setConstant(-1);
|
||||
panel_lsub.setConstant(-1);
|
||||
|
||||
// Set up pointers for scalar working arrays
|
||||
ScalarVector dense;
|
||||
dense.setZero(maxpanel);
|
||||
ScalarVector tempv;
|
||||
tempv.setZero(LU_NUM_TEMPV(m, m_perfv.panel_size, m_perfv.maxsuper, m_perfv.rowblk) );
|
||||
|
||||
// Compute the inverse of perm_c
|
||||
PermutationType iperm_c(m_perm_c.inverse());
|
||||
|
||||
// Identify initial relaxed snodes
|
||||
IndexVector relax_end(n);
|
||||
if ( m_symmetricmode == true )
|
||||
SparseLUBase<Scalar,Index>::LU_heap_relax_snode(n, m_etree, m_perfv.relax, marker, relax_end);
|
||||
else
|
||||
SparseLUBase<Scalar,Index>::LU_relax_snode(n, m_etree, m_perfv.relax, marker, relax_end);
|
||||
|
||||
|
||||
m_perm_r.resize(m);
|
||||
m_perm_r.indices().setConstant(-1);
|
||||
marker.setConstant(-1);
|
||||
|
||||
m_glu.supno(0) = IND_EMPTY; m_glu.xsup.setConstant(0);
|
||||
m_glu.xsup(0) = m_glu.xlsub(0) = m_glu.xusub(0) = m_glu.xlusup(0) = Index(0);
|
||||
|
||||
// Work on one 'panel' at a time. A panel is one of the following :
|
||||
// (a) a relaxed supernode at the bottom of the etree, or
|
||||
// (b) panel_size contiguous columns, <panel_size> defined by the user
|
||||
int jcol,kcol;
|
||||
IndexVector panel_histo(n);
|
||||
Index nextu, nextlu, jsupno, fsupc, new_next;
|
||||
Index pivrow; // Pivotal row number in the original row matrix
|
||||
int nseg1; // Number of segments in U-column above panel row jcol
|
||||
int nseg; // Number of segments in each U-column
|
||||
int irep, icol;
|
||||
int i, k, jj;
|
||||
for (jcol = 0; jcol < n; )
|
||||
{
|
||||
if (relax_end(jcol) != IND_EMPTY)
|
||||
{ // Starting a relaxed node from jcol
|
||||
kcol = relax_end(jcol); // End index of the relaxed snode
|
||||
|
||||
// Factorize the relaxed supernode(jcol:kcol)
|
||||
// First, determine the union of the row structure of the snode
|
||||
info = SparseLUBase<Scalar,Index>::LU_snode_dfs(jcol, kcol, m_mat, xprune, marker, m_glu);
|
||||
if ( info )
|
||||
{
|
||||
std::cerr << "MEMORY ALLOCATION FAILED IN SNODE_DFS() \n";
|
||||
m_info = NumericalIssue;
|
||||
m_factorizationIsOk = false;
|
||||
return;
|
||||
}
|
||||
nextu = m_glu.xusub(jcol); //starting location of column jcol in ucol
|
||||
nextlu = m_glu.xlusup(jcol); //Starting location of column jcol in lusup (rectangular supernodes)
|
||||
jsupno = m_glu.supno(jcol); // Supernode number which column jcol belongs to
|
||||
fsupc = m_glu.xsup(jsupno); //First column number of the current supernode
|
||||
new_next = nextlu + (m_glu.xlsub(fsupc+1)-m_glu.xlsub(fsupc)) * (kcol - jcol + 1);
|
||||
int mem;
|
||||
while (new_next > m_glu.nzlumax )
|
||||
{
|
||||
mem = SparseLUBase<Scalar,Index>::LUMemXpand(m_glu.lusup, m_glu.nzlumax, nextlu, LUSUP, m_glu.num_expansions);
|
||||
if (mem)
|
||||
{
|
||||
std::cerr << "MEMORY ALLOCATION FAILED FOR L FACTOR \n";
|
||||
m_factorizationIsOk = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Now, left-looking factorize each column within the snode
|
||||
for (icol = jcol; icol<=kcol; icol++){
|
||||
m_glu.xusub(icol+1) = nextu;
|
||||
// Scatter into SPA dense(*)
|
||||
for (typename MatrixType::InnerIterator it(m_mat, icol); it; ++it)
|
||||
dense(it.row()) = it.value();
|
||||
|
||||
// Numeric update within the snode
|
||||
SparseLUBase<Scalar,Index>::LU_snode_bmod(icol, fsupc, dense, m_glu);
|
||||
|
||||
// Eliminate the current column
|
||||
info = SparseLUBase<Scalar,Index>::LU_pivotL(icol, m_diagpivotthresh, m_perm_r.indices(), iperm_c.indices(), pivrow, m_glu);
|
||||
if ( info )
|
||||
{
|
||||
m_info = NumericalIssue;
|
||||
std::cerr<< "THE MATRIX IS STRUCTURALLY SINGULAR ... ZERO COLUMN AT " << info <<std::endl;
|
||||
m_factorizationIsOk = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
jcol = icol; // The last column te be eliminated
|
||||
}
|
||||
else
|
||||
{ // Work on one panel of panel_size columns
|
||||
|
||||
// Adjust panel size so that a panel won't overlap with the next relaxed snode.
|
||||
int panel_size = m_perfv.panel_size; // upper bound on panel width
|
||||
for (k = jcol + 1; k < (std::min)(jcol+panel_size, n); k++)
|
||||
{
|
||||
if (relax_end(k) != IND_EMPTY)
|
||||
{
|
||||
panel_size = k - jcol;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (k == n)
|
||||
panel_size = n - jcol;
|
||||
|
||||
// Symbolic outer factorization on a panel of columns
|
||||
SparseLUBase<Scalar,Index>::LU_panel_dfs(m, panel_size, jcol, m_mat, m_perm_r.indices(), nseg1, dense, panel_lsub, segrep, repfnz, xprune, marker, parent, xplore, m_glu);
|
||||
|
||||
// Numeric sup-panel updates in topological order
|
||||
SparseLUBase<Scalar,Index>::LU_panel_bmod(m, panel_size, jcol, nseg1, dense, tempv, segrep, repfnz, m_perfv, m_glu);
|
||||
|
||||
// Sparse LU within the panel, and below the panel diagonal
|
||||
for ( jj = jcol; jj< jcol + panel_size; jj++)
|
||||
{
|
||||
k = (jj - jcol) * m; // Column index for w-wide arrays
|
||||
|
||||
nseg = nseg1; // begin after all the panel segments
|
||||
//Depth-first-search for the current column
|
||||
VectorBlock<IndexVector> panel_lsubk(panel_lsub, k, m);
|
||||
VectorBlock<IndexVector> repfnz_k(repfnz, k, m);
|
||||
info = SparseLUBase<Scalar,Index>::LU_column_dfs(m, jj, m_perm_r.indices(), m_perfv.maxsuper, nseg, panel_lsubk, segrep, repfnz_k, xprune, marker, parent, xplore, m_glu);
|
||||
if ( info )
|
||||
{
|
||||
std::cerr << "UNABLE TO EXPAND MEMORY IN COLUMN_DFS() \n";
|
||||
m_info = NumericalIssue;
|
||||
m_factorizationIsOk = false;
|
||||
return;
|
||||
}
|
||||
// Numeric updates to this column
|
||||
VectorBlock<ScalarVector> dense_k(dense, k, m);
|
||||
VectorBlock<IndexVector> segrep_k(segrep, nseg1, m-nseg1);
|
||||
info = SparseLUBase<Scalar,Index>::LU_column_bmod(jj, (nseg - nseg1), dense_k, tempv, segrep_k, repfnz_k, jcol, m_glu);
|
||||
if ( info )
|
||||
{
|
||||
std::cerr << "UNABLE TO EXPAND MEMORY IN COLUMN_BMOD() \n";
|
||||
m_info = NumericalIssue;
|
||||
m_factorizationIsOk = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy the U-segments to ucol(*)
|
||||
info = SparseLUBase<Scalar,Index>::LU_copy_to_ucol(jj, nseg, segrep, repfnz_k ,m_perm_r.indices(), dense_k, m_glu);
|
||||
if ( info )
|
||||
{
|
||||
std::cerr << "UNABLE TO EXPAND MEMORY IN COPY_TO_UCOL() \n";
|
||||
m_info = NumericalIssue;
|
||||
m_factorizationIsOk = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Form the L-segment
|
||||
info = SparseLUBase<Scalar,Index>::LU_pivotL(jj, m_diagpivotthresh, m_perm_r.indices(), iperm_c.indices(), pivrow, m_glu);
|
||||
if ( info )
|
||||
{
|
||||
std::cerr<< "THE MATRIX IS STRUCTURALLY SINGULAR ... ZERO COLUMN AT " << info <<std::endl;
|
||||
m_info = NumericalIssue;
|
||||
m_factorizationIsOk = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Prune columns (0:jj-1) using column jj
|
||||
SparseLUBase<Scalar,Index>::LU_pruneL(jj, m_perm_r.indices(), pivrow, nseg, segrep, repfnz_k, xprune, m_glu);
|
||||
|
||||
// Reset repfnz for this column
|
||||
for (i = 0; i < nseg; i++)
|
||||
{
|
||||
irep = segrep(i);
|
||||
repfnz_k(irep) = IND_EMPTY;
|
||||
}
|
||||
} // end SparseLU within the panel
|
||||
jcol += panel_size; // Move to the next panel
|
||||
} // end else
|
||||
} // end for -- end elimination
|
||||
|
||||
// Count the number of nonzeros in factors
|
||||
SparseLUBase<Scalar,Index>::LU_countnz(n, m_nnzL, m_nnzU, m_glu);
|
||||
// Apply permutation to the L subscripts
|
||||
SparseLUBase<Scalar,Index>::LU_fixupL(n, m_perm_r.indices(), m_glu);
|
||||
|
||||
// Create supernode matrix L
|
||||
m_Lstore.setInfos(m, n, m_glu.lusup, m_glu.xlusup, m_glu.lsub, m_glu.xlsub, m_glu.supno, m_glu.xsup);
|
||||
// Create the column major upper sparse matrix U;
|
||||
new (&m_Ustore) MappedSparseMatrix<Scalar> ( m, n, m_nnzU, m_glu.xusub.data(), m_glu.usub.data(), m_glu.ucol.data() );
|
||||
|
||||
m_info = Success;
|
||||
m_factorizationIsOk = true;
|
||||
}
|
||||
|
||||
// #include "SparseLU_simplicialfactorize.h"
|
||||
namespace internal {
|
||||
|
||||
template<typename _MatrixType, typename Derived, typename Rhs>
|
||||
struct solve_retval<SparseLU<_MatrixType,Derived>, Rhs>
|
||||
: solve_retval_base<SparseLU<_MatrixType,Derived>, Rhs>
|
||||
{
|
||||
typedef SparseLU<_MatrixType,Derived> Dec;
|
||||
EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
|
||||
|
||||
template<typename Dest> void evalTo(Dest& dst) const
|
||||
{
|
||||
dec()._solve(rhs(),dst);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // End namespace Eigen
|
||||
#endif
|
74
Eigen/src/SparseLU/SparseLUBase.h
Normal file
74
Eigen/src/SparseLU/SparseLUBase.h
Normal file
@ -0,0 +1,74 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef SPARSELUBASE_H
|
||||
#define SPARSELUBASE_H
|
||||
/**
|
||||
* Base class for sparseLU
|
||||
*/
|
||||
template <typename Scalar, typename Index>
|
||||
struct SparseLUBase
|
||||
{
|
||||
typedef Matrix<Scalar,Dynamic,1> ScalarVector;
|
||||
typedef Matrix<Index,Dynamic,1> IndexVector;
|
||||
typedef typename ScalarVector::RealScalar RealScalar;
|
||||
typedef VectorBlock<Matrix<Scalar,Dynamic,1> > BlockScalarVector;
|
||||
typedef VectorBlock<Matrix<Index,Dynamic,1> > BlockIndexVector;
|
||||
// typedef Ref<Matrix<Scalar,Dynamic,1> > BlockScalarVector;
|
||||
// typedef Ref<Matrix<Index,Dynamic,1> > BlockIndexVector;
|
||||
typedef LU_GlobalLU_t<IndexVector, ScalarVector> GlobalLU_t;
|
||||
typedef SparseMatrix<Scalar,ColMajor,Index> MatrixType;
|
||||
|
||||
static int etree_find (int i, IndexVector& pp);
|
||||
static int LU_sp_coletree(const MatrixType& mat, IndexVector& parent);
|
||||
static void LU_nr_etdfs (int n, IndexVector& parent, IndexVector& first_kid, IndexVector& next_kid, IndexVector& post, int postnum);
|
||||
static void LU_TreePostorder(int n, IndexVector& parent, IndexVector& post);
|
||||
template <typename VectorType>
|
||||
static int expand(VectorType& vec, int& length, int nbElts, int keep_prev, int& num_expansions);
|
||||
static int LUMemInit(int m, int n, int annz, int lwork, int fillratio, int panel_size, GlobalLU_t& glu);
|
||||
template <typename VectorType>
|
||||
static int LUMemXpand(VectorType& vec, int& maxlen, int nbElts, LU_MemType memtype, int& num_expansions);
|
||||
static void LU_heap_relax_snode (const int n, IndexVector& et, const int relax_columns, IndexVector& descendants, IndexVector& relax_end);
|
||||
static void LU_relax_snode (const int n, IndexVector& et, const int relax_columns, IndexVector& descendants, IndexVector& relax_end);
|
||||
static int LU_snode_dfs(const int jcol, const int kcol,const MatrixType& mat, IndexVector& xprune, IndexVector& marker, LU_GlobalLU_t<IndexVector, ScalarVector>& glu);
|
||||
static int LU_snode_bmod (const int jcol, const int fsupc, ScalarVector& dense, GlobalLU_t& glu);
|
||||
static int LU_pivotL(const int jcol, const RealScalar diagpivotthresh, IndexVector& perm_r, IndexVector& iperm_c, int& pivrow, GlobalLU_t& glu);
|
||||
template <typename Traits>
|
||||
static void LU_dfs_kernel(const int jj, IndexVector& perm_r,
|
||||
int& nseg, IndexVector& panel_lsub, IndexVector& segrep,
|
||||
Ref<IndexVector> repfnz_col, IndexVector& xprune, Ref<IndexVector> marker, IndexVector& parent,
|
||||
IndexVector& xplore, GlobalLU_t& glu, int& nextl_col, int krow, Traits& traits);
|
||||
static void LU_panel_dfs(const int m, const int w, const int jcol, MatrixType& A, IndexVector& perm_r, int& nseg, ScalarVector& dense, IndexVector& panel_lsub, IndexVector& segrep, IndexVector& repfnz, IndexVector& xprune, IndexVector& marker, IndexVector& parent, IndexVector& xplore, GlobalLU_t& glu);
|
||||
|
||||
static void LU_panel_bmod(const int m, const int w, const int jcol, const int nseg, ScalarVector& dense, ScalarVector& tempv, IndexVector& segrep, IndexVector& repfnz, LU_perfvalues& perfv, GlobalLU_t& glu);
|
||||
static int LU_column_dfs(const int m, const int jcol, IndexVector& perm_r, int maxsuper, int& nseg, BlockIndexVector& lsub_col, IndexVector& segrep, BlockIndexVector& repfnz, IndexVector& xprune, IndexVector& marker, IndexVector& parent, IndexVector& xplore, GlobalLU_t& glu);
|
||||
static int LU_column_bmod(const int jcol, const int nseg, BlockScalarVector& dense, ScalarVector& tempv, BlockIndexVector& segrep, BlockIndexVector& repfnz, int fpanelc, GlobalLU_t& glu);
|
||||
static int LU_copy_to_ucol(const int jcol, const int nseg, IndexVector& segrep, BlockIndexVector& repfnz ,IndexVector& perm_r, BlockScalarVector& dense, GlobalLU_t& glu);
|
||||
static void LU_pruneL(const int jcol, const IndexVector& perm_r, const int pivrow, const int nseg, const IndexVector& segrep, BlockIndexVector& repfnz, IndexVector& xprune, GlobalLU_t& glu);
|
||||
static void LU_countnz(const int n, int& nnzL, int& nnzU, GlobalLU_t& glu);
|
||||
static void LU_fixupL(const int n, const IndexVector& perm_r, GlobalLU_t& glu);
|
||||
|
||||
};
|
||||
|
||||
#include "SparseLU_Coletree.h"
|
||||
#include "SparseLU_Memory.h"
|
||||
#include "SparseLU_heap_relax_snode.h"
|
||||
#include "SparseLU_relax_snode.h"
|
||||
#include "SparseLU_snode_dfs.h"
|
||||
#include "SparseLU_snode_bmod.h"
|
||||
#include "SparseLU_pivotL.h"
|
||||
#include "SparseLU_panel_dfs.h"
|
||||
#include "SparseLU_kernel_bmod.h"
|
||||
#include "SparseLU_panel_bmod.h"
|
||||
#include "SparseLU_column_dfs.h"
|
||||
#include "SparseLU_column_bmod.h"
|
||||
#include "SparseLU_copy_to_ucol.h"
|
||||
#include "SparseLU_pruneL.h"
|
||||
#include "SparseLU_Utils.h"
|
||||
|
||||
#endif
|
180
Eigen/src/SparseLU/SparseLU_Coletree.h
Normal file
180
Eigen/src/SparseLU/SparseLU_Coletree.h
Normal file
@ -0,0 +1,180 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
/*
|
||||
|
||||
* NOTE: This file is the modified version of sp_coletree.c file in SuperLU
|
||||
|
||||
* -- SuperLU routine (version 3.1) --
|
||||
* Univ. of California Berkeley, Xerox Palo Alto Research Center,
|
||||
* and Lawrence Berkeley National Lab.
|
||||
* August 1, 2008
|
||||
*
|
||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
|
||||
* EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program for any
|
||||
* purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is
|
||||
* granted, provided the above notices are retained, and a notice that
|
||||
* the code was modified is included with the above copyright notice.
|
||||
*/
|
||||
#ifndef SPARSELU_COLETREE_H
|
||||
#define SPARSELU_COLETREE_H
|
||||
/** Find the root of the tree/set containing the vertex i : Use Path halving */
|
||||
template< typename Scalar,typename Index>
|
||||
int SparseLUBase<Scalar,Index>::etree_find (int i, IndexVector& pp)
|
||||
{
|
||||
int p = pp(i); // Parent
|
||||
int gp = pp(p); // Grand parent
|
||||
while (gp != p)
|
||||
{
|
||||
pp(i) = gp; // Parent pointer on find path is changed to former grand parent
|
||||
i = gp;
|
||||
p = pp(i);
|
||||
gp = pp(p);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/** Compute the column elimination tree of a sparse matrix
|
||||
* NOTE : The matrix is supposed to be in column-major format.
|
||||
*
|
||||
*/
|
||||
template <typename Scalar, typename Index>
|
||||
int SparseLUBase<Scalar,Index>::LU_sp_coletree(const MatrixType& mat, IndexVector& parent)
|
||||
{
|
||||
int nc = mat.cols(); // Number of columns
|
||||
int nr = mat.rows(); // Number of rows
|
||||
|
||||
IndexVector root(nc); // root of subtree of etree
|
||||
root.setZero();
|
||||
IndexVector pp(nc); // disjoint sets
|
||||
pp.setZero(); // Initialize disjoint sets
|
||||
IndexVector firstcol(nr); // First nonzero column in each row
|
||||
|
||||
//Compute first nonzero column in each row
|
||||
int row,col;
|
||||
firstcol.setConstant(nc); //for (row = 0; row < nr; firstcol(row++) = nc);
|
||||
for (col = 0; col < nc; col++)
|
||||
{
|
||||
for (typename MatrixType::InnerIterator it(mat, col); it; ++it)
|
||||
{ // Is it necessary to browse the whole matrix, the lower part should do the job ??
|
||||
row = it.row();
|
||||
firstcol(row) = (std::min)(firstcol(row), col);
|
||||
}
|
||||
}
|
||||
/* Compute etree by Liu's algorithm for symmetric matrices,
|
||||
except use (firstcol[r],c) in place of an edge (r,c) of A.
|
||||
Thus each row clique in A'*A is replaced by a star
|
||||
centered at its first vertex, which has the same fill. */
|
||||
int rset, cset, rroot;
|
||||
for (col = 0; col < nc; col++)
|
||||
{
|
||||
pp(col) = col;
|
||||
cset = col;
|
||||
root(cset) = col;
|
||||
parent(col) = nc;
|
||||
for (typename MatrixType::InnerIterator it(mat, col); it; ++it)
|
||||
{ // A sequence of interleaved find and union is performed
|
||||
row = firstcol(it.row());
|
||||
if (row >= col) continue;
|
||||
rset = etree_find(row, pp); // Find the name of the set containing row
|
||||
rroot = root(rset);
|
||||
if (rroot != col)
|
||||
{
|
||||
parent(rroot) = col;
|
||||
pp(cset) = rset;
|
||||
cset = rset;
|
||||
root(cset) = col;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Depth-first search from vertex n. No recursion.
|
||||
* This routine was contributed by Cédric Doucet, CEDRAT Group, Meylan, France.
|
||||
*/
|
||||
template <typename Scalar, typename Index>
|
||||
void SparseLUBase<Scalar,Index>::LU_nr_etdfs (int n, IndexVector& parent, IndexVector& first_kid, IndexVector& next_kid, IndexVector& post, int postnum)
|
||||
{
|
||||
int current = n, first, next;
|
||||
while (postnum != n)
|
||||
{
|
||||
// No kid for the current node
|
||||
first = first_kid(current);
|
||||
|
||||
// no kid for the current node
|
||||
if (first == -1)
|
||||
{
|
||||
// Numbering this node because it has no kid
|
||||
post(current) = postnum++;
|
||||
|
||||
// looking for the next kid
|
||||
next = next_kid(current);
|
||||
while (next == -1)
|
||||
{
|
||||
// No more kids : back to the parent node
|
||||
current = parent(current);
|
||||
// numbering the parent node
|
||||
post(current) = postnum++;
|
||||
|
||||
// Get the next kid
|
||||
next = next_kid(current);
|
||||
}
|
||||
// stopping criterion
|
||||
if (postnum == n+1) return;
|
||||
|
||||
// Updating current node
|
||||
current = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
current = first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Post order a tree
|
||||
* \param parent Input tree
|
||||
* \param post postordered tree
|
||||
*/
|
||||
template <typename Scalar, typename Index>
|
||||
void SparseLUBase<Scalar,Index>::LU_TreePostorder(int n, IndexVector& parent, IndexVector& post)
|
||||
{
|
||||
IndexVector first_kid, next_kid; // Linked list of children
|
||||
int postnum;
|
||||
// Allocate storage for working arrays and results
|
||||
first_kid.resize(n+1);
|
||||
next_kid.setZero(n+1);
|
||||
post.setZero(n+1);
|
||||
|
||||
// Set up structure describing children
|
||||
int v, dad;
|
||||
first_kid.setConstant(-1);
|
||||
for (v = n-1; v >= 0; v--)
|
||||
{
|
||||
dad = parent(v);
|
||||
next_kid(v) = first_kid(dad);
|
||||
first_kid(dad) = v;
|
||||
}
|
||||
|
||||
// Depth-first search from dummy root vertex #n
|
||||
postnum = 0;
|
||||
LU_nr_etdfs(n, parent, first_kid, next_kid, post, postnum);
|
||||
}
|
||||
|
||||
#endif
|
313
Eigen/src/SparseLU/SparseLU_Matrix.h
Normal file
313
Eigen/src/SparseLU/SparseLU_Matrix.h
Normal file
@ -0,0 +1,313 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
// Copyright (C) 2012 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_SPARSELU_MATRIX_H
|
||||
#define EIGEN_SPARSELU_MATRIX_H
|
||||
|
||||
/** \ingroup SparseLU_Module
|
||||
* \brief a class to manipulate the L supernodal factor from the SparseLU factorization
|
||||
*
|
||||
* This class contain the data to easily store
|
||||
* and manipulate the supernodes during the factorization and solution phase of Sparse LU.
|
||||
* Only the lower triangular matrix has supernodes.
|
||||
*
|
||||
* NOTE : This class corresponds to the SCformat structure in SuperLU
|
||||
*
|
||||
*/
|
||||
/* TO DO
|
||||
* InnerIterator as for sparsematrix
|
||||
* SuperInnerIterator to iterate through all supernodes
|
||||
* Function for triangular solve
|
||||
*/
|
||||
template <typename _Scalar, typename _Index>
|
||||
class SuperNodalMatrix
|
||||
{
|
||||
public:
|
||||
typedef _Scalar Scalar;
|
||||
typedef _Index Index;
|
||||
typedef Matrix<Index,Dynamic,1> IndexVector;
|
||||
typedef Matrix<Scalar,Dynamic,1> ScalarVector;
|
||||
public:
|
||||
SuperNodalMatrix()
|
||||
{
|
||||
|
||||
}
|
||||
SuperNodalMatrix(int m, int n, ScalarVector& nzval, IndexVector& nzval_colptr, IndexVector& rowind,
|
||||
IndexVector& rowind_colptr, IndexVector& col_to_sup, IndexVector& sup_to_col )
|
||||
{
|
||||
setInfos(m, n, nzval, nzval_colptr, rowind, rowind_colptr, col_to_sup, sup_to_col);
|
||||
}
|
||||
|
||||
~SuperNodalMatrix()
|
||||
{
|
||||
|
||||
}
|
||||
/**
|
||||
* Set appropriate pointers for the lower triangular supernodal matrix
|
||||
* These infos are available at the end of the numerical factorization
|
||||
* FIXME This class will be modified such that it can be use in the course
|
||||
* of the factorization.
|
||||
*/
|
||||
void setInfos(int m, int n, ScalarVector& nzval, IndexVector& nzval_colptr, IndexVector& rowind,
|
||||
IndexVector& rowind_colptr, IndexVector& col_to_sup, IndexVector& sup_to_col )
|
||||
{
|
||||
m_row = m;
|
||||
m_col = n;
|
||||
m_nzval = nzval.data();
|
||||
m_nzval_colptr = nzval_colptr.data();
|
||||
m_rowind = rowind.data();
|
||||
m_rowind_colptr = rowind_colptr.data();
|
||||
m_nsuper = col_to_sup(n);
|
||||
m_col_to_sup = col_to_sup.data();
|
||||
m_sup_to_col = sup_to_col.data();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of rows
|
||||
*/
|
||||
int rows()
|
||||
{
|
||||
return m_row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of columns
|
||||
*/
|
||||
int cols()
|
||||
{
|
||||
return m_col;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the array of nonzero values packed by column
|
||||
*
|
||||
* The size is nnz
|
||||
*/
|
||||
Scalar* valuePtr()
|
||||
{
|
||||
return m_nzval;
|
||||
}
|
||||
|
||||
const Scalar* valuePtr() const
|
||||
{
|
||||
return m_nzval;
|
||||
}
|
||||
/**
|
||||
* Return the pointers to the beginning of each column in \ref valuePtr()
|
||||
*/
|
||||
Index* colIndexPtr()
|
||||
{
|
||||
return m_nzval_colptr;
|
||||
}
|
||||
|
||||
const Index* colIndexPtr() const
|
||||
{
|
||||
return m_nzval_colptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the array of compressed row indices of all supernodes
|
||||
*/
|
||||
Index* rowIndex()
|
||||
{
|
||||
return m_rowind;
|
||||
}
|
||||
|
||||
const Index* rowIndex() const
|
||||
{
|
||||
return m_rowind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location in \em rowvaluePtr() which starts each column
|
||||
*/
|
||||
Index* rowIndexPtr()
|
||||
{
|
||||
return m_rowind_colptr;
|
||||
}
|
||||
|
||||
const Index* rowIndexPtr() const
|
||||
{
|
||||
return m_rowind_colptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the array of column-to-supernode mapping
|
||||
*/
|
||||
Index* colToSup()
|
||||
{
|
||||
return m_col_to_sup;
|
||||
}
|
||||
|
||||
const Index* colToSup() const
|
||||
{
|
||||
return m_col_to_sup;
|
||||
}
|
||||
/**
|
||||
* Return the array of supernode-to-column mapping
|
||||
*/
|
||||
Index* supToCol()
|
||||
{
|
||||
return m_sup_to_col;
|
||||
}
|
||||
|
||||
const Index* supToCol() const
|
||||
{
|
||||
return m_sup_to_col;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of supernodes
|
||||
*/
|
||||
int nsuper() const
|
||||
{
|
||||
return m_nsuper;
|
||||
}
|
||||
|
||||
class InnerIterator;
|
||||
template<typename Dest>
|
||||
void solveInPlace( MatrixBase<Dest>&X) const;
|
||||
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
Index m_row; // Number of rows
|
||||
Index m_col; // Number of columns
|
||||
Index m_nsuper; // Number of supernodes
|
||||
Scalar* m_nzval; //array of nonzero values packed by column
|
||||
Index* m_nzval_colptr; //nzval_colptr[j] Stores the location in nzval[] which starts column j
|
||||
Index* m_rowind; // Array of compressed row indices of rectangular supernodes
|
||||
Index* m_rowind_colptr; //rowind_colptr[j] stores the location in rowind[] which starts column j
|
||||
Index* m_col_to_sup; // col_to_sup[j] is the supernode number to which column j belongs
|
||||
Index* m_sup_to_col; //sup_to_col[s] points to the starting column of the s-th supernode
|
||||
|
||||
private :
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief InnerIterator class to iterate over nonzero values of the current column in the supernode
|
||||
*
|
||||
*/
|
||||
template<typename Scalar, typename Index>
|
||||
class SuperNodalMatrix<Scalar,Index>::InnerIterator
|
||||
{
|
||||
public:
|
||||
InnerIterator(const SuperNodalMatrix& mat, Index outer)
|
||||
: m_matrix(mat),
|
||||
m_outer(outer),
|
||||
m_idval(mat.colIndexPtr()[outer]),
|
||||
m_startval(m_idval),
|
||||
m_endval(mat.colIndexPtr()[outer+1]),
|
||||
m_idrow(mat.rowIndexPtr()[outer]),
|
||||
m_startidrow(m_idrow),
|
||||
m_endidrow(mat.rowIndexPtr()[outer+1])
|
||||
{}
|
||||
inline InnerIterator& operator++()
|
||||
{
|
||||
m_idval++;
|
||||
m_idrow++;
|
||||
return *this;
|
||||
}
|
||||
inline Scalar value() const { return m_matrix.valuePtr()[m_idval]; }
|
||||
|
||||
inline Scalar& valueRef() { return const_cast<Scalar&>(m_matrix.valuePtr()[m_idval]); }
|
||||
|
||||
inline Index index() const { return m_matrix.rowIndex()[m_idrow]; }
|
||||
inline Index row() const { return index(); }
|
||||
inline Index col() const { return m_outer; }
|
||||
|
||||
inline Index supIndex() const { return m_matrix.colToSup()[m_outer]; }
|
||||
|
||||
inline operator bool() const
|
||||
{
|
||||
return ( (m_idval < m_endval) && (m_idval > m_startval) &&
|
||||
(m_idrow < m_endidrow) && (m_idrow > m_startidrow) );
|
||||
}
|
||||
|
||||
protected:
|
||||
const SuperNodalMatrix& m_matrix; // Supernodal lower triangular matrix
|
||||
const Index m_outer; // Current column
|
||||
Index m_idval; //Index to browse the values in the current column
|
||||
const Index m_startval; // Start of the column value
|
||||
const Index m_endval; // End of the column value
|
||||
Index m_idrow; //Index to browse the row indices
|
||||
const Index m_startidrow; // Start of the row indices of the current column value
|
||||
const Index m_endidrow; // End of the row indices of the current column value
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Solve with the supernode triangular matrix
|
||||
*
|
||||
*/
|
||||
template<typename Scalar, typename Index>
|
||||
template<typename Dest>
|
||||
void SuperNodalMatrix<Scalar,Index>::solveInPlace( MatrixBase<Dest>&X) const
|
||||
{
|
||||
Index n = X.rows();
|
||||
int nrhs = X.cols();
|
||||
const Scalar * Lval = valuePtr(); // Nonzero values
|
||||
Matrix<Scalar,Dynamic,Dynamic> work(n, nrhs); // working vector
|
||||
work.setZero();
|
||||
for (int k = 0; k <= nsuper(); k ++)
|
||||
{
|
||||
Index fsupc = supToCol()[k]; // First column of the current supernode
|
||||
Index istart = rowIndexPtr()[fsupc]; // Pointer index to the subscript of the current column
|
||||
Index nsupr = rowIndexPtr()[fsupc+1] - istart; // Number of rows in the current supernode
|
||||
Index nsupc = supToCol()[k+1] - fsupc; // Number of columns in the current supernode
|
||||
Index nrow = nsupr - nsupc; // Number of rows in the non-diagonal part of the supernode
|
||||
Index irow; //Current index row
|
||||
|
||||
if (nsupc == 1 )
|
||||
{
|
||||
for (int j = 0; j < nrhs; j++)
|
||||
{
|
||||
InnerIterator it(*this, fsupc);
|
||||
++it; // Skip the diagonal element
|
||||
for (; it; ++it)
|
||||
{
|
||||
irow = it.row();
|
||||
X(irow, j) -= X(fsupc, j) * it.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The supernode has more than one column
|
||||
Index luptr = colIndexPtr()[fsupc];
|
||||
|
||||
// Triangular solve
|
||||
Map<const Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > A( &(Lval[luptr]), nsupc, nsupc, OuterStride<>(nsupr) );
|
||||
Map< Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > U (&(X(fsupc,0)), nsupc, nrhs, OuterStride<>(n) );
|
||||
U = A.template triangularView<UnitLower>().solve(U);
|
||||
|
||||
// Matrix-vector product
|
||||
new (&A) Map<const Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > ( &(Lval[luptr+nsupc]), nrow, nsupc, OuterStride<>(nsupr) );
|
||||
work.block(0, 0, nrow, nrhs) = A * U;
|
||||
|
||||
//Begin Scatter
|
||||
for (int j = 0; j < nrhs; j++)
|
||||
{
|
||||
Index iptr = istart + nsupc;
|
||||
for (int i = 0; i < nrow; i++)
|
||||
{
|
||||
irow = rowIndex()[iptr];
|
||||
X(irow, j) -= work(i, j); // Scatter operation
|
||||
work(i, j) = Scalar(0);
|
||||
iptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
204
Eigen/src/SparseLU/SparseLU_Memory.h
Normal file
204
Eigen/src/SparseLU/SparseLU_Memory.h
Normal file
@ -0,0 +1,204 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
/*
|
||||
|
||||
* NOTE: This file is the modified version of [s,d,c,z]memory.c files in SuperLU
|
||||
|
||||
* -- SuperLU routine (version 3.1) --
|
||||
* Univ. of California Berkeley, Xerox Palo Alto Research Center,
|
||||
* and Lawrence Berkeley National Lab.
|
||||
* August 1, 2008
|
||||
*
|
||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
|
||||
* EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program for any
|
||||
* purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is
|
||||
* granted, provided the above notices are retained, and a notice that
|
||||
* the code was modified is included with the above copyright notice.
|
||||
*/
|
||||
|
||||
#ifndef EIGEN_SPARSELU_MEMORY
|
||||
#define EIGEN_SPARSELU_MEMORY
|
||||
|
||||
#define LU_NO_MARKER 3
|
||||
#define LU_NUM_TEMPV(m,w,t,b) ((std::max)(m, (t+b)*w) )
|
||||
#define IND_EMPTY (-1)
|
||||
|
||||
#define LU_Reduce(alpha) ((alpha + 1) / 2) // i.e (alpha-1)/2 + 1
|
||||
#define LU_GluIntArray(n) (5* (n) + 5)
|
||||
#define LU_TempSpace(m, w) ( (2*w + 4 + LU_NO_MARKER) * m * sizeof(Index) \
|
||||
+ (w + 1) * m * sizeof(Scalar) )
|
||||
|
||||
|
||||
/**
|
||||
* Expand the existing storage to accomodate more fill-ins
|
||||
* \param vec Valid pointer to the vector to allocate or expand
|
||||
* \param [in,out]length At input, contain the current length of the vector that is to be increased. At output, length of the newly allocated vector
|
||||
* \param [in]nbElts Current number of elements in the factors
|
||||
* \param keep_prev 1: use length and do not expand the vector; 0: compute new_len and expand
|
||||
* \param [in,out]num_expansions Number of times the memory has been expanded
|
||||
*/
|
||||
template <typename Scalar, typename Index>
|
||||
template <typename VectorType>
|
||||
int SparseLUBase<Scalar,Index>::expand(VectorType& vec, int& length, int nbElts, int keep_prev, int& num_expansions)
|
||||
{
|
||||
|
||||
float alpha = 1.5; // Ratio of the memory increase
|
||||
int new_len; // New size of the allocated memory
|
||||
|
||||
if(num_expansions == 0 || keep_prev)
|
||||
new_len = length ; // First time allocate requested
|
||||
else
|
||||
new_len = alpha * length ;
|
||||
|
||||
VectorType old_vec; // Temporary vector to hold the previous values
|
||||
if (nbElts > 0 )
|
||||
old_vec = vec.segment(0,nbElts);
|
||||
|
||||
//Allocate or expand the current vector
|
||||
try
|
||||
{
|
||||
vec.resize(new_len);
|
||||
}
|
||||
catch(std::bad_alloc& )
|
||||
{
|
||||
if ( !num_expansions )
|
||||
{
|
||||
// First time to allocate from LUMemInit()
|
||||
throw; // Pass the exception to LUMemInit() which has a try... catch block
|
||||
}
|
||||
if (keep_prev)
|
||||
{
|
||||
// In this case, the memory length should not not be reduced
|
||||
return new_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reduce the size and increase again
|
||||
int tries = 0; // Number of attempts
|
||||
do
|
||||
{
|
||||
alpha = LU_Reduce(alpha);
|
||||
new_len = alpha * length ;
|
||||
try
|
||||
{
|
||||
vec.resize(new_len);
|
||||
}
|
||||
catch(std::bad_alloc& )
|
||||
{
|
||||
tries += 1;
|
||||
if ( tries > 10) return new_len;
|
||||
}
|
||||
} while (!vec.size());
|
||||
}
|
||||
}
|
||||
//Copy the previous values to the newly allocated space
|
||||
if (nbElts > 0)
|
||||
vec.segment(0, nbElts) = old_vec;
|
||||
|
||||
|
||||
length = new_len;
|
||||
if(num_expansions) ++num_expansions;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Allocate various working space for the numerical factorization phase.
|
||||
* \param m number of rows of the input matrix
|
||||
* \param n number of columns
|
||||
* \param annz number of initial nonzeros in the matrix
|
||||
* \param lwork if lwork=-1, this routine returns an estimated size of the required memory
|
||||
* \param glu persistent data to facilitate multiple factors : will be deleted later ??
|
||||
* \return an estimated size of the required memory if lwork = -1; otherwise, return the size of actually allocated memory when allocation failed, and 0 on success
|
||||
* NOTE Unlike SuperLU, this routine does not support successive factorization with the same pattern and the same row permutation
|
||||
*/
|
||||
template <typename Scalar, typename Index>
|
||||
int SparseLUBase<Scalar,Index>::LUMemInit(int m, int n, int annz, int lwork, int fillratio, int panel_size, GlobalLU_t& glu)
|
||||
{
|
||||
int& num_expansions = glu.num_expansions; //No memory expansions so far
|
||||
num_expansions = 0;
|
||||
glu.nzumax = glu.nzlumax = (std::max)(fillratio * annz, m*n); // estimated number of nonzeros in U
|
||||
glu.nzlmax = (std::max)(1., fillratio/4.) * annz; // estimated nnz in L factor
|
||||
|
||||
// Return the estimated size to the user if necessary
|
||||
if (lwork == IND_EMPTY)
|
||||
{
|
||||
int estimated_size;
|
||||
estimated_size = LU_GluIntArray(n) * sizeof(Index) + LU_TempSpace(m, panel_size)
|
||||
+ (glu.nzlmax + glu.nzumax) * sizeof(Index) + (glu.nzlumax+glu.nzumax) * sizeof(Scalar) + n;
|
||||
return estimated_size;
|
||||
}
|
||||
|
||||
// Setup the required space
|
||||
|
||||
// First allocate Integer pointers for L\U factors
|
||||
glu.xsup.resize(n+1);
|
||||
glu.supno.resize(n+1);
|
||||
glu.xlsub.resize(n+1);
|
||||
glu.xlusup.resize(n+1);
|
||||
glu.xusub.resize(n+1);
|
||||
|
||||
// Reserve memory for L/U factors
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
expand<ScalarVector>(glu.lusup, glu.nzlumax, 0, 0, num_expansions);
|
||||
expand<ScalarVector>(glu.ucol,glu.nzumax, 0, 0, num_expansions);
|
||||
expand<IndexVector>(glu.lsub,glu.nzlmax, 0, 0, num_expansions);
|
||||
expand<IndexVector>(glu.usub,glu.nzumax, 0, 1, num_expansions);
|
||||
}
|
||||
catch(std::bad_alloc& )
|
||||
{
|
||||
//Reduce the estimated size and retry
|
||||
glu.nzlumax /= 2;
|
||||
glu.nzumax /= 2;
|
||||
glu.nzlmax /= 2;
|
||||
if (glu.nzlumax < annz ) return glu.nzlumax;
|
||||
}
|
||||
|
||||
} while (!glu.lusup.size() || !glu.ucol.size() || !glu.lsub.size() || !glu.usub.size());
|
||||
|
||||
|
||||
|
||||
++num_expansions;
|
||||
return 0;
|
||||
|
||||
} // end LuMemInit
|
||||
|
||||
/**
|
||||
* \brief Expand the existing storage
|
||||
* \param vec vector to expand
|
||||
* \param [in,out]maxlen On input, previous size of vec (Number of elements to copy ). on output, new size
|
||||
* \param nbElts current number of elements in the vector.
|
||||
* \param glu Global data structure
|
||||
* \return 0 on success, > 0 size of the memory allocated so far
|
||||
*/
|
||||
template <typename Scalar, typename Index>
|
||||
template <typename VectorType>
|
||||
int SparseLUBase<Scalar,Index>::LUMemXpand(VectorType& vec, int& maxlen, int nbElts, LU_MemType memtype, int& num_expansions)
|
||||
{
|
||||
int failed_size;
|
||||
if (memtype == USUB)
|
||||
failed_size = expand<VectorType>(vec, maxlen, nbElts, 1, num_expansions);
|
||||
else
|
||||
failed_size = expand<VectorType>(vec, maxlen, nbElts, 0, num_expansions);
|
||||
|
||||
if (failed_size)
|
||||
return failed_size;
|
||||
|
||||
return 0 ;
|
||||
|
||||
}
|
||||
#endif
|
103
Eigen/src/SparseLU/SparseLU_Structs.h
Normal file
103
Eigen/src/SparseLU/SparseLU_Structs.h
Normal file
@ -0,0 +1,103 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
/*
|
||||
* NOTE: This file comes from a partly modified version of files slu_[s,d,c,z]defs.h
|
||||
* -- SuperLU routine (version 4.1) --
|
||||
* Univ. of California Berkeley, Xerox Palo Alto Research Center,
|
||||
* and Lawrence Berkeley National Lab.
|
||||
* November, 2010
|
||||
*
|
||||
* Global data structures used in LU factorization -
|
||||
*
|
||||
* nsuper: #supernodes = nsuper + 1, numbered [0, nsuper].
|
||||
* (xsup,supno): supno[i] is the supernode no to which i belongs;
|
||||
* xsup(s) points to the beginning of the s-th supernode.
|
||||
* e.g. supno 0 1 2 2 3 3 3 4 4 4 4 4 (n=12)
|
||||
* xsup 0 1 2 4 7 12
|
||||
* Note: dfs will be performed on supernode rep. relative to the new
|
||||
* row pivoting ordering
|
||||
*
|
||||
* (xlsub,lsub): lsub[*] contains the compressed subscript of
|
||||
* rectangular supernodes; xlsub[j] points to the starting
|
||||
* location of the j-th column in lsub[*]. Note that xlsub
|
||||
* is indexed by column.
|
||||
* Storage: original row subscripts
|
||||
*
|
||||
* During the course of sparse LU factorization, we also use
|
||||
* (xlsub,lsub) for the purpose of symmetric pruning. For each
|
||||
* supernode {s,s+1,...,t=s+r} with first column s and last
|
||||
* column t, the subscript set
|
||||
* lsub[j], j=xlsub[s], .., xlsub[s+1]-1
|
||||
* is the structure of column s (i.e. structure of this supernode).
|
||||
* It is used for the storage of numerical values.
|
||||
* Furthermore,
|
||||
* lsub[j], j=xlsub[t], .., xlsub[t+1]-1
|
||||
* is the structure of the last column t of this supernode.
|
||||
* It is for the purpose of symmetric pruning. Therefore, the
|
||||
* structural subscripts can be rearranged without making physical
|
||||
* interchanges among the numerical values.
|
||||
*
|
||||
* However, if the supernode has only one column, then we
|
||||
* only keep one set of subscripts. For any subscript interchange
|
||||
* performed, similar interchange must be done on the numerical
|
||||
* values.
|
||||
*
|
||||
* The last column structures (for pruning) will be removed
|
||||
* after the numercial LU factorization phase.
|
||||
*
|
||||
* (xlusup,lusup): lusup[*] contains the numerical values of the
|
||||
* rectangular supernodes; xlusup[j] points to the starting
|
||||
* location of the j-th column in storage vector lusup[*]
|
||||
* Note: xlusup is indexed by column.
|
||||
* Each rectangular supernode is stored by column-major
|
||||
* scheme, consistent with Fortran 2-dim array storage.
|
||||
*
|
||||
* (xusub,ucol,usub): ucol[*] stores the numerical values of
|
||||
* U-columns outside the rectangular supernodes. The row
|
||||
* subscript of nonzero ucol[k] is stored in usub[k].
|
||||
* xusub[i] points to the starting location of column i in ucol.
|
||||
* Storage: new row subscripts; that is subscripts of PA.
|
||||
*/
|
||||
#ifndef EIGEN_LU_STRUCTS
|
||||
#define EIGEN_LU_STRUCTS
|
||||
typedef enum {LUSUP, UCOL, LSUB, USUB, LLVL, ULVL} LU_MemType;
|
||||
|
||||
|
||||
template <typename IndexVector, typename ScalarVector>
|
||||
struct LU_GlobalLU_t {
|
||||
typedef typename IndexVector::Scalar Index;
|
||||
IndexVector xsup; //First supernode column ... xsup(s) points to the beginning of the s-th supernode
|
||||
IndexVector supno; // Supernode number corresponding to this column (column to supernode mapping)
|
||||
ScalarVector lusup; // nonzero values of L ordered by columns
|
||||
IndexVector lsub; // Compressed row indices of L rectangular supernodes.
|
||||
IndexVector xlusup; // pointers to the beginning of each column in lusup
|
||||
IndexVector xlsub; // pointers to the beginning of each column in lsub
|
||||
Index nzlmax; // Current max size of lsub
|
||||
Index nzlumax; // Current max size of lusup
|
||||
ScalarVector ucol; // nonzero values of U ordered by columns
|
||||
IndexVector usub; // row indices of U columns in ucol
|
||||
IndexVector xusub; // Pointers to the beginning of each column of U in ucol
|
||||
Index nzumax; // Current max size of ucol
|
||||
Index n; // Number of columns in the matrix
|
||||
int num_expansions;
|
||||
};
|
||||
|
||||
// Values to set for performance
|
||||
struct LU_perfvalues {
|
||||
int panel_size; // a panel consists of at most <panel_size> consecutive columns
|
||||
int relax; // To control degree of relaxing supernodes. If the number of nodes (columns)
|
||||
// in a subtree of the elimination tree is less than relax, this subtree is considered
|
||||
// as one supernode regardless of the row structures of those columns
|
||||
int maxsuper; // The maximum size for a supernode in complete LU
|
||||
int rowblk; // The minimum row dimension for 2-D blocking to be used;
|
||||
int colblk; // The minimum column dimension for 2-D blocking to be used;
|
||||
int fillfactor; // The estimated fills factors for L and U, compared with A
|
||||
};
|
||||
#endif
|
75
Eigen/src/SparseLU/SparseLU_Utils.h
Normal file
75
Eigen/src/SparseLU/SparseLU_Utils.h
Normal file
@ -0,0 +1,75 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
#ifndef EIGEN_SPARSELU_UTILS_H
|
||||
#define EIGEN_SPARSELU_UTILS_H
|
||||
|
||||
|
||||
/**
|
||||
* \brief Count Nonzero elements in the factors
|
||||
*/
|
||||
template <typename Scalar, typename Index>
|
||||
void SparseLUBase<Scalar,Index>::LU_countnz(const int n, int& nnzL, int& nnzU, GlobalLU_t& glu)
|
||||
{
|
||||
nnzL = 0;
|
||||
nnzU = (glu.xusub)(n);
|
||||
int nsuper = (glu.supno)(n);
|
||||
int jlen;
|
||||
int i, j, fsupc;
|
||||
if (n <= 0 ) return;
|
||||
// For each supernode
|
||||
for (i = 0; i <= nsuper; i++)
|
||||
{
|
||||
fsupc = glu.xsup(i);
|
||||
jlen = glu.xlsub(fsupc+1) - glu.xlsub(fsupc);
|
||||
|
||||
for (j = fsupc; j < glu.xsup(i+1); j++)
|
||||
{
|
||||
nnzL += jlen;
|
||||
nnzU += j - fsupc + 1;
|
||||
jlen--;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* \brief Fix up the data storage lsub for L-subscripts.
|
||||
*
|
||||
* It removes the subscripts sets for structural pruning,
|
||||
* and applies permutation to the remaining subscripts
|
||||
*
|
||||
*/
|
||||
template <typename Scalar, typename Index>
|
||||
void SparseLUBase<Scalar,Index>::LU_fixupL(const int n, const IndexVector& perm_r, GlobalLU_t& glu)
|
||||
{
|
||||
int fsupc, i, j, k, jstart;
|
||||
|
||||
int nextl = 0;
|
||||
int nsuper = (glu.supno)(n);
|
||||
|
||||
// For each supernode
|
||||
for (i = 0; i <= nsuper; i++)
|
||||
{
|
||||
fsupc = glu.xsup(i);
|
||||
jstart = glu.xlsub(fsupc);
|
||||
glu.xlsub(fsupc) = nextl;
|
||||
for (j = jstart; j < glu.xlsub(fsupc + 1); j++)
|
||||
{
|
||||
glu.lsub(nextl) = perm_r(glu.lsub(j)); // Now indexed into P*A
|
||||
nextl++;
|
||||
}
|
||||
for (k = fsupc+1; k < glu.xsup(i+1); k++)
|
||||
glu.xlsub(k) = nextl; // other columns in supernode i
|
||||
}
|
||||
|
||||
glu.xlsub(n) = nextl;
|
||||
}
|
||||
|
||||
#endif
|
162
Eigen/src/SparseLU/SparseLU_column_bmod.h
Normal file
162
Eigen/src/SparseLU/SparseLU_column_bmod.h
Normal file
@ -0,0 +1,162 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
// Copyright (C) 2012 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
/*
|
||||
|
||||
* NOTE: This file is the modified version of xcolumn_bmod.c file in SuperLU
|
||||
|
||||
* -- SuperLU routine (version 3.0) --
|
||||
* Univ. of California Berkeley, Xerox Palo Alto Research Center,
|
||||
* and Lawrence Berkeley National Lab.
|
||||
* October 15, 2003
|
||||
*
|
||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
|
||||
* EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program for any
|
||||
* purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is
|
||||
* granted, provided the above notices are retained, and a notice that
|
||||
* the code was modified is included with the above copyright notice.
|
||||
*/
|
||||
#ifndef SPARSELU_COLUMN_BMOD_H
|
||||
#define SPARSELU_COLUMN_BMOD_H
|
||||
|
||||
/**
|
||||
* \brief Performs numeric block updates (sup-col) in topological order
|
||||
*
|
||||
* \param jcol current column to update
|
||||
* \param nseg Number of segments in the U part
|
||||
* \param dense Store the full representation of the column
|
||||
* \param tempv working array
|
||||
* \param segrep segment representative ...
|
||||
* \param repfnz ??? First nonzero column in each row ??? ...
|
||||
* \param fpanelc First column in the current panel
|
||||
* \param glu Global LU data.
|
||||
* \return 0 - successful return
|
||||
* > 0 - number of bytes allocated when run out of space
|
||||
*
|
||||
*/
|
||||
template <typename Scalar, typename Index>
|
||||
int SparseLUBase<Scalar,Index>::LU_column_bmod(const int jcol, const int nseg, BlockScalarVector& dense, ScalarVector& tempv, BlockIndexVector& segrep, BlockIndexVector& repfnz, int fpanelc, GlobalLU_t& glu)
|
||||
{
|
||||
int jsupno, k, ksub, krep, ksupno;
|
||||
int lptr, nrow, isub, irow, nextlu, new_next, ufirst;
|
||||
int fsupc, nsupc, nsupr, luptr, kfnz, no_zeros;
|
||||
/* krep = representative of current k-th supernode
|
||||
* fsupc = first supernodal column
|
||||
* nsupc = number of columns in a supernode
|
||||
* nsupr = number of rows in a supernode
|
||||
* luptr = location of supernodal LU-block in storage
|
||||
* kfnz = first nonz in the k-th supernodal segment
|
||||
* no_zeros = no lf leading zeros in a supernodal U-segment
|
||||
*/
|
||||
|
||||
jsupno = glu.supno(jcol);
|
||||
// For each nonzero supernode segment of U[*,j] in topological order
|
||||
k = nseg - 1;
|
||||
int d_fsupc; // distance between the first column of the current panel and the
|
||||
// first column of the current snode
|
||||
int fst_col; // First column within small LU update
|
||||
int segsize;
|
||||
for (ksub = 0; ksub < nseg; ksub++)
|
||||
{
|
||||
krep = segrep(k); k--;
|
||||
ksupno = glu.supno(krep);
|
||||
if (jsupno != ksupno )
|
||||
{
|
||||
// outside the rectangular supernode
|
||||
fsupc = glu.xsup(ksupno);
|
||||
fst_col = (std::max)(fsupc, fpanelc);
|
||||
|
||||
// Distance from the current supernode to the current panel;
|
||||
// d_fsupc = 0 if fsupc > fpanelc
|
||||
d_fsupc = fst_col - fsupc;
|
||||
|
||||
luptr = glu.xlusup(fst_col) + d_fsupc;
|
||||
lptr = glu.xlsub(fsupc) + d_fsupc;
|
||||
|
||||
kfnz = repfnz(krep);
|
||||
kfnz = (std::max)(kfnz, fpanelc);
|
||||
|
||||
segsize = krep - kfnz + 1;
|
||||
nsupc = krep - fst_col + 1;
|
||||
nsupr = glu.xlsub(fsupc+1) - glu.xlsub(fsupc);
|
||||
nrow = nsupr - d_fsupc - nsupc;
|
||||
|
||||
// Perform a triangular solver and block update,
|
||||
// then scatter the result of sup-col update to dense
|
||||
no_zeros = kfnz - fst_col;
|
||||
if(segsize==1)
|
||||
LU_kernel_bmod<1>::run(segsize, dense, tempv, glu.lusup, luptr, nsupr, nrow, glu.lsub, lptr, no_zeros);
|
||||
else
|
||||
LU_kernel_bmod<Dynamic>::run(segsize, dense, tempv, glu.lusup, luptr, nsupr, nrow, glu.lsub, lptr, no_zeros);
|
||||
} // end if jsupno
|
||||
} // end for each segment
|
||||
|
||||
// Process the supernodal portion of L\U[*,j]
|
||||
nextlu = glu.xlusup(jcol);
|
||||
fsupc = glu.xsup(jsupno);
|
||||
|
||||
// copy the SPA dense into L\U[*,j]
|
||||
int mem;
|
||||
new_next = nextlu + glu.xlsub(fsupc + 1) - glu.xlsub(fsupc);
|
||||
while (new_next > glu.nzlumax )
|
||||
{
|
||||
mem = LUMemXpand<ScalarVector>(glu.lusup, glu.nzlumax, nextlu, LUSUP, glu.num_expansions);
|
||||
if (mem) return mem;
|
||||
}
|
||||
|
||||
for (isub = glu.xlsub(fsupc); isub < glu.xlsub(fsupc+1); isub++)
|
||||
{
|
||||
irow = glu.lsub(isub);
|
||||
glu.lusup(nextlu) = dense(irow);
|
||||
dense(irow) = Scalar(0.0);
|
||||
++nextlu;
|
||||
}
|
||||
|
||||
glu.xlusup(jcol + 1) = nextlu; // close L\U(*,jcol);
|
||||
|
||||
/* For more updates within the panel (also within the current supernode),
|
||||
* should start from the first column of the panel, or the first column
|
||||
* of the supernode, whichever is bigger. There are two cases:
|
||||
* 1) fsupc < fpanelc, then fst_col <-- fpanelc
|
||||
* 2) fsupc >= fpanelc, then fst_col <-- fsupc
|
||||
*/
|
||||
fst_col = (std::max)(fsupc, fpanelc);
|
||||
|
||||
if (fst_col < jcol)
|
||||
{
|
||||
// Distance between the current supernode and the current panel
|
||||
// d_fsupc = 0 if fsupc >= fpanelc
|
||||
d_fsupc = fst_col - fsupc;
|
||||
|
||||
lptr = glu.xlsub(fsupc) + d_fsupc;
|
||||
luptr = glu.xlusup(fst_col) + d_fsupc;
|
||||
nsupr = glu.xlsub(fsupc+1) - glu.xlsub(fsupc); // leading dimension
|
||||
nsupc = jcol - fst_col; // excluding jcol
|
||||
nrow = nsupr - d_fsupc - nsupc;
|
||||
|
||||
// points to the beginning of jcol in snode L\U(jsupno)
|
||||
ufirst = glu.xlusup(jcol) + d_fsupc;
|
||||
Map<Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > A( &(glu.lusup.data()[luptr]), nsupc, nsupc, OuterStride<>(nsupr) );
|
||||
VectorBlock<ScalarVector> u(glu.lusup, ufirst, nsupc);
|
||||
u = A.template triangularView<UnitLower>().solve(u);
|
||||
|
||||
new (&A) Map<Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > ( &(glu.lusup.data()[luptr+nsupc]), nrow, nsupc, OuterStride<>(nsupr) );
|
||||
VectorBlock<ScalarVector> l(glu.lusup, ufirst+nsupc, nrow);
|
||||
l.noalias() -= A * u;
|
||||
|
||||
} // End if fst_col
|
||||
return 0;
|
||||
}
|
||||
#endif
|
164
Eigen/src/SparseLU/SparseLU_column_dfs.h
Normal file
164
Eigen/src/SparseLU/SparseLU_column_dfs.h
Normal file
@ -0,0 +1,164 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
/*
|
||||
|
||||
* NOTE: This file is the modified version of [s,d,c,z]column_dfs.c file in SuperLU
|
||||
|
||||
* -- SuperLU routine (version 2.0) --
|
||||
* Univ. of California Berkeley, Xerox Palo Alto Research Center,
|
||||
* and Lawrence Berkeley National Lab.
|
||||
* November 15, 1997
|
||||
*
|
||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
|
||||
* EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program for any
|
||||
* purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is
|
||||
* granted, provided the above notices are retained, and a notice that
|
||||
* the code was modified is included with the above copyright notice.
|
||||
*/
|
||||
#ifndef SPARSELU_COLUMN_DFS_H
|
||||
#define SPARSELU_COLUMN_DFS_H
|
||||
/**
|
||||
* \brief Performs a symbolic factorization on column jcol and decide the supernode boundary
|
||||
*
|
||||
* A supernode representative is the last column of a supernode.
|
||||
* The nonzeros in U[*,j] are segments that end at supernodes representatives.
|
||||
* The routine returns a list of the supernodal representatives
|
||||
* in topological order of the dfs that generates them.
|
||||
* The location of the first nonzero in each supernodal segment
|
||||
* (supernodal entry location) is also returned.
|
||||
*
|
||||
* \param m number of rows in the matrix
|
||||
* \param jcol Current column
|
||||
* \param perm_r Row permutation
|
||||
* \param maxsuper Maximum number of column allowed in a supernode
|
||||
* \param [in,out] nseg Number of segments in current U[*,j] - new segments appended
|
||||
* \param lsub_col defines the rhs vector to start the dfs
|
||||
* \param [in,out] segrep Segment representatives - new segments appended
|
||||
* \param repfnz First nonzero location in each row
|
||||
* \param xprune
|
||||
* \param marker marker[i] == jj, if i was visited during dfs of current column jj;
|
||||
* \param parent
|
||||
* \param xplore working array
|
||||
* \param glu global LU data
|
||||
* \return 0 success
|
||||
* > 0 number of bytes allocated when run out of space
|
||||
*
|
||||
*/
|
||||
template<typename IndexVector, typename ScalarVector>
|
||||
struct LU_column_dfs_traits
|
||||
{
|
||||
typedef typename IndexVector::Scalar Index;
|
||||
typedef typename ScalarVector::Scalar Scalar;
|
||||
LU_column_dfs_traits(Index jcol, Index& jsuper, LU_GlobalLU_t<IndexVector, ScalarVector>& glu)
|
||||
: m_jcol(jcol), m_jsuper_ref(jsuper), m_glu(glu)
|
||||
{}
|
||||
bool update_segrep(Index /*krep*/, Index /*jj*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
void mem_expand(IndexVector& lsub, int& nextl, int chmark)
|
||||
{
|
||||
if (nextl >= m_glu.nzlmax)
|
||||
SparseLUBase<Scalar,Index>::LUMemXpand(lsub, m_glu.nzlmax, nextl, LSUB, m_glu.num_expansions);
|
||||
if (chmark != (m_jcol-1)) m_jsuper_ref = IND_EMPTY;
|
||||
}
|
||||
enum { ExpandMem = true };
|
||||
|
||||
int m_jcol;
|
||||
int& m_jsuper_ref;
|
||||
LU_GlobalLU_t<IndexVector, ScalarVector>& m_glu;
|
||||
};
|
||||
|
||||
template <typename Scalar, typename Index>
|
||||
int SparseLUBase<Scalar,Index>::LU_column_dfs(const int m, const int jcol, IndexVector& perm_r, int maxsuper, int& nseg, BlockIndexVector& lsub_col, IndexVector& segrep, BlockIndexVector& repfnz, IndexVector& xprune, IndexVector& marker, IndexVector& parent, IndexVector& xplore, GlobalLU_t& glu)
|
||||
{
|
||||
|
||||
int jsuper = glu.supno(jcol);
|
||||
int nextl = glu.xlsub(jcol);
|
||||
VectorBlock<IndexVector> marker2(marker, 2*m, m);
|
||||
|
||||
|
||||
LU_column_dfs_traits<IndexVector, ScalarVector> traits(jcol, jsuper, glu);
|
||||
|
||||
// For each nonzero in A(*,jcol) do dfs
|
||||
for (int k = 0; lsub_col[k] != IND_EMPTY; k++)
|
||||
{
|
||||
int krow = lsub_col(k);
|
||||
lsub_col(k) = IND_EMPTY;
|
||||
int kmark = marker2(krow);
|
||||
|
||||
// krow was visited before, go to the next nonz;
|
||||
if (kmark == jcol) continue;
|
||||
|
||||
LU_dfs_kernel(jcol, perm_r, nseg, glu.lsub, segrep, repfnz, xprune, marker2, parent,
|
||||
xplore, glu, nextl, krow, traits);
|
||||
} // for each nonzero ...
|
||||
|
||||
int fsupc, jptr, jm1ptr, ito, ifrom, istop;
|
||||
int nsuper = glu.supno(jcol);
|
||||
int jcolp1 = jcol + 1;
|
||||
int jcolm1 = jcol - 1;
|
||||
|
||||
// check to see if j belongs in the same supernode as j-1
|
||||
if ( jcol == 0 )
|
||||
{ // Do nothing for column 0
|
||||
nsuper = glu.supno(0) = 0 ;
|
||||
}
|
||||
else
|
||||
{
|
||||
fsupc = glu.xsup(nsuper);
|
||||
jptr = glu.xlsub(jcol); // Not yet compressed
|
||||
jm1ptr = glu.xlsub(jcolm1);
|
||||
|
||||
// Use supernodes of type T2 : see SuperLU paper
|
||||
if ( (nextl-jptr != jptr-jm1ptr-1) ) jsuper = IND_EMPTY;
|
||||
|
||||
// Make sure the number of columns in a supernode doesn't
|
||||
// exceed threshold
|
||||
if ( (jcol - fsupc) >= maxsuper) jsuper = IND_EMPTY;
|
||||
|
||||
/* If jcol starts a new supernode, reclaim storage space in
|
||||
* glu.lsub from previous supernode. Note we only store
|
||||
* the subscript set of the first and last columns of
|
||||
* a supernode. (first for num values, last for pruning)
|
||||
*/
|
||||
if (jsuper == IND_EMPTY)
|
||||
{ // starts a new supernode
|
||||
if ( (fsupc < jcolm1-1) )
|
||||
{ // >= 3 columns in nsuper
|
||||
ito = glu.xlsub(fsupc+1);
|
||||
glu.xlsub(jcolm1) = ito;
|
||||
istop = ito + jptr - jm1ptr;
|
||||
xprune(jcolm1) = istop; // intialize xprune(jcol-1)
|
||||
glu.xlsub(jcol) = istop;
|
||||
|
||||
for (ifrom = jm1ptr; ifrom < nextl; ++ifrom, ++ito)
|
||||
glu.lsub(ito) = glu.lsub(ifrom);
|
||||
nextl = ito; // = istop + length(jcol)
|
||||
}
|
||||
nsuper++;
|
||||
glu.supno(jcol) = nsuper;
|
||||
} // if a new supernode
|
||||
} // end else: jcol > 0
|
||||
|
||||
// Tidy up the pointers before exit
|
||||
glu.xsup(nsuper+1) = jcolp1;
|
||||
glu.supno(jcolp1) = nsuper;
|
||||
xprune(jcol) = nextl; // Intialize upper bound for pruning
|
||||
glu.xlsub(jcolp1) = nextl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
100
Eigen/src/SparseLU/SparseLU_copy_to_ucol.h
Normal file
100
Eigen/src/SparseLU/SparseLU_copy_to_ucol.h
Normal file
@ -0,0 +1,100 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
/*
|
||||
|
||||
* NOTE: This file is the modified version of [s,d,c,z]copy_to_ucol.c file in SuperLU
|
||||
|
||||
* -- SuperLU routine (version 2.0) --
|
||||
* Univ. of California Berkeley, Xerox Palo Alto Research Center,
|
||||
* and Lawrence Berkeley National Lab.
|
||||
* November 15, 1997
|
||||
*
|
||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
|
||||
* EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program for any
|
||||
* purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is
|
||||
* granted, provided the above notices are retained, and a notice that
|
||||
* the code was modified is included with the above copyright notice.
|
||||
*/
|
||||
#ifndef SPARSELU_COPY_TO_UCOL_H
|
||||
#define SPARSELU_COPY_TO_UCOL_H
|
||||
|
||||
/**
|
||||
* \brief Performs numeric block updates (sup-col) in topological order
|
||||
*
|
||||
* \param jcol current column to update
|
||||
* \param nseg Number of segments in the U part
|
||||
* \param segrep segment representative ...
|
||||
* \param repfnz First nonzero column in each row ...
|
||||
* \param perm_r Row permutation
|
||||
* \param dense Store the full representation of the column
|
||||
* \param glu Global LU data.
|
||||
* \return 0 - successful return
|
||||
* > 0 - number of bytes allocated when run out of space
|
||||
*
|
||||
*/
|
||||
template <typename Scalar, typename Index>
|
||||
int SparseLUBase<Scalar,Index>::LU_copy_to_ucol(const int jcol, const int nseg, IndexVector& segrep, BlockIndexVector& repfnz ,IndexVector& perm_r, BlockScalarVector& dense, GlobalLU_t& glu)
|
||||
{
|
||||
Index ksub, krep, ksupno;
|
||||
|
||||
Index jsupno = glu.supno(jcol);
|
||||
|
||||
// For each nonzero supernode segment of U[*,j] in topological order
|
||||
int k = nseg - 1, i;
|
||||
Index nextu = glu.xusub(jcol);
|
||||
Index kfnz, isub, segsize;
|
||||
Index new_next,irow;
|
||||
Index fsupc, mem;
|
||||
for (ksub = 0; ksub < nseg; ksub++)
|
||||
{
|
||||
krep = segrep(k); k--;
|
||||
ksupno = glu.supno(krep);
|
||||
if (jsupno != ksupno ) // should go into ucol();
|
||||
{
|
||||
kfnz = repfnz(krep);
|
||||
if (kfnz != IND_EMPTY)
|
||||
{ // Nonzero U-segment
|
||||
fsupc = glu.xsup(ksupno);
|
||||
isub = glu.xlsub(fsupc) + kfnz - fsupc;
|
||||
segsize = krep - kfnz + 1;
|
||||
new_next = nextu + segsize;
|
||||
while (new_next > glu.nzumax)
|
||||
{
|
||||
mem = LUMemXpand<ScalarVector>(glu.ucol, glu.nzumax, nextu, UCOL, glu.num_expansions);
|
||||
if (mem) return mem;
|
||||
mem = LUMemXpand<IndexVector>(glu.usub, glu.nzumax, nextu, USUB, glu.num_expansions);
|
||||
if (mem) return mem;
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < segsize; i++)
|
||||
{
|
||||
irow = glu.lsub(isub);
|
||||
glu.usub(nextu) = perm_r(irow); // Unlike the L part, the U part is stored in its final order
|
||||
glu.ucol(nextu) = dense(irow);
|
||||
dense(irow) = Scalar(0.0);
|
||||
nextu++;
|
||||
isub++;
|
||||
}
|
||||
|
||||
} // end nonzero U-segment
|
||||
|
||||
} // end if jsupno
|
||||
|
||||
} // end for each segment
|
||||
glu.xusub(jcol + 1) = nextu; // close U(*,jcol)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
119
Eigen/src/SparseLU/SparseLU_heap_relax_snode.h
Normal file
119
Eigen/src/SparseLU/SparseLU_heap_relax_snode.h
Normal file
@ -0,0 +1,119 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
/* This file is a modified version of heap_relax_snode.c file in SuperLU
|
||||
* -- SuperLU routine (version 3.0) --
|
||||
* Univ. of California Berkeley, Xerox Palo Alto Research Center,
|
||||
* and Lawrence Berkeley National Lab.
|
||||
* October 15, 2003
|
||||
*
|
||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
|
||||
* EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program for any
|
||||
* purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is
|
||||
* granted, provided the above notices are retained, and a notice that
|
||||
* the code was modified is included with the above copyright notice.
|
||||
*/
|
||||
|
||||
#ifndef SPARSELU_HEAP_RELAX_SNODE_H
|
||||
#define SPARSELU_HEAP_RELAX_SNODE_H
|
||||
#include "SparseLU_Coletree.h"
|
||||
/**
|
||||
* \brief Identify the initial relaxed supernodes
|
||||
*
|
||||
* This routine applied to a symmetric elimination tree.
|
||||
* It assumes that the matrix has been reordered according to the postorder of the etree
|
||||
* \param et elimination tree
|
||||
* \param relax_columns Maximum number of columns allowed in a relaxed snode
|
||||
* \param descendants Number of descendants of each node in the etree
|
||||
* \param relax_end last column in a supernode
|
||||
*/
|
||||
template <typename Scalar, typename Index>
|
||||
void SparseLUBase<Scalar,Index>::LU_heap_relax_snode (const int n, IndexVector& et, const int relax_columns, IndexVector& descendants, IndexVector& relax_end)
|
||||
{
|
||||
|
||||
// The etree may not be postordered, but its heap ordered
|
||||
IndexVector post;
|
||||
LU_TreePostorder(n, et, post); // Post order etree
|
||||
IndexVector inv_post(n+1);
|
||||
int i;
|
||||
for (i = 0; i < n+1; ++i) inv_post(post(i)) = i; // inv_post = post.inverse()???
|
||||
|
||||
// Renumber etree in postorder
|
||||
IndexVector iwork(n);
|
||||
IndexVector et_save(n+1);
|
||||
for (i = 0; i < n; ++i)
|
||||
{
|
||||
iwork(post(i)) = post(et(i));
|
||||
}
|
||||
et_save = et; // Save the original etree
|
||||
et = iwork;
|
||||
|
||||
// compute the number of descendants of each node in the etree
|
||||
relax_end.setConstant(IND_EMPTY);
|
||||
int j, parent;
|
||||
descendants.setZero();
|
||||
for (j = 0; j < n; j++)
|
||||
{
|
||||
parent = et(j);
|
||||
if (parent != n) // not the dummy root
|
||||
descendants(parent) += descendants(j) + 1;
|
||||
}
|
||||
// Identify the relaxed supernodes by postorder traversal of the etree
|
||||
int snode_start; // beginning of a snode
|
||||
int k;
|
||||
int nsuper_et_post = 0; // Number of relaxed snodes in postordered etree
|
||||
int nsuper_et = 0; // Number of relaxed snodes in the original etree
|
||||
int l;
|
||||
for (j = 0; j < n; )
|
||||
{
|
||||
parent = et(j);
|
||||
snode_start = j;
|
||||
while ( parent != n && descendants(parent) < relax_columns )
|
||||
{
|
||||
j = parent;
|
||||
parent = et(j);
|
||||
}
|
||||
// Found a supernode in postordered etree, j is the last column
|
||||
++nsuper_et_post;
|
||||
k = n;
|
||||
for (i = snode_start; i <= j; ++i)
|
||||
k = (std::min)(k, inv_post(i));
|
||||
l = inv_post(j);
|
||||
if ( (l - k) == (j - snode_start) ) // Same number of columns in the snode
|
||||
{
|
||||
// This is also a supernode in the original etree
|
||||
relax_end(k) = l; // Record last column
|
||||
++nsuper_et;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = snode_start; i <= j; ++i)
|
||||
{
|
||||
l = inv_post(i);
|
||||
if (descendants(i) == 0)
|
||||
{
|
||||
relax_end(l) = l;
|
||||
++nsuper_et;
|
||||
}
|
||||
}
|
||||
}
|
||||
j++;
|
||||
// Search for a new leaf
|
||||
while (descendants(j) != 0 && j < n) j++;
|
||||
} // End postorder traversal of the etree
|
||||
|
||||
// Recover the original etree
|
||||
et = et_save;
|
||||
}
|
||||
#endif
|
109
Eigen/src/SparseLU/SparseLU_kernel_bmod.h
Normal file
109
Eigen/src/SparseLU/SparseLU_kernel_bmod.h
Normal file
@ -0,0 +1,109 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
// Copyright (C) 2012 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef SPARSELU_KERNEL_BMOD_H
|
||||
#define SPARSELU_KERNEL_BMOD_H
|
||||
|
||||
/**
|
||||
* \brief Performs numeric block updates from a given supernode to a single column
|
||||
*
|
||||
* \param segsize Size of the segment (and blocks ) to use for updates
|
||||
* \param [in,out]dense Packed values of the original matrix
|
||||
* \param tempv temporary vector to use for updates
|
||||
* \param lusup array containing the supernodes
|
||||
* \param nsupr Number of rows in the supernode
|
||||
* \param nrow Number of rows in the rectangular part of the supernode
|
||||
* \param lsub compressed row subscripts of supernodes
|
||||
* \param lptr pointer to the first column of the current supernode in lsub
|
||||
* \param no_zeros Number of nonzeros elements before the diagonal part of the supernode
|
||||
* \return 0 on success
|
||||
*/
|
||||
template <int SegSizeAtCompileTime> struct LU_kernel_bmod
|
||||
{
|
||||
template <typename BlockScalarVector, typename ScalarVector, typename IndexVector>
|
||||
EIGEN_DONT_INLINE static void run(const int segsize, BlockScalarVector& dense, ScalarVector& tempv, ScalarVector& lusup, int& luptr, const int nsupr, const int nrow, IndexVector& lsub, const int lptr, const int no_zeros)
|
||||
{
|
||||
typedef typename ScalarVector::Scalar Scalar;
|
||||
// First, copy U[*,j] segment from dense(*) to tempv(*)
|
||||
// The result of triangular solve is in tempv[*];
|
||||
// The result of matric-vector update is in dense[*]
|
||||
int isub = lptr + no_zeros;
|
||||
int i, irow;
|
||||
for (i = 0; i < ((SegSizeAtCompileTime==Dynamic)?segsize:SegSizeAtCompileTime); i++)
|
||||
{
|
||||
irow = lsub(isub);
|
||||
tempv(i) = dense(irow);
|
||||
++isub;
|
||||
}
|
||||
// Dense triangular solve -- start effective triangle
|
||||
luptr += nsupr * no_zeros + no_zeros;
|
||||
// Form Eigen matrix and vector
|
||||
Map<Matrix<Scalar,SegSizeAtCompileTime,SegSizeAtCompileTime>, 0, OuterStride<> > A( &(lusup.data()[luptr]), segsize, segsize, OuterStride<>(nsupr) );
|
||||
Map<Matrix<Scalar,SegSizeAtCompileTime,1> > u(tempv.data(), segsize);
|
||||
|
||||
u = A.template triangularView<UnitLower>().solve(u);
|
||||
|
||||
// Dense matrix-vector product y <-- B*x
|
||||
luptr += segsize;
|
||||
Map<Matrix<Scalar,Dynamic,SegSizeAtCompileTime>, 0, OuterStride<> > B( &(lusup.data()[luptr]), nrow, segsize, OuterStride<>(nsupr) );
|
||||
Map<Matrix<Scalar,Dynamic,1> > l(tempv.data()+segsize, nrow);
|
||||
if(SegSizeAtCompileTime==2)
|
||||
l = u(0) * B.col(0) + u(1) * B.col(1);
|
||||
else if(SegSizeAtCompileTime==3)
|
||||
l = u(0) * B.col(0) + u(1) * B.col(1) + u(2) * B.col(2);
|
||||
else
|
||||
l.noalias() = B * u;
|
||||
|
||||
// Scatter tempv[] into SPA dense[] as a temporary storage
|
||||
isub = lptr + no_zeros;
|
||||
for (i = 0; i < ((SegSizeAtCompileTime==Dynamic)?segsize:SegSizeAtCompileTime); i++)
|
||||
{
|
||||
irow = lsub(isub++);
|
||||
dense(irow) = tempv(i);
|
||||
}
|
||||
|
||||
// Scatter l into SPA dense[]
|
||||
for (i = 0; i < nrow; i++)
|
||||
{
|
||||
irow = lsub(isub++);
|
||||
dense(irow) -= l(i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct LU_kernel_bmod<1>
|
||||
{
|
||||
template <typename BlockScalarVector, typename ScalarVector, typename IndexVector>
|
||||
EIGEN_DONT_INLINE static void run(const int /*segsize*/, BlockScalarVector& dense, ScalarVector& /*tempv*/, ScalarVector& lusup, int& luptr, const int nsupr, const int nrow, IndexVector& lsub, const int lptr, const int no_zeros)
|
||||
{
|
||||
typedef typename ScalarVector::Scalar Scalar;
|
||||
Scalar f = dense(lsub(lptr + no_zeros));
|
||||
luptr += nsupr * no_zeros + no_zeros + 1;
|
||||
const Scalar* a(lusup.data() + luptr);
|
||||
const typename IndexVector::Scalar* irow(lsub.data()+lptr + no_zeros + 1);
|
||||
int i = 0;
|
||||
for (; i+1 < nrow; i+=2)
|
||||
{
|
||||
int i0 = *(irow++);
|
||||
int i1 = *(irow++);
|
||||
Scalar a0 = *(a++);
|
||||
Scalar a1 = *(a++);
|
||||
Scalar d0 = dense.coeff(i0);
|
||||
Scalar d1 = dense.coeff(i1);
|
||||
d0 -= f*a0;
|
||||
d1 -= f*a1;
|
||||
dense.coeffRef(i0) = d0;
|
||||
dense.coeffRef(i1) = d1;
|
||||
}
|
||||
if(i<nrow)
|
||||
dense.coeffRef(*(irow++)) -= f * *(a++);
|
||||
}
|
||||
};
|
||||
#endif
|
204
Eigen/src/SparseLU/SparseLU_panel_bmod.h
Normal file
204
Eigen/src/SparseLU/SparseLU_panel_bmod.h
Normal file
@ -0,0 +1,204 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
// Copyright (C) 2012 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
/*
|
||||
|
||||
* NOTE: This file is the modified version of [s,d,c,z]panel_bmod.c file in SuperLU
|
||||
|
||||
* -- SuperLU routine (version 3.0) --
|
||||
* Univ. of California Berkeley, Xerox Palo Alto Research Center,
|
||||
* and Lawrence Berkeley National Lab.
|
||||
* October 15, 2003
|
||||
*
|
||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
|
||||
* EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program for any
|
||||
* purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is
|
||||
* granted, provided the above notices are retained, and a notice that
|
||||
* the code was modified is included with the above copyright notice.
|
||||
*/
|
||||
#ifndef SPARSELU_PANEL_BMOD_H
|
||||
#define SPARSELU_PANEL_BMOD_H
|
||||
/**
|
||||
* \brief Performs numeric block updates (sup-panel) in topological order.
|
||||
*
|
||||
* Before entering this routine, the original nonzeros in the panel
|
||||
* were already copied i nto the spa[m,w]
|
||||
*
|
||||
* \param m number of rows in the matrix
|
||||
* \param w Panel size
|
||||
* \param jcol Starting column of the panel
|
||||
* \param nseg Number of segments in the U part
|
||||
* \param dense Store the full representation of the panel
|
||||
* \param tempv working array
|
||||
* \param segrep segment representative... first row in the segment
|
||||
* \param repfnz First nonzero rows
|
||||
* \param glu Global LU data.
|
||||
*
|
||||
*
|
||||
*/
|
||||
template <typename Scalar, typename Index>
|
||||
void SparseLUBase<Scalar,Index>::LU_panel_bmod(const int m, const int w, const int jcol, const int nseg, ScalarVector& dense, ScalarVector& tempv, IndexVector& segrep, IndexVector& repfnz, LU_perfvalues& perfv, GlobalLU_t& glu)
|
||||
{
|
||||
|
||||
int ksub,jj,nextl_col;
|
||||
int fsupc, nsupc, nsupr, nrow;
|
||||
int krep, kfnz;
|
||||
int lptr; // points to the row subscripts of a supernode
|
||||
int luptr; // ...
|
||||
int segsize,no_zeros ;
|
||||
// For each nonz supernode segment of U[*,j] in topological order
|
||||
int k = nseg - 1;
|
||||
for (ksub = 0; ksub < nseg; ksub++)
|
||||
{ // For each updating supernode
|
||||
|
||||
/* krep = representative of current k-th supernode
|
||||
* fsupc = first supernodal column
|
||||
* nsupc = number of columns in a supernode
|
||||
* nsupr = number of rows in a supernode
|
||||
*/
|
||||
krep = segrep(k); k--;
|
||||
fsupc = glu.xsup(glu.supno(krep));
|
||||
nsupc = krep - fsupc + 1;
|
||||
nsupr = glu.xlsub(fsupc+1) - glu.xlsub(fsupc);
|
||||
nrow = nsupr - nsupc;
|
||||
lptr = glu.xlsub(fsupc);
|
||||
|
||||
// loop over the panel columns to detect the actual number of columns and rows
|
||||
int u_rows = 0;
|
||||
int u_cols = 0;
|
||||
for (jj = jcol; jj < jcol + w; jj++)
|
||||
{
|
||||
nextl_col = (jj-jcol) * m;
|
||||
VectorBlock<IndexVector> repfnz_col(repfnz, nextl_col, m); // First nonzero column index for each row
|
||||
|
||||
kfnz = repfnz_col(krep);
|
||||
if ( kfnz == IND_EMPTY )
|
||||
continue; // skip any zero segment
|
||||
|
||||
segsize = krep - kfnz + 1;
|
||||
u_cols++;
|
||||
u_rows = (std::max)(segsize,u_rows);
|
||||
}
|
||||
|
||||
// if the blocks are large enough, use level 3
|
||||
// TODO find better heuristics!
|
||||
if( nsupc >= perfv.colblk && nrow > perfv.rowblk && u_cols>perfv.relax)
|
||||
{
|
||||
Map<Matrix<Scalar,Dynamic,Dynamic> > U(tempv.data(), u_rows, u_cols);
|
||||
|
||||
// gather U
|
||||
int u_col = 0;
|
||||
for (jj = jcol; jj < jcol + w; jj++)
|
||||
{
|
||||
nextl_col = (jj-jcol) * m;
|
||||
VectorBlock<IndexVector> repfnz_col(repfnz, nextl_col, m); // First nonzero column index for each row
|
||||
VectorBlock<ScalarVector> dense_col(dense, nextl_col, m); // Scatter/gather entire matrix column from/to here
|
||||
|
||||
kfnz = repfnz_col(krep);
|
||||
if ( kfnz == IND_EMPTY )
|
||||
continue; // skip any zero segment
|
||||
|
||||
segsize = krep - kfnz + 1;
|
||||
luptr = glu.xlusup(fsupc);
|
||||
no_zeros = kfnz - fsupc;
|
||||
|
||||
int isub = lptr + no_zeros;
|
||||
int off = u_rows-segsize;
|
||||
for (int i = 0; i < off; i++) U(i,u_col) = 0;
|
||||
for (int i = 0; i < segsize; i++)
|
||||
{
|
||||
int irow = glu.lsub(isub);
|
||||
U(i+off,u_col) = dense_col(irow);
|
||||
++isub;
|
||||
}
|
||||
u_col++;
|
||||
}
|
||||
// solve U = A^-1 U
|
||||
luptr = glu.xlusup(fsupc);
|
||||
no_zeros = (krep - u_rows + 1) - fsupc;
|
||||
luptr += nsupr * no_zeros + no_zeros;
|
||||
Map<Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > A(glu.lusup.data()+luptr, u_rows, u_rows, OuterStride<>(nsupr) );
|
||||
U = A.template triangularView<UnitLower>().solve(U);
|
||||
|
||||
// update
|
||||
luptr += u_rows;
|
||||
Map<Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > B(glu.lusup.data()+luptr, nrow, u_rows, OuterStride<>(nsupr) );
|
||||
assert(tempv.size()>w*u_rows + nrow*w);
|
||||
Map<Matrix<Scalar,Dynamic,Dynamic> > L(tempv.data()+w*u_rows, nrow, u_cols);
|
||||
L.noalias() = B * U;
|
||||
|
||||
// scatter U and L
|
||||
u_col = 0;
|
||||
for (jj = jcol; jj < jcol + w; jj++)
|
||||
{
|
||||
nextl_col = (jj-jcol) * m;
|
||||
VectorBlock<IndexVector> repfnz_col(repfnz, nextl_col, m); // First nonzero column index for each row
|
||||
VectorBlock<ScalarVector> dense_col(dense, nextl_col, m); // Scatter/gather entire matrix column from/to here
|
||||
|
||||
kfnz = repfnz_col(krep);
|
||||
if ( kfnz == IND_EMPTY )
|
||||
continue; // skip any zero segment
|
||||
|
||||
segsize = krep - kfnz + 1;
|
||||
no_zeros = kfnz - fsupc;
|
||||
int isub = lptr + no_zeros;
|
||||
|
||||
int off = u_rows-segsize;
|
||||
for (int i = 0; i < segsize; i++)
|
||||
{
|
||||
int irow = glu.lsub(isub++);
|
||||
dense_col(irow) = U.coeff(i+off,u_col);
|
||||
U.coeffRef(i+off,u_col) = 0;
|
||||
}
|
||||
|
||||
// Scatter l into SPA dense[]
|
||||
for (int i = 0; i < nrow; i++)
|
||||
{
|
||||
int irow = glu.lsub(isub++);
|
||||
dense_col(irow) -= L.coeff(i,u_col);
|
||||
L.coeffRef(i,u_col) = 0;
|
||||
}
|
||||
u_col++;
|
||||
}
|
||||
}
|
||||
else // level 2 only
|
||||
{
|
||||
// Sequence through each column in the panel
|
||||
for (jj = jcol; jj < jcol + w; jj++)
|
||||
{
|
||||
nextl_col = (jj-jcol) * m;
|
||||
VectorBlock<IndexVector> repfnz_col(repfnz, nextl_col, m); // First nonzero column index for each row
|
||||
VectorBlock<ScalarVector> dense_col(dense, nextl_col, m); // Scatter/gather entire matrix column from/to here
|
||||
|
||||
kfnz = repfnz_col(krep);
|
||||
if ( kfnz == IND_EMPTY )
|
||||
continue; // skip any zero segment
|
||||
|
||||
segsize = krep - kfnz + 1;
|
||||
luptr = glu.xlusup(fsupc);
|
||||
|
||||
// Perform a trianglar solve and block update,
|
||||
// then scatter the result of sup-col update to dense[]
|
||||
no_zeros = kfnz - fsupc;
|
||||
if(segsize==1) LU_kernel_bmod<1>::run(segsize, dense_col, tempv, glu.lusup, luptr, nsupr, nrow, glu.lsub, lptr, no_zeros);
|
||||
else if(segsize==2) LU_kernel_bmod<2>::run(segsize, dense_col, tempv, glu.lusup, luptr, nsupr, nrow, glu.lsub, lptr, no_zeros);
|
||||
else if(segsize==3) LU_kernel_bmod<3>::run(segsize, dense_col, tempv, glu.lusup, luptr, nsupr, nrow, glu.lsub, lptr, no_zeros);
|
||||
else LU_kernel_bmod<Dynamic>::run(segsize, dense_col, tempv, glu.lusup, luptr, nsupr, nrow, glu.lsub, lptr, no_zeros);
|
||||
} // End for each column in the panel
|
||||
}
|
||||
|
||||
} // End for each updating supernode
|
||||
}
|
||||
#endif
|
247
Eigen/src/SparseLU/SparseLU_panel_dfs.h
Normal file
247
Eigen/src/SparseLU/SparseLU_panel_dfs.h
Normal file
@ -0,0 +1,247 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
/*
|
||||
|
||||
* NOTE: This file is the modified version of [s,d,c,z]panel_dfs.c file in SuperLU
|
||||
|
||||
* -- SuperLU routine (version 2.0) --
|
||||
* Univ. of California Berkeley, Xerox Palo Alto Research Center,
|
||||
* and Lawrence Berkeley National Lab.
|
||||
* November 15, 1997
|
||||
*
|
||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
|
||||
* EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program for any
|
||||
* purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is
|
||||
* granted, provided the above notices are retained, and a notice that
|
||||
* the code was modified is included with the above copyright notice.
|
||||
*/
|
||||
#ifndef SPARSELU_PANEL_DFS_H
|
||||
#define SPARSELU_PANEL_DFS_H
|
||||
template <typename Scalar, typename Index>
|
||||
template <typename Traits>
|
||||
void SparseLUBase<Scalar,Index>::LU_dfs_kernel(const int jj, IndexVector& perm_r,
|
||||
int& nseg, IndexVector& panel_lsub, IndexVector& segrep,
|
||||
Ref<IndexVector> repfnz_col, IndexVector& xprune, Ref<IndexVector> marker, IndexVector& parent,
|
||||
IndexVector& xplore, GlobalLU_t& glu,
|
||||
int& nextl_col, int krow, Traits& traits
|
||||
)
|
||||
{
|
||||
|
||||
int kmark = marker(krow);
|
||||
|
||||
// For each unmarked krow of jj
|
||||
marker(krow) = jj;
|
||||
int kperm = perm_r(krow);
|
||||
if (kperm == IND_EMPTY ) {
|
||||
// krow is in L : place it in structure of L(*, jj)
|
||||
panel_lsub(nextl_col++) = krow; // krow is indexed into A
|
||||
|
||||
traits.mem_expand(panel_lsub, nextl_col, kmark);
|
||||
}
|
||||
else
|
||||
{
|
||||
// krow is in U : if its supernode-representative krep
|
||||
// has been explored, update repfnz(*)
|
||||
// krep = supernode representative of the current row
|
||||
int krep = glu.xsup(glu.supno(kperm)+1) - 1;
|
||||
// First nonzero element in the current column:
|
||||
int myfnz = repfnz_col(krep);
|
||||
|
||||
if (myfnz != IND_EMPTY )
|
||||
{
|
||||
// Representative visited before
|
||||
if (myfnz > kperm ) repfnz_col(krep) = kperm;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, perform dfs starting at krep
|
||||
int oldrep = IND_EMPTY;
|
||||
parent(krep) = oldrep;
|
||||
repfnz_col(krep) = kperm;
|
||||
int xdfs = glu.xlsub(krep);
|
||||
int maxdfs = xprune(krep);
|
||||
|
||||
int kpar;
|
||||
do
|
||||
{
|
||||
// For each unmarked kchild of krep
|
||||
while (xdfs < maxdfs)
|
||||
{
|
||||
int kchild = glu.lsub(xdfs);
|
||||
xdfs++;
|
||||
int chmark = marker(kchild);
|
||||
|
||||
if (chmark != jj )
|
||||
{
|
||||
marker(kchild) = jj;
|
||||
int chperm = perm_r(kchild);
|
||||
|
||||
if (chperm == IND_EMPTY)
|
||||
{
|
||||
// case kchild is in L: place it in L(*, j)
|
||||
panel_lsub(nextl_col++) = kchild;
|
||||
traits.mem_expand(panel_lsub, nextl_col, chmark);
|
||||
}
|
||||
else
|
||||
{
|
||||
// case kchild is in U :
|
||||
// chrep = its supernode-rep. If its rep has been explored,
|
||||
// update its repfnz(*)
|
||||
int chrep = glu.xsup(glu.supno(chperm)+1) - 1;
|
||||
myfnz = repfnz_col(chrep);
|
||||
|
||||
if (myfnz != IND_EMPTY)
|
||||
{ // Visited before
|
||||
if (myfnz > chperm)
|
||||
repfnz_col(chrep) = chperm;
|
||||
}
|
||||
else
|
||||
{ // Cont. dfs at snode-rep of kchild
|
||||
xplore(krep) = xdfs;
|
||||
oldrep = krep;
|
||||
krep = chrep; // Go deeper down G(L)
|
||||
parent(krep) = oldrep;
|
||||
repfnz_col(krep) = chperm;
|
||||
xdfs = glu.xlsub(krep);
|
||||
maxdfs = xprune(krep);
|
||||
|
||||
} // end if myfnz != -1
|
||||
} // end if chperm == -1
|
||||
|
||||
} // end if chmark !=jj
|
||||
} // end while xdfs < maxdfs
|
||||
|
||||
// krow has no more unexplored nbrs :
|
||||
// Place snode-rep krep in postorder DFS, if this
|
||||
// segment is seen for the first time. (Note that
|
||||
// "repfnz(krep)" may change later.)
|
||||
// Baktrack dfs to its parent
|
||||
if(traits.update_segrep(krep,jj))
|
||||
//if (marker1(krep) < jcol )
|
||||
{
|
||||
segrep(nseg) = krep;
|
||||
++nseg;
|
||||
//marker1(krep) = jj;
|
||||
}
|
||||
|
||||
kpar = parent(krep); // Pop recursion, mimic recursion
|
||||
if (kpar == IND_EMPTY)
|
||||
break; // dfs done
|
||||
krep = kpar;
|
||||
xdfs = xplore(krep);
|
||||
maxdfs = xprune(krep);
|
||||
|
||||
} while (kpar != IND_EMPTY); // Do until empty stack
|
||||
|
||||
} // end if (myfnz = -1)
|
||||
|
||||
} // end if (kperm == -1)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Performs a symbolic factorization on a panel of columns [jcol, jcol+w)
|
||||
*
|
||||
* A supernode representative is the last column of a supernode.
|
||||
* The nonzeros in U[*,j] are segments that end at supernodes representatives
|
||||
*
|
||||
* The routine returns a list of the supernodal representatives
|
||||
* in topological order of the dfs that generates them. This list is
|
||||
* a superset of the topological order of each individual column within
|
||||
* the panel.
|
||||
* The location of the first nonzero in each supernodal segment
|
||||
* (supernodal entry location) is also returned. Each column has
|
||||
* a separate list for this purpose.
|
||||
*
|
||||
* Two markers arrays are used for dfs :
|
||||
* marker[i] == jj, if i was visited during dfs of current column jj;
|
||||
* marker1[i] >= jcol, if i was visited by earlier columns in this panel;
|
||||
*
|
||||
* \param [in]m number of rows in the matrix
|
||||
* \param [in]w Panel size
|
||||
* \param [in]jcol Starting column of the panel
|
||||
* \param [in]A Input matrix in column-major storage
|
||||
* \param [in]perm_r Row permutation
|
||||
* \param [out]nseg Number of U segments
|
||||
* \param [out]dense Accumulate the column vectors of the panel
|
||||
* \param [out]panel_lsub Subscripts of the row in the panel
|
||||
* \param [out]segrep Segment representative i.e first nonzero row of each segment
|
||||
* \param [out]repfnz First nonzero location in each row
|
||||
* \param [out]xprune
|
||||
* \param [out]marker
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
template<typename IndexVector>
|
||||
struct LU_panel_dfs_traits
|
||||
{
|
||||
typedef typename IndexVector::Scalar Index;
|
||||
LU_panel_dfs_traits(Index jcol, Index* marker)
|
||||
: m_jcol(jcol), m_marker(marker)
|
||||
{}
|
||||
bool update_segrep(Index krep, Index jj)
|
||||
{
|
||||
if(m_marker[krep]<m_jcol)
|
||||
{
|
||||
m_marker[krep] = jj;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void mem_expand(IndexVector& /*glu.lsub*/, int /*nextl*/, int /*chmark*/) {}
|
||||
enum { ExpandMem = false };
|
||||
Index m_jcol;
|
||||
Index* m_marker;
|
||||
};
|
||||
|
||||
template <typename Scalar, typename Index>
|
||||
void SparseLUBase<Scalar,Index>::LU_panel_dfs(const int m, const int w, const int jcol, MatrixType& A, IndexVector& perm_r, int& nseg, ScalarVector& dense, IndexVector& panel_lsub, IndexVector& segrep, IndexVector& repfnz, IndexVector& xprune, IndexVector& marker, IndexVector& parent, IndexVector& xplore, GlobalLU_t& glu)
|
||||
{
|
||||
int nextl_col; // Next available position in panel_lsub[*,jj]
|
||||
|
||||
// Initialize pointers
|
||||
VectorBlock<IndexVector> marker1(marker, m, m);
|
||||
nseg = 0;
|
||||
|
||||
LU_panel_dfs_traits<IndexVector> traits(jcol, marker1.data());
|
||||
|
||||
// For each column in the panel
|
||||
for (int jj = jcol; jj < jcol + w; jj++)
|
||||
{
|
||||
nextl_col = (jj - jcol) * m;
|
||||
|
||||
VectorBlock<IndexVector> repfnz_col(repfnz, nextl_col, m); // First nonzero location in each row
|
||||
VectorBlock<ScalarVector> dense_col(dense,nextl_col, m); // Accumulate a column vector here
|
||||
|
||||
|
||||
// For each nnz in A[*, jj] do depth first search
|
||||
for (typename MatrixType::InnerIterator it(A, jj); it; ++it)
|
||||
{
|
||||
int krow = it.row();
|
||||
dense_col(krow) = it.value();
|
||||
|
||||
int kmark = marker(krow);
|
||||
if (kmark == jj)
|
||||
continue; // krow visited before, go to the next nonzero
|
||||
|
||||
LU_dfs_kernel(jj, perm_r, nseg, panel_lsub, segrep, repfnz_col, xprune, marker, parent,
|
||||
xplore, glu, nextl_col, krow, traits);
|
||||
}// end for nonzeros in column jj
|
||||
|
||||
} // end for column jj
|
||||
|
||||
}
|
||||
#endif
|
125
Eigen/src/SparseLU/SparseLU_pivotL.h
Normal file
125
Eigen/src/SparseLU/SparseLU_pivotL.h
Normal file
@ -0,0 +1,125 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
/*
|
||||
|
||||
* NOTE: This file is the modified version of xpivotL.c file in SuperLU
|
||||
|
||||
* -- SuperLU routine (version 3.0) --
|
||||
* Univ. of California Berkeley, Xerox Palo Alto Research Center,
|
||||
* and Lawrence Berkeley National Lab.
|
||||
* October 15, 2003
|
||||
*
|
||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
|
||||
* EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program for any
|
||||
* purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is
|
||||
* granted, provided the above notices are retained, and a notice that
|
||||
* the code was modified is included with the above copyright notice.
|
||||
*/
|
||||
#ifndef SPARSELU_PIVOTL_H
|
||||
#define SPARSELU_PIVOTL_H
|
||||
/**
|
||||
* \brief Performs the numerical pivotin on the current column of L, and the CDIV operation.
|
||||
*
|
||||
* Pivot policy :
|
||||
* (1) Compute thresh = u * max_(i>=j) abs(A_ij);
|
||||
* (2) IF user specifies pivot row k and abs(A_kj) >= thresh THEN
|
||||
* pivot row = k;
|
||||
* ELSE IF abs(A_jj) >= thresh THEN
|
||||
* pivot row = j;
|
||||
* ELSE
|
||||
* pivot row = m;
|
||||
*
|
||||
* Note: If you absolutely want to use a given pivot order, then set u=0.0.
|
||||
*
|
||||
* \param jcol The current column of L
|
||||
* \param u diagonal pivoting threshold
|
||||
* \param [in,out]perm_r Row permutation (threshold pivoting)
|
||||
* \param [in] iperm_c column permutation - used to finf diagonal of Pc*A*Pc'
|
||||
* \param [out]pivrow The pivot row
|
||||
* \param glu Global LU data
|
||||
* \return 0 if success, i > 0 if U(i,i) is exactly zero
|
||||
*
|
||||
*/
|
||||
template <typename Scalar, typename Index>
|
||||
int SparseLUBase<Scalar,Index>::LU_pivotL(const int jcol, const RealScalar diagpivotthresh, IndexVector& perm_r, IndexVector& iperm_c, int& pivrow, GlobalLU_t& glu)
|
||||
{
|
||||
|
||||
Index fsupc = (glu.xsup)((glu.supno)(jcol)); // First column in the supernode containing the column jcol
|
||||
Index nsupc = jcol - fsupc; // Number of columns in the supernode portion, excluding jcol; nsupc >=0
|
||||
Index lptr = glu.xlsub(fsupc); // pointer to the starting location of the row subscripts for this supernode portion
|
||||
Index nsupr = glu.xlsub(fsupc+1) - lptr; // Number of rows in the supernode
|
||||
Scalar* lu_sup_ptr = &(glu.lusup.data()[glu.xlusup(fsupc)]); // Start of the current supernode
|
||||
Scalar* lu_col_ptr = &(glu.lusup.data()[glu.xlusup(jcol)]); // Start of jcol in the supernode
|
||||
Index* lsub_ptr = &(glu.lsub.data()[lptr]); // Start of row indices of the supernode
|
||||
|
||||
// Determine the largest abs numerical value for partial pivoting
|
||||
Index diagind = iperm_c(jcol); // diagonal index
|
||||
RealScalar pivmax = 0.0;
|
||||
Index pivptr = nsupc;
|
||||
Index diag = IND_EMPTY;
|
||||
RealScalar rtemp;
|
||||
Index isub, icol, itemp, k;
|
||||
for (isub = nsupc; isub < nsupr; ++isub) {
|
||||
rtemp = std::abs(lu_col_ptr[isub]);
|
||||
if (rtemp > pivmax) {
|
||||
pivmax = rtemp;
|
||||
pivptr = isub;
|
||||
}
|
||||
if (lsub_ptr[isub] == diagind) diag = isub;
|
||||
}
|
||||
|
||||
// Test for singularity
|
||||
if ( pivmax == 0.0 ) {
|
||||
pivrow = lsub_ptr[pivptr];
|
||||
perm_r(pivrow) = jcol;
|
||||
return (jcol+1);
|
||||
}
|
||||
|
||||
RealScalar thresh = diagpivotthresh * pivmax;
|
||||
|
||||
// Choose appropriate pivotal element
|
||||
|
||||
{
|
||||
// Test if the diagonal element can be used as a pivot (given the threshold value)
|
||||
if (diag >= 0 )
|
||||
{
|
||||
// Diagonal element exists
|
||||
rtemp = std::abs(lu_col_ptr[diag]);
|
||||
if (rtemp != 0.0 && rtemp >= thresh) pivptr = diag;
|
||||
}
|
||||
pivrow = lsub_ptr[pivptr];
|
||||
}
|
||||
|
||||
// Record pivot row
|
||||
perm_r(pivrow) = jcol;
|
||||
// Interchange row subscripts
|
||||
if (pivptr != nsupc )
|
||||
{
|
||||
std::swap( lsub_ptr[pivptr], lsub_ptr[nsupc] );
|
||||
// Interchange numerical values as well, for the two rows in the whole snode
|
||||
// such that L is indexed the same way as A
|
||||
for (icol = 0; icol <= nsupc; icol++)
|
||||
{
|
||||
itemp = pivptr + icol * nsupr;
|
||||
std::swap(lu_sup_ptr[itemp], lu_sup_ptr[nsupc + icol * nsupr]);
|
||||
}
|
||||
}
|
||||
// cdiv operations
|
||||
Scalar temp = Scalar(1.0) / lu_col_ptr[nsupc];
|
||||
for (k = nsupc+1; k < nsupr; k++)
|
||||
lu_col_ptr[k] *= temp;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
129
Eigen/src/SparseLU/SparseLU_pruneL.h
Normal file
129
Eigen/src/SparseLU/SparseLU_pruneL.h
Normal file
@ -0,0 +1,129 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
/*
|
||||
|
||||
* NOTE: This file is the modified version of [s,d,c,z]pruneL.c file in SuperLU
|
||||
|
||||
* -- SuperLU routine (version 2.0) --
|
||||
* Univ. of California Berkeley, Xerox Palo Alto Research Center,
|
||||
* and Lawrence Berkeley National Lab.
|
||||
* November 15, 1997
|
||||
*
|
||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
|
||||
* EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program for any
|
||||
* purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is
|
||||
* granted, provided the above notices are retained, and a notice that
|
||||
* the code was modified is included with the above copyright notice.
|
||||
*/
|
||||
#ifndef SPARSELU_PRUNEL_H
|
||||
#define SPARSELU_PRUNEL_H
|
||||
|
||||
/**
|
||||
* \brief Prunes the L-structure.
|
||||
*
|
||||
* It prunes the L-structure of supernodes whose L-structure contains the current pivot row "pivrow"
|
||||
*
|
||||
*
|
||||
* \param jcol The current column of L
|
||||
* \param [in]perm_r Row permutation
|
||||
* \param [out]pivrow The pivot row
|
||||
* \param nseg Number of segments
|
||||
* \param segrep
|
||||
* \param repfnz
|
||||
* \param [out]xprune
|
||||
* \param glu Global LU data
|
||||
*
|
||||
*/
|
||||
template <typename Scalar, typename Index>
|
||||
void SparseLUBase<Scalar,Index>::LU_pruneL(const int jcol, const IndexVector& perm_r, const int pivrow, const int nseg, const IndexVector& segrep, BlockIndexVector& repfnz, IndexVector& xprune, GlobalLU_t& glu)
|
||||
{
|
||||
// For each supernode-rep irep in U(*,j]
|
||||
int jsupno = glu.supno(jcol);
|
||||
int i,irep,irep1;
|
||||
bool movnum, do_prune = false;
|
||||
Index kmin, kmax, minloc, maxloc,krow;
|
||||
for (i = 0; i < nseg; i++)
|
||||
{
|
||||
irep = segrep(i);
|
||||
irep1 = irep + 1;
|
||||
do_prune = false;
|
||||
|
||||
// Don't prune with a zero U-segment
|
||||
if (repfnz(irep) == IND_EMPTY) continue;
|
||||
|
||||
// If a snode overlaps with the next panel, then the U-segment
|
||||
// is fragmented into two parts -- irep and irep1. We should let
|
||||
// pruning occur at the rep-column in irep1s snode.
|
||||
if (glu.supno(irep) == glu.supno(irep1) ) continue; // don't prune
|
||||
|
||||
// If it has not been pruned & it has a nonz in row L(pivrow,i)
|
||||
if (glu.supno(irep) != jsupno )
|
||||
{
|
||||
if ( xprune (irep) >= glu.xlsub(irep1) )
|
||||
{
|
||||
kmin = glu.xlsub(irep);
|
||||
kmax = glu.xlsub(irep1) - 1;
|
||||
for (krow = kmin; krow <= kmax; krow++)
|
||||
{
|
||||
if (glu.lsub(krow) == pivrow)
|
||||
{
|
||||
do_prune = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (do_prune)
|
||||
{
|
||||
// do a quicksort-type partition
|
||||
// movnum=true means that the num values have to be exchanged
|
||||
movnum = false;
|
||||
if (irep == glu.xsup(glu.supno(irep)) ) // Snode of size 1
|
||||
movnum = true;
|
||||
|
||||
while (kmin <= kmax)
|
||||
{
|
||||
if (perm_r(glu.lsub(kmax)) == IND_EMPTY)
|
||||
kmax--;
|
||||
else if ( perm_r(glu.lsub(kmin)) != IND_EMPTY)
|
||||
kmin++;
|
||||
else
|
||||
{
|
||||
// kmin below pivrow (not yet pivoted), and kmax
|
||||
// above pivrow: interchange the two suscripts
|
||||
std::swap(glu.lsub(kmin), glu.lsub(kmax));
|
||||
|
||||
// If the supernode has only one column, then we
|
||||
// only keep one set of subscripts. For any subscript
|
||||
// intercnahge performed, similar interchange must be
|
||||
// done on the numerical values.
|
||||
if (movnum)
|
||||
{
|
||||
minloc = glu.xlusup(irep) + ( kmin - glu.xlsub(irep) );
|
||||
maxloc = glu.xlusup(irep) + ( kmax - glu.xlsub(irep) );
|
||||
std::swap(glu.lusup(minloc), glu.lusup(maxloc));
|
||||
}
|
||||
kmin++;
|
||||
kmax--;
|
||||
}
|
||||
} // end while
|
||||
|
||||
xprune(irep) = kmin; //Pruning
|
||||
} // end if do_prune
|
||||
} // end pruning
|
||||
} // End for each U-segment
|
||||
}
|
||||
|
||||
#endif
|
73
Eigen/src/SparseLU/SparseLU_relax_snode.h
Normal file
73
Eigen/src/SparseLU/SparseLU_relax_snode.h
Normal file
@ -0,0 +1,73 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
/* This file is a modified version of heap_relax_snode.c file in SuperLU
|
||||
* -- SuperLU routine (version 3.0) --
|
||||
* Univ. of California Berkeley, Xerox Palo Alto Research Center,
|
||||
* and Lawrence Berkeley National Lab.
|
||||
* October 15, 2003
|
||||
*
|
||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
|
||||
* EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program for any
|
||||
* purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is
|
||||
* granted, provided the above notices are retained, and a notice that
|
||||
* the code was modified is included with the above copyright notice.
|
||||
*/
|
||||
|
||||
#ifndef SPARSELU_RELAX_SNODE_H
|
||||
#define SPARSELU_RELAX_SNODE_H
|
||||
/**
|
||||
* \brief Identify the initial relaxed supernodes
|
||||
*
|
||||
* This routine is applied to a column elimination tree.
|
||||
* It assumes that the matrix has been reordered according to the postorder of the etree
|
||||
* \param et elimination tree
|
||||
* \param relax_columns Maximum number of columns allowed in a relaxed snode
|
||||
* \param descendants Number of descendants of each node in the etree
|
||||
* \param relax_end last column in a supernode
|
||||
*/
|
||||
template <typename Scalar, typename Index>
|
||||
void SparseLUBase<Scalar,Index>::LU_relax_snode (const int n, IndexVector& et, const int relax_columns, IndexVector& descendants, IndexVector& relax_end)
|
||||
{
|
||||
|
||||
// compute the number of descendants of each node in the etree
|
||||
int j, parent;
|
||||
relax_end.setConstant(IND_EMPTY);
|
||||
descendants.setZero();
|
||||
for (j = 0; j < n; j++)
|
||||
{
|
||||
parent = et(j);
|
||||
if (parent != n) // not the dummy root
|
||||
descendants(parent) += descendants(j) + 1;
|
||||
}
|
||||
// Identify the relaxed supernodes by postorder traversal of the etree
|
||||
int snode_start; // beginning of a snode
|
||||
for (j = 0; j < n; )
|
||||
{
|
||||
parent = et(j);
|
||||
snode_start = j;
|
||||
while ( parent != n && descendants(parent) < relax_columns )
|
||||
{
|
||||
j = parent;
|
||||
parent = et(j);
|
||||
}
|
||||
// Found a supernode in postordered etree, j is the last column
|
||||
relax_end(snode_start) = j; // Record last column
|
||||
j++;
|
||||
// Search for a new leaf
|
||||
while (descendants(j) != 0 && j < n) j++;
|
||||
} // End postorder traversal of the etree
|
||||
|
||||
}
|
||||
#endif
|
72
Eigen/src/SparseLU/SparseLU_snode_bmod.h
Normal file
72
Eigen/src/SparseLU/SparseLU_snode_bmod.h
Normal file
@ -0,0 +1,72 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
/*
|
||||
|
||||
* NOTE: This file is the modified version of [s,d,c,z]snode_bmod.c file in SuperLU
|
||||
|
||||
* -- SuperLU routine (version 3.0) --
|
||||
* Univ. of California Berkeley, Xerox Palo Alto Research Center,
|
||||
* and Lawrence Berkeley National Lab.
|
||||
* October 15, 2003
|
||||
*
|
||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
|
||||
* EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program for any
|
||||
* purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is
|
||||
* granted, provided the above notices are retained, and a notice that
|
||||
* the code was modified is included with the above copyright notice.
|
||||
*/
|
||||
#ifndef SPARSELU_SNODE_BMOD_H
|
||||
#define SPARSELU_SNODE_BMOD_H
|
||||
template <typename Scalar, typename Index>
|
||||
int SparseLUBase<Scalar,Index>::LU_snode_bmod (const int jcol, const int fsupc, ScalarVector& dense, GlobalLU_t& glu)
|
||||
{
|
||||
/* lsub : Compressed row subscripts of ( rectangular supernodes )
|
||||
* xlsub : xlsub[j] is the starting location of the j-th column in lsub(*)
|
||||
* lusup : Numerical values of the rectangular supernodes
|
||||
* xlusup[j] is the starting location of the j-th column in lusup(*)
|
||||
*/
|
||||
int nextlu = glu.xlusup(jcol); // Starting location of the next column to add
|
||||
int irow, isub;
|
||||
// Process the supernodal portion of L\U[*,jcol]
|
||||
for (isub = glu.xlsub(fsupc); isub < glu.xlsub(fsupc+1); isub++)
|
||||
{
|
||||
irow = glu.lsub(isub);
|
||||
glu.lusup(nextlu) = dense(irow);
|
||||
dense(irow) = 0;
|
||||
++nextlu;
|
||||
}
|
||||
glu.xlusup(jcol + 1) = nextlu; // Initialize xlusup for next column ( jcol+1 )
|
||||
|
||||
if (fsupc < jcol ){
|
||||
int luptr = glu.xlusup(fsupc); // points to the first column of the supernode
|
||||
int nsupr = glu.xlsub(fsupc + 1) -glu.xlsub(fsupc); //Number of rows in the supernode
|
||||
int nsupc = jcol - fsupc; // Number of columns in the supernodal portion of L\U[*,jcol]
|
||||
int ufirst = glu.xlusup(jcol); // points to the beginning of column jcol in supernode L\U(jsupno)
|
||||
|
||||
int nrow = nsupr - nsupc; // Number of rows in the off-diagonal blocks
|
||||
|
||||
// Solve the triangular system for U(fsupc:jcol, jcol) with L(fspuc:jcol, fsupc:jcol)
|
||||
Map<Matrix<Scalar,Dynamic,Dynamic>,0,OuterStride<> > A( &(glu.lusup.data()[luptr]), nsupc, nsupc, OuterStride<>(nsupr) );
|
||||
VectorBlock<ScalarVector> u(glu.lusup, ufirst, nsupc);
|
||||
u = A.template triangularView<UnitLower>().solve(u); // Call the Eigen dense triangular solve interface
|
||||
|
||||
// Update the trailing part of the column jcol U(jcol:jcol+nrow, jcol) using L(jcol:jcol+nrow, fsupc:jcol) and U(fsupc:jcol)
|
||||
new (&A) Map<Matrix<Scalar,Dynamic,Dynamic>,0,OuterStride<> > ( &(glu.lusup.data()[luptr+nsupc]), nrow, nsupc, OuterStride<>(nsupr) );
|
||||
VectorBlock<ScalarVector> l(glu.lusup, ufirst+nsupc, nrow);
|
||||
l.noalias() -= A * u;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
95
Eigen/src/SparseLU/SparseLU_snode_dfs.h
Normal file
95
Eigen/src/SparseLU/SparseLU_snode_dfs.h
Normal file
@ -0,0 +1,95 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
/*
|
||||
|
||||
* NOTE: This file is the modified version of [s,d,c,z]snode_dfs.c file in SuperLU
|
||||
|
||||
* -- SuperLU routine (version 2.0) --
|
||||
* Univ. of California Berkeley, Xerox Palo Alto Research Center,
|
||||
* and Lawrence Berkeley National Lab.
|
||||
* November 15, 1997
|
||||
*
|
||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
|
||||
* EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program for any
|
||||
* purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is
|
||||
* granted, provided the above notices are retained, and a notice that
|
||||
* the code was modified is included with the above copyright notice.
|
||||
*/
|
||||
#ifndef SPARSELU_SNODE_DFS_H
|
||||
#define SPARSELU_SNODE_DFS_H
|
||||
/**
|
||||
* \brief Determine the union of the row structures of those columns within the relaxed snode.
|
||||
* NOTE: The relaxed snodes are leaves of the supernodal etree, therefore,
|
||||
* the portion outside the rectangular supernode must be zero.
|
||||
*
|
||||
* \param jcol start of the supernode
|
||||
* \param kcol end of the supernode
|
||||
* \param asub Row indices
|
||||
* \param colptr Pointer to the beginning of each column
|
||||
* \param xprune (out) The pruned tree ??
|
||||
* \param marker (in/out) working vector
|
||||
* \return 0 on success, > 0 size of the memory when memory allocation failed
|
||||
*/
|
||||
template <typename Scalar, typename Index>
|
||||
int SparseLUBase<Scalar,Index>::LU_snode_dfs(const int jcol, const int kcol,const MatrixType& mat, IndexVector& xprune, IndexVector& marker, GlobalLU_t& glu)
|
||||
{
|
||||
int mem;
|
||||
Index nsuper = ++glu.supno(jcol); // Next available supernode number
|
||||
int nextl = glu.xlsub(jcol); //Index of the starting location of the jcol-th column in lsub
|
||||
int krow,kmark;
|
||||
for (int i = jcol; i <=kcol; i++)
|
||||
{
|
||||
// For each nonzero in A(*,i)
|
||||
for (typename MatrixType::InnerIterator it(mat, i); it; ++it)
|
||||
{
|
||||
krow = it.row();
|
||||
kmark = marker(krow);
|
||||
if ( kmark != kcol )
|
||||
{
|
||||
// First time to visit krow
|
||||
marker(krow) = kcol;
|
||||
glu.lsub(nextl++) = krow;
|
||||
if( nextl >= glu.nzlmax )
|
||||
{
|
||||
mem = LUMemXpand<IndexVector>(glu.lsub, glu.nzlmax, nextl, LSUB, glu.num_expansions);
|
||||
if (mem) return mem; // Memory expansion failed... Return the memory allocated so far
|
||||
}
|
||||
}
|
||||
}
|
||||
glu.supno(i) = nsuper;
|
||||
}
|
||||
|
||||
// If supernode > 1, then make a copy of the subscripts for pruning
|
||||
if (jcol < kcol)
|
||||
{
|
||||
Index new_next = nextl + (nextl - glu.xlsub(jcol));
|
||||
while (new_next > glu.nzlmax)
|
||||
{
|
||||
mem = LUMemXpand<IndexVector>(glu.lsub, glu.nzlmax, nextl, LSUB, glu.num_expansions);
|
||||
if (mem) return mem; // Memory expansion failed... Return the memory allocated so far
|
||||
}
|
||||
Index ifrom, ito = nextl;
|
||||
for (ifrom = glu.xlsub(jcol); ifrom < nextl;)
|
||||
glu.lsub(ito++) = glu.lsub(ifrom++);
|
||||
for (int i = jcol+1; i <=kcol; i++) glu.xlsub(i) = nextl;
|
||||
nextl = ito;
|
||||
}
|
||||
glu.xsup(nsuper+1) = kcol + 1; // Start of next available supernode
|
||||
glu.supno(kcol+1) = nsuper;
|
||||
xprune(kcol) = nextl;
|
||||
glu.xlsub(kcol+1) = nextl;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
@ -612,6 +612,7 @@ void SuperLU<MatrixType>::factorize(const MatrixType& a)
|
||||
|
||||
this->initFactorization(a);
|
||||
|
||||
m_sluOptions.ColPerm = COLAMD;
|
||||
int info = 0;
|
||||
RealScalar recip_pivot_growth, rcond;
|
||||
RealScalar ferr, berr;
|
||||
|
@ -33,7 +33,8 @@ EIGEN_MAKE_CWISE_BINARY_OP(min,internal::scalar_min_op)
|
||||
*
|
||||
* \sa max()
|
||||
*/
|
||||
EIGEN_STRONG_INLINE const CwiseBinaryOp<internal::scalar_min_op<Scalar>, const Derived, const ConstantReturnType>
|
||||
EIGEN_STRONG_INLINE const CwiseBinaryOp<internal::scalar_min_op<Scalar>, const Derived,
|
||||
const CwiseNullaryOp<internal::scalar_constant_op<Scalar>, PlainObject> >
|
||||
(min)(const Scalar &other) const
|
||||
{
|
||||
return (min)(Derived::PlainObject::Constant(rows(), cols(), other));
|
||||
@ -52,7 +53,8 @@ EIGEN_MAKE_CWISE_BINARY_OP(max,internal::scalar_max_op)
|
||||
*
|
||||
* \sa min()
|
||||
*/
|
||||
EIGEN_STRONG_INLINE const CwiseBinaryOp<internal::scalar_max_op<Scalar>, const Derived, const ConstantReturnType>
|
||||
EIGEN_STRONG_INLINE const CwiseBinaryOp<internal::scalar_max_op<Scalar>, const Derived,
|
||||
const CwiseNullaryOp<internal::scalar_constant_op<Scalar>, PlainObject> >
|
||||
(max)(const Scalar &other) const
|
||||
{
|
||||
return (max)(Derived::PlainObject::Constant(rows(), cols(), other));
|
||||
|
@ -200,3 +200,4 @@ EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator<=, std::less_equal)
|
||||
EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator>, std::greater)
|
||||
EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator>=, std::greater_equal)
|
||||
|
||||
|
||||
|
@ -55,6 +55,12 @@ if(PASTIX_FOUND AND BLAS_FOUND)
|
||||
set(PASTIX_ALL_LIBS ${PASTIX_LIBRARIES} ${BLAS_LIBRARIES})
|
||||
endif(PASTIX_FOUND AND BLAS_FOUND)
|
||||
|
||||
if(METIS_FOUND)
|
||||
include_directories(${METIS_INCLUDES})
|
||||
set (SPARSE_LIBS ${SPARSE_LIBS} ${METIS_LIBRARIES})
|
||||
add_definitions("-DEIGEN_METIS_SUPPORT")
|
||||
endif(METIS_FOUND)
|
||||
|
||||
find_library(RT_LIBRARY rt)
|
||||
if(RT_LIBRARY)
|
||||
set(SPARSE_LIBS ${SPARSE_LIBS} ${RT_LIBRARY})
|
||||
@ -63,3 +69,10 @@ endif(RT_LIBRARY)
|
||||
add_executable(spbenchsolver spbenchsolver.cpp)
|
||||
target_link_libraries (spbenchsolver ${SPARSE_LIBS})
|
||||
|
||||
add_executable(spsolver sp_solver.cpp)
|
||||
target_link_libraries (spsolver ${SPARSE_LIBS})
|
||||
|
||||
|
||||
add_executable(test_sparseLU test_sparseLU.cpp)
|
||||
target_link_libraries (test_sparseLU ${SPARSE_LIBS})
|
||||
|
||||
|
125
bench/spbench/sp_solver.cpp
Normal file
125
bench/spbench/sp_solver.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
// Small bench routine for Eigen available in Eigen
|
||||
// (C) Desire NUENTSA WAKAM, INRIA
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <Eigen/Jacobi>
|
||||
#include <Eigen/Householder>
|
||||
#include <Eigen/IterativeLinearSolvers>
|
||||
#include <Eigen/LU>
|
||||
#include <unsupported/Eigen/SparseExtra>
|
||||
//#include <Eigen/SparseLU>
|
||||
#include <Eigen/SuperLUSupport>
|
||||
// #include <unsupported/Eigen/src/IterativeSolvers/Scaling.h>
|
||||
#include <bench/BenchTimer.h>
|
||||
#include <unsupported/Eigen/IterativeSolvers>
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
|
||||
int main(int argc, char **args)
|
||||
{
|
||||
SparseMatrix<double, ColMajor> A;
|
||||
typedef SparseMatrix<double, ColMajor>::Index Index;
|
||||
typedef Matrix<double, Dynamic, Dynamic> DenseMatrix;
|
||||
typedef Matrix<double, Dynamic, 1> DenseRhs;
|
||||
VectorXd b, x, tmp;
|
||||
BenchTimer timer,totaltime;
|
||||
//SparseLU<SparseMatrix<double, ColMajor> > solver;
|
||||
// SuperLU<SparseMatrix<double, ColMajor> > solver;
|
||||
ConjugateGradient<SparseMatrix<double, ColMajor>, Lower,IncompleteCholesky<double,Lower> > solver;
|
||||
ifstream matrix_file;
|
||||
string line;
|
||||
int n;
|
||||
// Set parameters
|
||||
// solver.iparm(IPARM_THREAD_NBR) = 4;
|
||||
/* Fill the matrix with sparse matrix stored in Matrix-Market coordinate column-oriented format */
|
||||
if (argc < 2) assert(false && "please, give the matrix market file ");
|
||||
|
||||
timer.start();
|
||||
totaltime.start();
|
||||
loadMarket(A, args[1]);
|
||||
cout << "End charging matrix " << endl;
|
||||
bool iscomplex=false, isvector=false;
|
||||
int sym;
|
||||
getMarketHeader(args[1], sym, iscomplex, isvector);
|
||||
if (iscomplex) { cout<< " Not for complex matrices \n"; return -1; }
|
||||
if (isvector) { cout << "The provided file is not a matrix file\n"; return -1;}
|
||||
if (sym != 0) { // symmetric matrices, only the lower part is stored
|
||||
SparseMatrix<double, ColMajor> temp;
|
||||
temp = A;
|
||||
A = temp.selfadjointView<Lower>();
|
||||
}
|
||||
timer.stop();
|
||||
|
||||
n = A.cols();
|
||||
// ====== TESTS FOR SPARSE TUTORIAL ======
|
||||
// cout<< "OuterSize " << A.outerSize() << " inner " << A.innerSize() << endl;
|
||||
// SparseMatrix<double, RowMajor> mat1(A);
|
||||
// SparseMatrix<double, RowMajor> mat2;
|
||||
// cout << " norm of A " << mat1.norm() << endl; ;
|
||||
// PermutationMatrix<Dynamic, Dynamic, int> perm(n);
|
||||
// perm.resize(n,1);
|
||||
// perm.indices().setLinSpaced(n, 0, n-1);
|
||||
// mat2 = perm * mat1;
|
||||
// mat.subrows();
|
||||
// mat2.resize(n,n);
|
||||
// mat2.reserve(10);
|
||||
// mat2.setConstant();
|
||||
// std::cout<< "NORM " << mat1.squaredNorm()<< endl;
|
||||
|
||||
cout<< "Time to load the matrix " << timer.value() <<endl;
|
||||
/* Fill the right hand side */
|
||||
|
||||
// solver.set_restart(374);
|
||||
if (argc > 2)
|
||||
loadMarketVector(b, args[2]);
|
||||
else
|
||||
{
|
||||
b.resize(n);
|
||||
tmp.resize(n);
|
||||
// tmp.setRandom();
|
||||
for (int i = 0; i < n; i++) tmp(i) = i;
|
||||
b = A * tmp ;
|
||||
}
|
||||
// Scaling<SparseMatrix<double> > scal;
|
||||
// scal.computeRef(A);
|
||||
// b = scal.LeftScaling().cwiseProduct(b);
|
||||
|
||||
/* Compute the factorization */
|
||||
cout<< "Starting the factorization "<< endl;
|
||||
timer.reset();
|
||||
timer.start();
|
||||
cout<< "Size of Input Matrix "<< b.size()<<"\n\n";
|
||||
cout<< "Rows and columns "<< A.rows() <<" " <<A.cols() <<"\n";
|
||||
solver.compute(A);
|
||||
// solver.analyzePattern(A);
|
||||
// solver.factorize(A);
|
||||
if (solver.info() != Success) {
|
||||
std::cout<< "The solver failed \n";
|
||||
return -1;
|
||||
}
|
||||
timer.stop();
|
||||
float time_comp = timer.value();
|
||||
cout <<" Compute Time " << time_comp<< endl;
|
||||
|
||||
timer.reset();
|
||||
timer.start();
|
||||
x = solver.solve(b);
|
||||
// x = scal.RightScaling().cwiseProduct(x);
|
||||
timer.stop();
|
||||
float time_solve = timer.value();
|
||||
cout<< " Time to solve " << time_solve << endl;
|
||||
|
||||
/* Check the accuracy */
|
||||
VectorXd tmp2 = b - A*x;
|
||||
double tempNorm = tmp2.norm()/b.norm();
|
||||
cout << "Relative norm of the computed solution : " << tempNorm <<"\n";
|
||||
// cout << "Iterations : " << solver.iterations() << "\n";
|
||||
|
||||
totaltime.stop();
|
||||
cout << "Total time " << totaltime.value() << "\n";
|
||||
// std::cout<<x.transpose()<<"\n";
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
|
||||
|
||||
<!-- Desire Nuentsa, Inria -->
|
||||
|
||||
<xsl:output method="html" indent="no"/>
|
||||
|
||||
<xsl:template match="/"> <!-- Root of the document -->
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
td { white-space: nowrap;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table border="1" width="100%" height="100%">
|
||||
<TR> <!-- Write the table header -->
|
||||
<TH>Matrix</TH> <TH>N</TH> <TH> NNZ</TH> <TH> Sym</TH> <TH> SPD</TH> <TH> </TH>
|
||||
<xsl:for-each select="BENCH/AVAILSOLVER/SOLVER">
|
||||
<xsl:sort select="@ID" data-type="number"/>
|
||||
<TH>
|
||||
<xsl:value-of select="TYPE" />
|
||||
<xsl:text></xsl:text>
|
||||
<xsl:value-of select="PACKAGE" />
|
||||
<xsl:text></xsl:text>
|
||||
</TH>
|
||||
</xsl:for-each>
|
||||
</TR>
|
||||
|
||||
<xsl:for-each select="BENCH/LINEARSYSTEM">
|
||||
<TR> <!-- print statistics for one linear system-->
|
||||
<TH rowspan="4"> <xsl:value-of select="MATRIX/NAME" /> </TH>
|
||||
<TD rowspan="4"> <xsl:value-of select="MATRIX/SIZE" /> </TD>
|
||||
<TD rowspan="4"> <xsl:value-of select="MATRIX/ENTRIES" /> </TD>
|
||||
<TD rowspan="4"> <xsl:value-of select="MATRIX/SYMMETRY" /> </TD>
|
||||
<TD rowspan="4"> <xsl:value-of select="MATRIX/POSDEF" /> </TD>
|
||||
<TH> Compute Time </TH>
|
||||
<xsl:for-each select="SOLVER_STAT">
|
||||
<xsl:sort select="@ID" data-type="number"/>
|
||||
<TD> <xsl:value-of select="TIME/COMPUTE" /> </TD>
|
||||
</xsl:for-each>
|
||||
</TR>
|
||||
<TR>
|
||||
<TH> Solve Time </TH>
|
||||
<xsl:for-each select="SOLVER_STAT">
|
||||
<xsl:sort select="@ID" data-type="number"/>
|
||||
<TD> <xsl:value-of select="TIME/SOLVE" /> </TD>
|
||||
</xsl:for-each>
|
||||
</TR>
|
||||
<TR>
|
||||
<TH> Total Time </TH>
|
||||
<xsl:for-each select="SOLVER_STAT">
|
||||
<xsl:sort select="@ID" data-type="number"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="@ID=../BEST_SOLVER/@ID">
|
||||
<TD style="background-color:red"> <xsl:value-of select="TIME/TOTAL" /> </TD>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<TD> <xsl:value-of select="TIME/TOTAL" /></TD>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:for-each>
|
||||
</TR>
|
||||
<TR>
|
||||
<TH> Error </TH>
|
||||
<xsl:for-each select="SOLVER_STAT">
|
||||
<xsl:sort select="@ID" data-type="number"/>
|
||||
<TD> <xsl:value-of select="ERROR" />
|
||||
<xsl:if test="ITER">
|
||||
<xsl:text>(</xsl:text>
|
||||
<xsl:value-of select="ITER" />
|
||||
<xsl:text>)</xsl:text>
|
||||
</xsl:if> </TD>
|
||||
</xsl:for-each>
|
||||
</TR>
|
||||
</xsl:for-each>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
@ -14,7 +14,7 @@ void bench_printhelp()
|
||||
cout<< " OPTIONS : \n";
|
||||
cout<< " -h or --help \n print this help and return\n\n";
|
||||
cout<< " -d matrixdir \n Use matrixdir as the matrix folder instead of the one specified in the environment variable EIGEN_MATRIXDIR\n\n";
|
||||
cout<< " -o outputfile.html \n Output the statistics to a html file \n\n";
|
||||
cout<< " -o outputfile.xml \n Output the statistics to a xml file \n\n";
|
||||
cout<< " --eps <RelErr> Sets the relative tolerance for iterative solvers (default 1e-08) \n\n";
|
||||
cout<< " --maxits <MaxIts> Sets the maximum number of iterations (default 1000) \n\n";
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "Eigen/SparseCore"
|
||||
#include <Eigen/SparseCore>
|
||||
#include <bench/BenchTimer.h>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
@ -21,6 +21,13 @@
|
||||
#include <unsupported/Eigen/IterativeSolvers>
|
||||
#include <Eigen/LU>
|
||||
#include <unsupported/Eigen/SparseExtra>
|
||||
#include <Eigen/SparseLU>
|
||||
|
||||
#include "spbenchstyle.h"
|
||||
|
||||
#ifdef EIGEN_METIS_SUPPORT
|
||||
#include <Eigen/MetisSupport>
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_CHOLMOD_SUPPORT
|
||||
#include <Eigen/CholmodSupport>
|
||||
@ -43,26 +50,27 @@
|
||||
#endif
|
||||
|
||||
// CONSTANTS
|
||||
#define EIGEN_UMFPACK 0
|
||||
#define EIGEN_SUPERLU 1
|
||||
#define EIGEN_PASTIX 2
|
||||
#define EIGEN_PARDISO 3
|
||||
#define EIGEN_BICGSTAB 4
|
||||
#define EIGEN_BICGSTAB_ILUT 5
|
||||
#define EIGEN_GMRES 6
|
||||
#define EIGEN_GMRES_ILUT 7
|
||||
#define EIGEN_SIMPLICIAL_LDLT 8
|
||||
#define EIGEN_CHOLMOD_LDLT 9
|
||||
#define EIGEN_PASTIX_LDLT 10
|
||||
#define EIGEN_PARDISO_LDLT 11
|
||||
#define EIGEN_SIMPLICIAL_LLT 12
|
||||
#define EIGEN_CHOLMOD_SUPERNODAL_LLT 13
|
||||
#define EIGEN_CHOLMOD_SIMPLICIAL_LLT 14
|
||||
#define EIGEN_PASTIX_LLT 15
|
||||
#define EIGEN_PARDISO_LLT 16
|
||||
#define EIGEN_CG 17
|
||||
#define EIGEN_CG_PRECOND 18
|
||||
#define EIGEN_ALL_SOLVERS 19
|
||||
#define EIGEN_UMFPACK 10
|
||||
#define EIGEN_SUPERLU 20
|
||||
#define EIGEN_PASTIX 30
|
||||
#define EIGEN_PARDISO 40
|
||||
#define EIGEN_SPARSELU_COLAMD 50
|
||||
#define EIGEN_SPARSELU_METIS 51
|
||||
#define EIGEN_BICGSTAB 60
|
||||
#define EIGEN_BICGSTAB_ILUT 61
|
||||
#define EIGEN_GMRES 70
|
||||
#define EIGEN_GMRES_ILUT 71
|
||||
#define EIGEN_SIMPLICIAL_LDLT 80
|
||||
#define EIGEN_CHOLMOD_LDLT 90
|
||||
#define EIGEN_PASTIX_LDLT 100
|
||||
#define EIGEN_PARDISO_LDLT 110
|
||||
#define EIGEN_SIMPLICIAL_LLT 120
|
||||
#define EIGEN_CHOLMOD_SUPERNODAL_LLT 130
|
||||
#define EIGEN_CHOLMOD_SIMPLICIAL_LLT 140
|
||||
#define EIGEN_PASTIX_LLT 150
|
||||
#define EIGEN_PARDISO_LLT 160
|
||||
#define EIGEN_CG 170
|
||||
#define EIGEN_CG_PRECOND 180
|
||||
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
@ -85,107 +93,118 @@ void printStatheader(std::ofstream& out)
|
||||
// Print XML header
|
||||
// NOTE It would have been much easier to write these XML documents using external libraries like tinyXML or Xerces-C++.
|
||||
|
||||
out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n";
|
||||
out << "<?xml-stylesheet type=\"text/xsl\" href=\"spbench.xsl\" ?> \n";
|
||||
out << "<!DOCTYPE BENCH SYSTEM \"spbench.dtd\"> \n";
|
||||
out << "\n<!-- Generated by the Eigen library -->\n";
|
||||
out << "<?xml version='1.0' encoding='UTF-8'?> \n";
|
||||
out << "<?xml-stylesheet type='text/xsl' href='#stylesheet' ?> \n";
|
||||
out << "<!DOCTYPE BENCH [\n<!ATTLIST xsl:stylesheet\n id\t ID #REQUIRED>\n]>";
|
||||
out << "\n\n<!-- Generated by the Eigen library -->\n";
|
||||
|
||||
|
||||
// Write the root XML element
|
||||
out << "\n<BENCH> \n" ;
|
||||
out << "\n<BENCH> \n" ; //root XML element
|
||||
// Print the xsl style section
|
||||
printBenchStyle(out);
|
||||
// List all available solvers
|
||||
out << " <AVAILSOLVER> \n";
|
||||
#ifdef EIGEN_UMFPACK_SUPPORT
|
||||
out <<" <SOLVER ID=\"" << EIGEN_UMFPACK << "\">\n";
|
||||
out <<" <SOLVER ID='" << EIGEN_UMFPACK << "'>\n";
|
||||
out << " <TYPE> LU </TYPE> \n";
|
||||
out << " <PACKAGE> UMFPACK </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
#endif
|
||||
#ifdef EIGEN_SUPERLU_SUPPORT
|
||||
out <<" <SOLVER ID=\"" << EIGEN_SUPERLU << "\">\n";
|
||||
out <<" <SOLVER ID='" << EIGEN_SUPERLU << "'>\n";
|
||||
out << " <TYPE> LU </TYPE> \n";
|
||||
out << " <PACKAGE> SUPERLU </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
#endif
|
||||
#ifdef EIGEN_CHOLMOD_SUPPORT
|
||||
out <<" <SOLVER ID=\"" << EIGEN_CHOLMOD_SIMPLICIAL_LLT << "\">\n";
|
||||
out <<" <SOLVER ID='" << EIGEN_CHOLMOD_SIMPLICIAL_LLT << "'>\n";
|
||||
out << " <TYPE> LLT SP</TYPE> \n";
|
||||
out << " <PACKAGE> CHOLMOD </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
|
||||
out <<" <SOLVER ID=\"" << EIGEN_CHOLMOD_SUPERNODAL_LLT << "\">\n";
|
||||
out <<" <SOLVER ID='" << EIGEN_CHOLMOD_SUPERNODAL_LLT << "'>\n";
|
||||
out << " <TYPE> LLT</TYPE> \n";
|
||||
out << " <PACKAGE> CHOLMOD </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
|
||||
out <<" <SOLVER ID=\"" << EIGEN_CHOLMOD_LDLT << "\">\n";
|
||||
out <<" <SOLVER ID='" << EIGEN_CHOLMOD_LDLT << "'>\n";
|
||||
out << " <TYPE> LDLT </TYPE> \n";
|
||||
out << " <PACKAGE> CHOLMOD </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
#endif
|
||||
#ifdef EIGEN_PARDISO_SUPPORT
|
||||
out <<" <SOLVER ID=\"" << EIGEN_PARDISO << "\">\n";
|
||||
out <<" <SOLVER ID='" << EIGEN_PARDISO << "'>\n";
|
||||
out << " <TYPE> LU </TYPE> \n";
|
||||
out << " <PACKAGE> PARDISO </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
|
||||
out <<" <SOLVER ID=\"" << EIGEN_PARDISO_LLT << "\">\n";
|
||||
out <<" <SOLVER ID='" << EIGEN_PARDISO_LLT << "'>\n";
|
||||
out << " <TYPE> LLT </TYPE> \n";
|
||||
out << " <PACKAGE> PARDISO </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
|
||||
out <<" <SOLVER ID=\"" << EIGEN_PARDISO_LDLT << "\">\n";
|
||||
out <<" <SOLVER ID='" << EIGEN_PARDISO_LDLT << "'>\n";
|
||||
out << " <TYPE> LDLT </TYPE> \n";
|
||||
out << " <PACKAGE> PARDISO </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
#endif
|
||||
#ifdef EIGEN_PASTIX_SUPPORT
|
||||
out <<" <SOLVER ID=\"" << EIGEN_PASTIX << "\">\n";
|
||||
out <<" <SOLVER ID='" << EIGEN_PASTIX << "'>\n";
|
||||
out << " <TYPE> LU </TYPE> \n";
|
||||
out << " <PACKAGE> PASTIX </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
|
||||
out <<" <SOLVER ID=\"" << EIGEN_PASTIX_LLT << "\">\n";
|
||||
out <<" <SOLVER ID='" << EIGEN_PASTIX_LLT << "'>\n";
|
||||
out << " <TYPE> LLT </TYPE> \n";
|
||||
out << " <PACKAGE> PASTIX </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
|
||||
out <<" <SOLVER ID=\"" << EIGEN_PASTIX_LDLT << "\">\n";
|
||||
out <<" <SOLVER ID='" << EIGEN_PASTIX_LDLT << "'>\n";
|
||||
out << " <TYPE> LDLT </TYPE> \n";
|
||||
out << " <PACKAGE> PASTIX </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
#endif
|
||||
|
||||
out <<" <SOLVER ID=\"" << EIGEN_BICGSTAB << "\">\n";
|
||||
out <<" <SOLVER ID='" << EIGEN_BICGSTAB << "'>\n";
|
||||
out << " <TYPE> BICGSTAB </TYPE> \n";
|
||||
out << " <PACKAGE> EIGEN </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
|
||||
out <<" <SOLVER ID=\"" << EIGEN_BICGSTAB_ILUT << "\">\n";
|
||||
out <<" <SOLVER ID='" << EIGEN_BICGSTAB_ILUT << "'>\n";
|
||||
out << " <TYPE> BICGSTAB_ILUT </TYPE> \n";
|
||||
out << " <PACKAGE> EIGEN </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
|
||||
out <<" <SOLVER ID=\"" << EIGEN_GMRES_ILUT << "\">\n";
|
||||
out <<" <SOLVER ID='" << EIGEN_GMRES_ILUT << "'>\n";
|
||||
out << " <TYPE> GMRES_ILUT </TYPE> \n";
|
||||
out << " <PACKAGE> EIGEN </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
|
||||
out <<" <SOLVER ID=\"" << EIGEN_SIMPLICIAL_LDLT << "\">\n";
|
||||
out <<" <SOLVER ID='" << EIGEN_SIMPLICIAL_LDLT << "'>\n";
|
||||
out << " <TYPE> LDLT </TYPE> \n";
|
||||
out << " <PACKAGE> EIGEN </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
|
||||
out <<" <SOLVER ID=\"" << EIGEN_SIMPLICIAL_LLT << "\">\n";
|
||||
out <<" <SOLVER ID='" << EIGEN_SIMPLICIAL_LLT << "'>\n";
|
||||
out << " <TYPE> LLT </TYPE> \n";
|
||||
out << " <PACKAGE> EIGEN </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
|
||||
out <<" <SOLVER ID=\"" << EIGEN_CG << "\">\n";
|
||||
out <<" <SOLVER ID='" << EIGEN_CG << "'>\n";
|
||||
out << " <TYPE> CG </TYPE> \n";
|
||||
out << " <PACKAGE> EIGEN </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
|
||||
out <<" <SOLVER ID='" << EIGEN_SPARSELU_COLAMD << "'>\n";
|
||||
out << " <TYPE> LU_COLAMD </TYPE> \n";
|
||||
out << " <PACKAGE> EIGEN </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
|
||||
#ifdef EIGEN_METIS_SUPPORT
|
||||
out <<" <SOLVER ID='" << EIGEN_SPARSELU_METIS << "'>\n";
|
||||
out << " <TYPE> LU_METIS </TYPE> \n";
|
||||
out << " <PACKAGE> EIGEN </PACKAGE> \n";
|
||||
out << " </SOLVER> \n";
|
||||
#endif
|
||||
out << " </AVAILSOLVER> \n";
|
||||
|
||||
}
|
||||
@ -260,7 +279,7 @@ template<typename Solver, typename Scalar>
|
||||
void call_directsolver(Solver& solver, const int solver_id, const typename Solver::MatrixType& A, const Matrix<Scalar, Dynamic, 1>& b, const Matrix<Scalar, Dynamic, 1>& refX, std::string& statFile)
|
||||
{
|
||||
std::ofstream statbuf(statFile.c_str(), std::ios::app);
|
||||
statbuf << " <SOLVER_STAT ID=\"" << solver_id <<"\">\n";
|
||||
statbuf << " <SOLVER_STAT ID='" << solver_id <<"'>\n";
|
||||
call_solver(solver, solver_id, A, b, refX,statbuf);
|
||||
statbuf << " </SOLVER_STAT>\n";
|
||||
statbuf.close();
|
||||
@ -273,7 +292,7 @@ void call_itersolver(Solver &solver, const int solver_id, const typename Solver:
|
||||
solver.setMaxIterations(MaximumIters);
|
||||
|
||||
std::ofstream statbuf(statFile.c_str(), std::ios::app);
|
||||
statbuf << " <SOLVER_STAT ID=\"" << solver_id <<"\">\n";
|
||||
statbuf << " <SOLVER_STAT ID='" << solver_id <<"'>\n";
|
||||
call_solver(solver, solver_id, A, b, refX,statbuf);
|
||||
statbuf << " <ITER> "<< solver.iterations() << "</ITER>\n";
|
||||
statbuf << " </SOLVER_STAT>\n";
|
||||
@ -303,7 +322,6 @@ void SelectSolvers(const SparseMatrix<Scalar>&A, unsigned int sym, Matrix<Scalar
|
||||
cout << "\nSolving with SUPERLU ... \n";
|
||||
SuperLU<SpMat> solver;
|
||||
call_directsolver(solver, EIGEN_SUPERLU, A, b, refX,statFile);
|
||||
printStatItem(stat, best_time_id, best_time_val);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -324,8 +342,19 @@ void SelectSolvers(const SparseMatrix<Scalar>&A, unsigned int sym, Matrix<Scalar
|
||||
call_directsolver(solver, EIGEN_PARDISO, A, b, refX,statFile);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Eigen SparseLU METIS
|
||||
cout << "\n Solving with Sparse LU AND COLAMD ... \n";
|
||||
SparseLU<SpMat, COLAMDOrdering<int> > solver;
|
||||
call_directsolver(solver, EIGEN_SPARSELU_COLAMD, A, b, refX, statFile);
|
||||
// Eigen SparseLU METIS
|
||||
#ifdef EIGEN_METIS_SUPPORT
|
||||
{
|
||||
cout << "\n Solving with Sparse LU AND METIS ... \n";
|
||||
SparseLU<SpMat, MetisOrdering<int> > solver;
|
||||
call_directsolver(solver, EIGEN_SPARSELU_METIS, A, b, refX, statFile);
|
||||
}
|
||||
#endif
|
||||
|
||||
//BiCGSTAB
|
||||
{
|
||||
@ -448,7 +477,6 @@ void SelectSolvers(const SparseMatrix<Scalar>&A, unsigned int sym, Matrix<Scalar
|
||||
// cout << "\nSolving with CG and IdentityPreconditioner ... \n";
|
||||
// ConjugateGradient<SpMat, Lower, IdentityPreconditioner> solver;
|
||||
// call_itersolver(solver,EIGEN_CG_PRECOND, A, b, refX,statFile);
|
||||
// printStatItem(stat, best_time_id, best_time_val);
|
||||
// }
|
||||
} // End SPD matrices
|
||||
}
|
||||
@ -504,8 +532,8 @@ void Browse_Matrices(const string folder, bool statFileExists, std::string& stat
|
||||
if(statFileExists)
|
||||
{
|
||||
std::ofstream statbuf(statFile.c_str(), std::ios::app);
|
||||
statbuf << " <BEST_SOLVER ID=\""<< best_time_id
|
||||
<< "\"></BEST_SOLVER>\n";
|
||||
statbuf << " <BEST_SOLVER ID='"<< best_time_id
|
||||
<< "'></BEST_SOLVER>\n";
|
||||
statbuf << " </LINEARSYSTEM> \n";
|
||||
statbuf.close();
|
||||
}
|
||||
|
94
bench/spbench/spbenchstyle.h
Normal file
94
bench/spbench/spbenchstyle.h
Normal file
@ -0,0 +1,94 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef SPBENCHSTYLE_H
|
||||
#define SPBENCHSTYLE_H
|
||||
|
||||
void printBenchStyle(std::ofstream& out)
|
||||
{
|
||||
out << "<xsl:stylesheet id='stylesheet' version='1.0' \
|
||||
xmlns:xsl='http://www.w3.org/1999/XSL/Transform' >\n \
|
||||
<xsl:template match='xsl:stylesheet' />\n \
|
||||
<xsl:template match='/'> <!-- Root of the document -->\n \
|
||||
<html>\n \
|
||||
<head> \n \
|
||||
<style type='text/css'> \n \
|
||||
td { white-space: nowrap;}\n \
|
||||
</style>\n \
|
||||
</head>\n \
|
||||
<body>";
|
||||
out<<"<table border='1' width='100%' height='100%'>\n \
|
||||
<TR> <!-- Write the table header -->\n \
|
||||
<TH>Matrix</TH> <TH>N</TH> <TH> NNZ</TH> <TH> Sym</TH> <TH> SPD</TH> <TH> </TH>\n \
|
||||
<xsl:for-each select='BENCH/AVAILSOLVER/SOLVER'>\n \
|
||||
<xsl:sort select='@ID' data-type='number'/>\n \
|
||||
<TH>\n \
|
||||
<xsl:value-of select='TYPE' />\n \
|
||||
<xsl:text></xsl:text>\n \
|
||||
<xsl:value-of select='PACKAGE' />\n \
|
||||
<xsl:text></xsl:text>\n \
|
||||
</TH>\n \
|
||||
</xsl:for-each>\n \
|
||||
</TR>";
|
||||
|
||||
out<<" <xsl:for-each select='BENCH/LINEARSYSTEM'>\n \
|
||||
<TR> <!-- print statistics for one linear system-->\n \
|
||||
<TH rowspan='4'> <xsl:value-of select='MATRIX/NAME' /> </TH>\n \
|
||||
<TD rowspan='4'> <xsl:value-of select='MATRIX/SIZE' /> </TD>\n \
|
||||
<TD rowspan='4'> <xsl:value-of select='MATRIX/ENTRIES' /> </TD>\n \
|
||||
<TD rowspan='4'> <xsl:value-of select='MATRIX/SYMMETRY' /> </TD>\n \
|
||||
<TD rowspan='4'> <xsl:value-of select='MATRIX/POSDEF' /> </TD>\n \
|
||||
<TH> Compute Time </TH>\n \
|
||||
<xsl:for-each select='SOLVER_STAT'>\n \
|
||||
<xsl:sort select='@ID' data-type='number'/>\n \
|
||||
<TD> <xsl:value-of select='TIME/COMPUTE' /> </TD>\n \
|
||||
</xsl:for-each>\n \
|
||||
</TR>";
|
||||
out<<" <TR>\n \
|
||||
<TH> Solve Time </TH>\n \
|
||||
<xsl:for-each select='SOLVER_STAT'>\n \
|
||||
<xsl:sort select='@ID' data-type='number'/>\n \
|
||||
<TD> <xsl:value-of select='TIME/SOLVE' /> </TD>\n \
|
||||
</xsl:for-each>\n \
|
||||
</TR>\n \
|
||||
<TR>\n \
|
||||
<TH> Total Time </TH>\n \
|
||||
<xsl:for-each select='SOLVER_STAT'>\n \
|
||||
<xsl:sort select='@ID' data-type='number'/>\n \
|
||||
<xsl:choose>\n \
|
||||
<xsl:when test='@ID=../BEST_SOLVER/@ID'>\n \
|
||||
<TD style='background-color:red'> <xsl:value-of select='TIME/TOTAL' /> </TD>\n \
|
||||
</xsl:when>\n \
|
||||
<xsl:otherwise>\n \
|
||||
<TD> <xsl:value-of select='TIME/TOTAL' /></TD>\n \
|
||||
</xsl:otherwise>\n \
|
||||
</xsl:choose>\n \
|
||||
</xsl:for-each>\n \
|
||||
</TR>";
|
||||
out<<" <TR>\n \
|
||||
<TH> Error </TH>\n \
|
||||
<xsl:for-each select='SOLVER_STAT'>\n \
|
||||
<xsl:sort select='@ID' data-type='number'/>\n \
|
||||
<TD> <xsl:value-of select='ERROR' />\n \
|
||||
<xsl:if test='ITER'>\n \
|
||||
<xsl:text>(</xsl:text>\n \
|
||||
<xsl:value-of select='ITER' />\n \
|
||||
<xsl:text>)</xsl:text>\n \
|
||||
</xsl:if> </TD>\n \
|
||||
</xsl:for-each>\n \
|
||||
</TR>\n \
|
||||
</xsl:for-each>\n \
|
||||
</table>\n \
|
||||
</body>\n \
|
||||
</html>\n \
|
||||
</xsl:template>\n \
|
||||
</xsl:stylesheet>\n\n";
|
||||
|
||||
}
|
||||
#endif
|
93
bench/spbench/test_sparseLU.cpp
Normal file
93
bench/spbench/test_sparseLU.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
// Small bench routine for Eigen available in Eigen
|
||||
// (C) Desire NUENTSA WAKAM, INRIA
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <unsupported/Eigen/SparseExtra>
|
||||
#include <Eigen/SparseLU>
|
||||
#include <bench/BenchTimer.h>
|
||||
#ifdef EIGEN_METIS_SUPPORT
|
||||
#include <Eigen/MetisSupport>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
|
||||
int main(int argc, char **args)
|
||||
{
|
||||
// typedef complex<double> scalar;
|
||||
typedef double scalar;
|
||||
SparseMatrix<scalar, ColMajor> A;
|
||||
typedef SparseMatrix<scalar, ColMajor>::Index Index;
|
||||
typedef Matrix<scalar, Dynamic, Dynamic> DenseMatrix;
|
||||
typedef Matrix<scalar, Dynamic, 1> DenseRhs;
|
||||
Matrix<scalar, Dynamic, 1> b, x, tmp;
|
||||
// SparseLU<SparseMatrix<scalar, ColMajor>, AMDOrdering<int> > solver;
|
||||
// #ifdef EIGEN_METIS_SUPPORT
|
||||
// SparseLU<SparseMatrix<scalar, ColMajor>, MetisOrdering<int> > solver;
|
||||
// std::cout<< "ORDERING : METIS\n";
|
||||
// #else
|
||||
SparseLU<SparseMatrix<scalar, ColMajor>, COLAMDOrdering<int> > solver;
|
||||
std::cout<< "ORDERING : COLAMD\n";
|
||||
// #endif
|
||||
|
||||
ifstream matrix_file;
|
||||
string line;
|
||||
int n;
|
||||
BenchTimer timer;
|
||||
|
||||
// Set parameters
|
||||
/* Fill the matrix with sparse matrix stored in Matrix-Market coordinate column-oriented format */
|
||||
if (argc < 2) assert(false && "please, give the matrix market file ");
|
||||
loadMarket(A, args[1]);
|
||||
cout << "End charging matrix " << endl;
|
||||
bool iscomplex=false, isvector=false;
|
||||
int sym;
|
||||
getMarketHeader(args[1], sym, iscomplex, isvector);
|
||||
// if (iscomplex) { cout<< " Not for complex matrices \n"; return -1; }
|
||||
if (isvector) { cout << "The provided file is not a matrix file\n"; return -1;}
|
||||
if (sym != 0) { // symmetric matrices, only the lower part is stored
|
||||
SparseMatrix<scalar, ColMajor> temp;
|
||||
temp = A;
|
||||
A = temp.selfadjointView<Lower>();
|
||||
}
|
||||
n = A.cols();
|
||||
/* Fill the right hand side */
|
||||
|
||||
if (argc > 2)
|
||||
loadMarketVector(b, args[2]);
|
||||
else
|
||||
{
|
||||
b.resize(n);
|
||||
tmp.resize(n);
|
||||
// tmp.setRandom();
|
||||
for (int i = 0; i < n; i++) tmp(i) = i;
|
||||
b = A * tmp ;
|
||||
}
|
||||
|
||||
/* Compute the factorization */
|
||||
// solver.isSymmetric(true);
|
||||
timer.start();
|
||||
// solver.compute(A);
|
||||
solver.analyzePattern(A);
|
||||
timer.stop();
|
||||
cout << "Time to analyze " << timer.value() << std::endl;
|
||||
timer.reset();
|
||||
timer.start();
|
||||
solver.factorize(A);
|
||||
timer.stop();
|
||||
cout << "Factorize Time " << timer.value() << std::endl;
|
||||
timer.reset();
|
||||
timer.start();
|
||||
x = solver.solve(b);
|
||||
timer.stop();
|
||||
cout << "solve time " << timer.value() << std::endl;
|
||||
/* Check the accuracy */
|
||||
Matrix<scalar, Dynamic, 1> tmp2 = b - A*x;
|
||||
scalar tempNorm = tmp2.norm()/b.norm();
|
||||
cout << "Relative norm of the computed solution : " << tempNorm <<"\n";
|
||||
cout << "Number of nonzeros in the factor : " << solver.nnzL() + solver.nnzU() << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
@ -10,6 +10,9 @@
|
||||
#ifndef EIGEN_BLAS_COMMON_H
|
||||
#define EIGEN_BLAS_COMMON_H
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Jacobi>
|
||||
|
||||
#include <iostream>
|
||||
#include <complex>
|
||||
|
||||
@ -68,9 +71,6 @@ inline bool check_uplo(const char* uplo)
|
||||
return UPLO(*uplo)!=0xff;
|
||||
}
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Jacobi>
|
||||
|
||||
|
||||
namespace Eigen {
|
||||
#include "BandTriangularSolver.h"
|
||||
|
@ -12,10 +12,11 @@ find_path(METIS_INCLUDES
|
||||
${INCLUDE_INSTALL_DIR}
|
||||
PATH_SUFFIXES
|
||||
metis
|
||||
include
|
||||
)
|
||||
|
||||
|
||||
find_library(METIS_LIBRARIES metis PATHS $ENV{METISDIR} ${LIB_INSTALL_DIR})
|
||||
find_library(METIS_LIBRARIES metis PATHS $ENV{METISDIR} ${LIB_INSTALL_DIR} PATH_SUFFIXES lib)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(METIS DEFAULT_MSG
|
||||
|
@ -51,12 +51,12 @@ class EigenMatrixPrinter:
|
||||
template_params = m.split(',')
|
||||
template_params = map(lambda x:x.replace(" ", ""), template_params)
|
||||
|
||||
if template_params[1] == '-0x00000000000000001' or template_params[1] == '-0x000000001':
|
||||
if template_params[1] == '-0x00000000000000001' or template_params[1] == '-0x000000001' or template_params[1] == '-1':
|
||||
self.rows = val['m_storage']['m_rows']
|
||||
else:
|
||||
self.rows = int(template_params[1])
|
||||
|
||||
if template_params[2] == '-0x00000000000000001' or template_params[2] == '-0x000000001':
|
||||
if template_params[2] == '-0x00000000000000001' or template_params[2] == '-0x000000001' or template_params[2] == '-1':
|
||||
self.cols = val['m_storage']['m_cols']
|
||||
else:
|
||||
self.cols = int(template_params[2])
|
||||
|
@ -211,7 +211,7 @@ Here is a typical usage example:
|
||||
\code
|
||||
typedef Eigen::Triplet<double> T;
|
||||
std::vector<T> tripletList;
|
||||
triplets.reserve(estimation_of_entries);
|
||||
tripletList.reserve(estimation_of_entries);
|
||||
for(...)
|
||||
{
|
||||
// ...
|
||||
|
110
doc/I17_SparseLinearSystems.dox
Normal file
110
doc/I17_SparseLinearSystems.dox
Normal file
@ -0,0 +1,110 @@
|
||||
namespace Eigen {
|
||||
/** \page TopicSparseSystems Solving Sparse Linear Systems
|
||||
In Eigen, there are several methods available to solve linear systems when the coefficient matrix is sparse. Because of the special representation of this class of matrices, special care should be taken in order to get a good performance. See \ref TutorialSparse for a detailed introduction about sparse matrices in Eigen. In this page, we briefly present the main steps that are common to all the linear solvers in Eigen together with the main concepts behind them. Depending on the properties of the matrix, the desired accuracy, the end-user is able to tune these steps in order to improve the performance of its code. However, an impatient user does not need to know deeply what's hiding behind these steps: the last section presents a benchmark routine that can be easily used to get an insight on the performance of all the available solvers.
|
||||
|
||||
\b Table \b of \b contents \n
|
||||
- \ref TheSparseCompute
|
||||
- \ref TheSparseSolve
|
||||
- \ref BenchmarkRoutine
|
||||
|
||||
As summarized in \ref TutorialSparseDirectSolvers, there are many built-in solvers in Eigen as well as interface to external solvers libraries. All these solvers follow the same calling sequence. The basic steps are as follows :
|
||||
\code
|
||||
#include <Eigen/RequiredModuleName>
|
||||
// ...
|
||||
SparseMatrix<double> A;
|
||||
// fill A
|
||||
VectorXd b, x;
|
||||
// fill b
|
||||
// solve Ax = b
|
||||
SolverClassName<SparseMatrix<double> > solver;
|
||||
solver.compute(A);
|
||||
if(solver.info()!=Succeeded) {
|
||||
// decomposition failed
|
||||
return;
|
||||
}
|
||||
x = solver.solve(b);
|
||||
if(solver.info()!=Succeeded) {
|
||||
// solving failed
|
||||
return;
|
||||
}
|
||||
\endcode
|
||||
|
||||
\section TheSparseCompute The Compute Step
|
||||
In the compute() function, the matrix is generally factorized: LLT for self-adjoint matrices, LDLT for general hermitian matrices and LU for non hermitian matrices. These are the results of using direct solvers. For this class of solvers precisely, the compute step is further subdivided into analyzePattern() and factorize().
|
||||
|
||||
The goal of analyzePattern() is to reorder the nonzero elements of the matrix, such that the factorization step creates less fill-in. This step exploits only the structure of the matrix. Hence, the results of this step can be used for other linear systems where the matrix has the same structure. Note however that sometimes, some external solvers (like SuperLU) require that the values of the matrix are set in this step, for instance to equilibrate the rows and columns of the matrix. In this situation, the results of this step can note be used with other matrices.
|
||||
|
||||
Eigen provides a limited set of methods to reorder the matrix in this step, either built-in (COLAMD, AMD) or external (METIS). These methods are set in template parameter list of the solver :
|
||||
\code
|
||||
DirectSolverClassName<SparseMatrix<double>, OrderingMethod<IndexType> > solver;
|
||||
\endcode
|
||||
|
||||
See \link Ordering_Modules the Ordering module \endlink for the list of available methods and the associated options.
|
||||
|
||||
In factorize(), the factors of the coefficient matrix are computed. This step should be called each time the values of the matrix change. However, the structural pattern of the matrix should not change between multiple calls.
|
||||
|
||||
For iterative solvers, the compute step is used to eventually setup a preconditioner. Remember that, basically, the goal of the preconditioner is to speedup the convergence of an iterative method by solving a modified linear system where the coefficient matrix has more clustered eigenvalues. For real problems, an iterative solver should always be used with a preconditioner. In Eigen, a preconditioner is selected by simply adding it as a template parameter to the iterative solver object.
|
||||
\code
|
||||
IterativeSolverClassName<SparseMatrix<double>, PreconditionerName<SparseMatrix<double> > solver;
|
||||
\endcode
|
||||
The member function preconditioner() returns a read-write reference to the preconditioner
|
||||
to directly interact with it.
|
||||
|
||||
For instance, with the ILUT preconditioner, the incomplete factors L and U are computed in this step.
|
||||
See \link Sparse_modules the Sparse module \endlink for the list of available preconditioners in Eigen.
|
||||
\section TheSparseSolve The Solve step
|
||||
The solve() function computes the solution of the linear systems with one or many right hand sides.
|
||||
\code
|
||||
X = solver.solve(B);
|
||||
\endcode
|
||||
Here, B can be a vector or a matrix where the columns form the different right hand sides. The solve() function can be called several times as well, for instance When all the right hand sides are not available at once.
|
||||
\code
|
||||
x1 = solver.solve(b1);
|
||||
// Get the second right hand side b2
|
||||
x2 = solver.solve(b2);
|
||||
// ...
|
||||
\endcode
|
||||
For direct methods, the solution are computed at the machine precision. Sometimes, the solution need not be too accurate. In this case, the iterative methods are more suitable and the desired accuracy can be set before the solve step using setTolerance(). For all the available functions, please, refer to the documentation of the \link IterativeLinearSolvers_module Iterative solvers module \endlink.
|
||||
|
||||
\section BenchmarkRoutine
|
||||
Most of the time, all you need is to know how much time it will take to qolve your system, and hopefully, what is the most suitable solver. In Eigen, we provide a benchmark routine that can be used for this purpose. It is very easy to use. First, it should be activated at the configuration step with the flag TEST_REAL_CASES. Then, in bench/spbench, you can compile the routine by typing \b make \e spbenchsolver. You can then run it with --help option to get the list of all available options. Basically, the matrices to test should be in \link http://math.nist.gov/MatrixMarket/formats.html MatrixMarket Coordinate format \endlink, and the routine returns the statistics from all available solvers in Eigen.
|
||||
|
||||
The following table gives an example of XHTML statistics from several Eigen built-in and external solvers.
|
||||
<TABLE border="1">
|
||||
<TR><TH>Matrix <TH> N <TH> NNZ <TH> <TH > UMFPACK <TH > SUPERLU <TH > PASTIX LU <TH >BiCGSTAB <TH > BiCGSTAB+ILUT <TH >GMRES+ILUT<TH > LDLT <TH> CHOLMOD LDLT <TH > PASTIX LDLT <TH > LLT <TH > CHOLMOD SP LLT <TH > CHOLMOD LLT <TH > PASTIX LLT <TH> CG</TR>
|
||||
<TR><TH rowspan="4">vector_graphics <TD rowspan="4"> 12855 <TD rowspan="4"> 72069 <TH>Compute Time <TD>0.0254549<TD>0.0215677<TD>0.0701827<TD>0.000153388<TD>0.0140107<TD>0.0153709<TD>0.0101601<TD style="background-color:red">0.00930502<TD>0.0649689
|
||||
<TR><TH>Solve Time <TD>0.00337835<TD>0.000951826<TD>0.00484373<TD>0.0374886<TD>0.0046445<TD>0.00847754<TD>0.000541813<TD style="background-color:red">0.000293696<TD>0.00485376
|
||||
<TR><TH>Total Time <TD>0.0288333<TD>0.0225195<TD>0.0750265<TD>0.037642<TD>0.0186552<TD>0.0238484<TD>0.0107019<TD style="background-color:red">0.00959871<TD>0.0698227
|
||||
<TR><TH>Error(Iter) <TD> 1.299e-16 <TD> 2.04207e-16 <TD> 4.83393e-15 <TD> 3.94856e-11 (80) <TD> 1.03861e-12 (3) <TD> 5.81088e-14 (6) <TD> 1.97578e-16 <TD> 1.83927e-16 <TD> 4.24115e-15
|
||||
<TR><TH rowspan="4">poisson_SPD <TD rowspan="4"> 19788 <TD rowspan="4"> 308232 <TH>Compute Time <TD>0.425026<TD>1.82378<TD>0.617367<TD>0.000478921<TD>1.34001<TD>1.33471<TD>0.796419<TD>0.857573<TD>0.473007<TD>0.814826<TD style="background-color:red">0.184719<TD>0.861555<TD>0.470559<TD>0.000458188
|
||||
<TR><TH>Solve Time <TD>0.0280053<TD>0.0194402<TD>0.0268747<TD>0.249437<TD>0.0548444<TD>0.0926991<TD>0.00850204<TD>0.0053171<TD>0.0258932<TD>0.00874603<TD style="background-color:red">0.00578155<TD>0.00530361<TD>0.0248942<TD>0.239093
|
||||
<TR><TH>Total Time <TD>0.453031<TD>1.84322<TD>0.644241<TD>0.249916<TD>1.39486<TD>1.42741<TD>0.804921<TD>0.862891<TD>0.4989<TD>0.823572<TD style="background-color:red">0.190501<TD>0.866859<TD>0.495453<TD>0.239551
|
||||
<TR><TH>Error(Iter) <TD> 4.67146e-16 <TD> 1.068e-15 <TD> 1.3397e-15 <TD> 6.29233e-11 (201) <TD> 3.68527e-11 (6) <TD> 3.3168e-15 (16) <TD> 1.86376e-15 <TD> 1.31518e-16 <TD> 1.42593e-15 <TD> 3.45361e-15 <TD> 3.14575e-16 <TD> 2.21723e-15 <TD> 7.21058e-16 <TD> 9.06435e-12 (261)
|
||||
<TR><TH rowspan="4">sherman2 <TD rowspan="4"> 1080 <TD rowspan="4"> 23094 <TH>Compute Time <TD style="background-color:red">0.00631754<TD>0.015052<TD>0.0247514 <TD> -<TD>0.0214425<TD>0.0217988
|
||||
<TR><TH>Solve Time <TD style="background-color:red">0.000478424<TD>0.000337998<TD>0.0010291 <TD> -<TD>0.00243152<TD>0.00246152
|
||||
<TR><TH>Total Time <TD style="background-color:red">0.00679597<TD>0.01539<TD>0.0257805 <TD> -<TD>0.023874<TD>0.0242603
|
||||
<TR><TH>Error(Iter) <TD> 1.83099e-15 <TD> 8.19351e-15 <TD> 2.625e-14 <TD> 1.3678e+69 (1080) <TD> 4.1911e-12 (7) <TD> 5.0299e-13 (12)
|
||||
<TR><TH rowspan="4">bcsstk01_SPD <TD rowspan="4"> 48 <TD rowspan="4"> 400 <TH>Compute Time <TD>0.000169079<TD>0.00010789<TD>0.000572538<TD>1.425e-06<TD>9.1612e-05<TD>8.3985e-05<TD style="background-color:red">5.6489e-05<TD>7.0913e-05<TD>0.000468251<TD>5.7389e-05<TD>8.0212e-05<TD>5.8394e-05<TD>0.000463017<TD>1.333e-06
|
||||
<TR><TH>Solve Time <TD>1.2288e-05<TD>1.1124e-05<TD>0.000286387<TD>8.5896e-05<TD>1.6381e-05<TD>1.6984e-05<TD style="background-color:red">3.095e-06<TD>4.115e-06<TD>0.000325438<TD>3.504e-06<TD>7.369e-06<TD>3.454e-06<TD>0.000294095<TD>6.0516e-05
|
||||
<TR><TH>Total Time <TD>0.000181367<TD>0.000119014<TD>0.000858925<TD>8.7321e-05<TD>0.000107993<TD>0.000100969<TD style="background-color:red">5.9584e-05<TD>7.5028e-05<TD>0.000793689<TD>6.0893e-05<TD>8.7581e-05<TD>6.1848e-05<TD>0.000757112<TD>6.1849e-05
|
||||
<TR><TH>Error(Iter) <TD> 1.03474e-16 <TD> 2.23046e-16 <TD> 2.01273e-16 <TD> 4.87455e-07 (48) <TD> 1.03553e-16 (2) <TD> 3.55965e-16 (2) <TD> 2.48189e-16 <TD> 1.88808e-16 <TD> 1.97976e-16 <TD> 2.37248e-16 <TD> 1.82701e-16 <TD> 2.71474e-16 <TD> 2.11322e-16 <TD> 3.547e-09 (48)
|
||||
<TR><TH rowspan="4">sherman1 <TD rowspan="4"> 1000 <TD rowspan="4"> 3750 <TH>Compute Time <TD>0.00228805<TD>0.00209231<TD>0.00528268<TD>9.846e-06<TD>0.00163522<TD>0.00162155<TD>0.000789259<TD style="background-color:red">0.000804495<TD>0.00438269
|
||||
<TR><TH>Solve Time <TD>0.000213788<TD>9.7983e-05<TD>0.000938831<TD>0.00629835<TD>0.000361764<TD>0.00078794<TD>4.3989e-05<TD style="background-color:red">2.5331e-05<TD>0.000917166
|
||||
<TR><TH>Total Time <TD>0.00250184<TD>0.00219029<TD>0.00622151<TD>0.0063082<TD>0.00199698<TD>0.00240949<TD>0.000833248<TD style="background-color:red">0.000829826<TD>0.00529986
|
||||
<TR><TH>Error(Iter) <TD> 1.16839e-16 <TD> 2.25968e-16 <TD> 2.59116e-16 <TD> 3.76779e-11 (248) <TD> 4.13343e-11 (4) <TD> 2.22347e-14 (10) <TD> 2.05861e-16 <TD> 1.83555e-16 <TD> 1.02917e-15
|
||||
<TR><TH rowspan="4">young1c <TD rowspan="4"> 841 <TD rowspan="4"> 4089 <TH>Compute Time <TD>0.00235843<TD style="background-color:red">0.00217228<TD>0.00568075<TD>1.2735e-05<TD>0.00264866<TD>0.00258236
|
||||
<TR><TH>Solve Time <TD>0.000329599<TD style="background-color:red">0.000168634<TD>0.00080118<TD>0.0534738<TD>0.00187193<TD>0.00450211
|
||||
<TR><TH>Total Time <TD>0.00268803<TD style="background-color:red">0.00234091<TD>0.00648193<TD>0.0534865<TD>0.00452059<TD>0.00708447
|
||||
<TR><TH>Error(Iter) <TD> 1.27029e-16 <TD> 2.81321e-16 <TD> 5.0492e-15 <TD> 8.0507e-11 (706) <TD> 3.00447e-12 (8) <TD> 1.46532e-12 (16)
|
||||
<TR><TH rowspan="4">mhd1280b <TD rowspan="4"> 1280 <TD rowspan="4"> 22778 <TH>Compute Time <TD>0.00234898<TD>0.00207079<TD>0.00570918<TD>2.5976e-05<TD>0.00302563<TD>0.00298036<TD>0.00144525<TD style="background-color:red">0.000919922<TD>0.00426444
|
||||
<TR><TH>Solve Time <TD>0.00103392<TD>0.000211911<TD>0.00105<TD>0.0110432<TD>0.000628287<TD>0.00392089<TD>0.000138303<TD style="background-color:red">6.2446e-05<TD>0.00097564
|
||||
<TR><TH>Total Time <TD>0.0033829<TD>0.0022827<TD>0.00675918<TD>0.0110692<TD>0.00365392<TD>0.00690124<TD>0.00158355<TD style="background-color:red">0.000982368<TD>0.00524008
|
||||
<TR><TH>Error(Iter) <TD> 1.32953e-16 <TD> 3.08646e-16 <TD> 6.734e-16 <TD> 8.83132e-11 (40) <TD> 1.51153e-16 (1) <TD> 6.08556e-16 (8) <TD> 1.89264e-16 <TD> 1.97477e-16 <TD> 6.68126e-09
|
||||
<TR><TH rowspan="4">crashbasis <TD rowspan="4"> 160000 <TD rowspan="4"> 1750416 <TH>Compute Time <TD>3.2019<TD>5.7892<TD>15.7573<TD style="background-color:red">0.00383515<TD>3.1006<TD>3.09921
|
||||
<TR><TH>Solve Time <TD>0.261915<TD>0.106225<TD>0.402141<TD style="background-color:red">1.49089<TD>0.24888<TD>0.443673
|
||||
<TR><TH>Total Time <TD>3.46381<TD>5.89542<TD>16.1594<TD style="background-color:red">1.49473<TD>3.34948<TD>3.54288
|
||||
<TR><TH>Error(Iter) <TD> 1.76348e-16 <TD> 4.58395e-16 <TD> 1.67982e-14 <TD> 8.64144e-11 (61) <TD> 8.5996e-12 (2) <TD> 6.04042e-14 (5)
|
||||
|
||||
</TABLE>
|
||||
*/
|
||||
}
|
@ -205,7 +205,7 @@ ei_add_test(vectorwiseop)
|
||||
ei_add_test(simplicial_cholesky)
|
||||
ei_add_test(conjugate_gradient)
|
||||
ei_add_test(bicgstab)
|
||||
|
||||
ei_add_test(sparselu)
|
||||
|
||||
if(UMFPACK_FOUND)
|
||||
ei_add_test(umfpack_support "" "${UMFPACK_ALL_LIBS}")
|
||||
|
@ -168,6 +168,12 @@ template<typename MatrixType> void cwise_min_max(const MatrixType& m)
|
||||
VERIFY_IS_APPROX(MatrixType::Constant(rows,cols, maxM1), m1.cwiseMax( maxM1));
|
||||
VERIFY_IS_APPROX(m1, m1.cwiseMax( minM1));
|
||||
|
||||
VERIFY_IS_APPROX(MatrixType::Constant(rows,cols, minM1).array(), (m1.array().min)( minM1));
|
||||
VERIFY_IS_APPROX(m1.array(), (m1.array().min)( maxM1));
|
||||
|
||||
VERIFY_IS_APPROX(MatrixType::Constant(rows,cols, maxM1).array(), (m1.array().max)( maxM1));
|
||||
VERIFY_IS_APPROX(m1.array(), (m1.array().max)( minM1));
|
||||
|
||||
}
|
||||
|
||||
template<typename MatrixTraits> void resize(const MatrixTraits& t)
|
||||
|
@ -32,6 +32,8 @@ template<typename MatrixType> void diagonalmatrices(const MatrixType& m)
|
||||
rv2 = RowVectorType::Random(cols);
|
||||
LeftDiagonalMatrix ldm1(v1), ldm2(v2);
|
||||
RightDiagonalMatrix rdm1(rv1), rdm2(rv2);
|
||||
|
||||
Scalar s1 = internal::random<Scalar>();
|
||||
|
||||
SquareMatrixType sq_m1 (v1.asDiagonal());
|
||||
VERIFY_IS_APPROX(sq_m1, v1.asDiagonal().toDenseMatrix());
|
||||
@ -76,6 +78,13 @@ template<typename MatrixType> void diagonalmatrices(const MatrixType& m)
|
||||
big.block(i,j,rows,cols) = big.block(i,j,rows,cols) * rv1.asDiagonal();
|
||||
VERIFY_IS_APPROX((big.block(i,j,rows,cols)) , m1 * rv1.asDiagonal() );
|
||||
|
||||
|
||||
// scalar multiple
|
||||
VERIFY_IS_APPROX(LeftDiagonalMatrix(ldm1*s1).diagonal(), ldm1.diagonal() * s1);
|
||||
VERIFY_IS_APPROX(LeftDiagonalMatrix(s1*ldm1).diagonal(), s1 * ldm1.diagonal());
|
||||
|
||||
VERIFY_IS_APPROX(m1 * (rdm1 * s1), (m1 * rdm1) * s1);
|
||||
VERIFY_IS_APPROX(m1 * (s1 * rdm1), (m1 * rdm1) * s1);
|
||||
}
|
||||
|
||||
void test_diagonalmatrices()
|
||||
|
@ -158,9 +158,9 @@ inline std::string get_matrixfolder()
|
||||
{
|
||||
std::string mat_folder = TEST_REAL_CASES;
|
||||
if( internal::is_same<Scalar, std::complex<float> >::value || internal::is_same<Scalar, std::complex<double> >::value )
|
||||
mat_folder = mat_folder + static_cast<string>("/complex/");
|
||||
mat_folder = mat_folder + static_cast<std::string>("/complex/");
|
||||
else
|
||||
mat_folder = mat_folder + static_cast<string>("/real/");
|
||||
mat_folder = mat_folder + static_cast<std::string>("/real/");
|
||||
return mat_folder;
|
||||
}
|
||||
#endif
|
||||
|
43
test/sparselu.cpp
Normal file
43
test/sparselu.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// Eigen 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.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen 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 or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "sparse_solver.h"
|
||||
#include <Eigen/SparseLU>
|
||||
#include <unsupported/Eigen/SparseExtra>
|
||||
|
||||
template<typename T> void test_sparselu_T()
|
||||
{
|
||||
SparseLU<SparseMatrix<T, ColMajor>, COLAMDOrdering<int> > sparselu_colamd;
|
||||
SparseLU<SparseMatrix<T, ColMajor>, AMDOrdering<int> > sparselu_amd;
|
||||
|
||||
check_sparse_square_solving(sparselu_colamd);
|
||||
check_sparse_square_solving(sparselu_amd);
|
||||
}
|
||||
|
||||
void test_sparselu()
|
||||
{
|
||||
CALL_SUBTEST_1(test_sparselu_T<float>());
|
||||
CALL_SUBTEST_2(test_sparselu_T<double>());
|
||||
CALL_SUBTEST_3(test_sparselu_T<std::complex<float> >());
|
||||
CALL_SUBTEST_4(test_sparselu_T<std::complex<double> >());
|
||||
}
|
@ -33,6 +33,7 @@
|
||||
#include "../../Eigen/Jacobi"
|
||||
#include "../../Eigen/Householder"
|
||||
#include "src/IterativeSolvers/GMRES.h"
|
||||
#include "src/IterativeSolvers/IncompleteCholesky.h"
|
||||
//#include "src/IterativeSolvers/SSORPreconditioner.h"
|
||||
|
||||
//@}
|
||||
|
221
unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h
Normal file
221
unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h
Normal file
@ -0,0 +1,221 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_INCOMPLETE_CHOlESKY_H
|
||||
#define EIGEN_INCOMPLETE_CHOlESKY_H
|
||||
#include "Eigen/src/IterativeLinearSolvers/IncompleteLUT.h"
|
||||
#include <Eigen/OrderingMethods>
|
||||
#include <list>
|
||||
|
||||
namespace Eigen {
|
||||
/**
|
||||
* \brief Modified Incomplete Cholesky with dual threshold
|
||||
*
|
||||
* References : C-J. Lin and J. J. Moré, Incomplete Cholesky Factorizations with
|
||||
* Limited memory, SIAM J. Sci. Comput. 21(1), pp. 24-45, 1999
|
||||
*
|
||||
* \tparam _MatrixType The type of the sparse matrix. It should be a symmetric
|
||||
* matrix. It is advised to give a row-oriented sparse matrix
|
||||
* \tparam _UpLo The triangular part of the matrix to reference.
|
||||
* \tparam _OrderingType
|
||||
*/
|
||||
|
||||
template <typename Scalar, int _UpLo = Lower, typename _OrderingType = NaturalOrdering<int> >
|
||||
class IncompleteCholesky : internal::noncopyable
|
||||
{
|
||||
public:
|
||||
typedef SparseMatrix<Scalar,ColMajor> MatrixType;
|
||||
typedef _OrderingType OrderingType;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
typedef typename MatrixType::Index Index;
|
||||
typedef PermutationMatrix<Dynamic, Dynamic, Index> PermutationType;
|
||||
typedef Matrix<Scalar,Dynamic,1> VectorType;
|
||||
typedef Matrix<Index,Dynamic, 1> IndexType;
|
||||
|
||||
public:
|
||||
IncompleteCholesky() {}
|
||||
IncompleteCholesky(const MatrixType& matrix)
|
||||
{
|
||||
compute(matrix);
|
||||
}
|
||||
|
||||
Index rows() const { return m_L.rows(); }
|
||||
|
||||
Index cols() const { return m_L.cols(); }
|
||||
|
||||
|
||||
/** \brief Reports whether previous computation was successful.
|
||||
*
|
||||
* \returns \c Success if computation was succesful,
|
||||
* \c NumericalIssue if the matrix appears to be negative.
|
||||
*/
|
||||
ComputationInfo info() const
|
||||
{
|
||||
eigen_assert(m_isInitialized && "IncompleteLLT is not initialized.");
|
||||
return m_info;
|
||||
}
|
||||
/**
|
||||
* \brief Computes the fill reducing permutation vector.
|
||||
*/
|
||||
template<typename MatrixType>
|
||||
void analyzePattern(const MatrixType& mat)
|
||||
{
|
||||
OrderingType ord;
|
||||
ord(mat, m_perm);
|
||||
m_analysisIsOk = true;
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
void factorize(const MatrixType& amat);
|
||||
|
||||
template<typename MatrixType>
|
||||
void compute (const MatrixType& matrix)
|
||||
{
|
||||
analyzePattern(matrix);
|
||||
factorize(matrix);
|
||||
}
|
||||
|
||||
template<typename Rhs, typename Dest>
|
||||
void _solve(const Rhs& b, Dest& x) const
|
||||
{
|
||||
eigen_assert(m_factorizationIsOk && "factorize() should be called first");
|
||||
if (m_perm.rows() == b.rows())
|
||||
x = m_perm.inverse() * b;
|
||||
else
|
||||
x = b;
|
||||
x = m_L.template triangularView<UnitLower>().solve(x);
|
||||
x = m_L.adjoint().template triangularView<Upper>().solve(x);
|
||||
if (m_perm.rows() == b.rows())
|
||||
x = m_perm * x;
|
||||
}
|
||||
template<typename Rhs> inline const internal::solve_retval<IncompleteCholesky, Rhs>
|
||||
solve(const MatrixBase<Rhs>& b) const
|
||||
{
|
||||
eigen_assert(m_isInitialized && "IncompleteLLT is not initialized.");
|
||||
eigen_assert(cols()==b.rows()
|
||||
&& "IncompleteLLT::solve(): invalid number of rows of the right hand side matrix b");
|
||||
return internal::solve_retval<IncompleteCholesky, Rhs>(*this, b.derived());
|
||||
}
|
||||
protected:
|
||||
SparseMatrix<Scalar,ColMajor> m_L; // The lower part stored in CSC
|
||||
bool m_analysisIsOk;
|
||||
bool m_factorizationIsOk;
|
||||
bool m_isInitialized;
|
||||
ComputationInfo m_info;
|
||||
PermutationType m_perm;
|
||||
|
||||
};
|
||||
|
||||
template<typename Scalar, int _UpLo, typename OrderingType>
|
||||
template<typename _MatrixType>
|
||||
void IncompleteCholesky<Scalar,_UpLo, OrderingType>::factorize(const _MatrixType& mat)
|
||||
{
|
||||
eigen_assert(m_analysisIsOk && "analyzePattern() should be called first");
|
||||
|
||||
// FIXME Stability: We should probably compute the scaling factors and the shifts that are needed to ensure a succesful LLT factorization and an efficient preconditioner.
|
||||
|
||||
// Dropping strategies : Keep only the p largest elements per column, where p is the number of elements in the column of the original matrix. Other strategies will be added
|
||||
|
||||
// Apply the fill-reducing permutation computed in analyzePattern()
|
||||
if (m_perm.rows() == mat.rows() )
|
||||
m_L.template selfadjointView<Lower>() = mat.template selfadjointView<_UpLo>().twistedBy(m_perm);
|
||||
else
|
||||
m_L.template selfadjointView<Lower>() = mat.template selfadjointView<_UpLo>();
|
||||
|
||||
int n = mat.cols();
|
||||
|
||||
Scalar *vals = m_L.valuePtr(); //Values
|
||||
Index *rowIdx = m_L.innerIndexPtr(); //Row indices
|
||||
Index *colPtr = m_L.outerIndexPtr(); // Pointer to the beginning of each row
|
||||
VectorType firstElt(n-1); // for each j, points to the next entry in vals that will be used in the factorization
|
||||
// Initialize firstElt;
|
||||
for (int j = 0; j < n-1; j++) firstElt(j) = colPtr[j]+1;
|
||||
std::vector<std::list<Index> > listCol(n); // listCol(j) is a linked list of columns to update column j
|
||||
VectorType curCol(n); // Store a nonzero values in each column
|
||||
VectorType irow(n); // Row indices of nonzero elements in each column
|
||||
// jki version of the Cholesky factorization
|
||||
for (int j=0; j < n; j++)
|
||||
{
|
||||
//Left-looking factorize the column j
|
||||
// First, load the jth column into curCol
|
||||
Scalar diag = vals[colPtr[j]]; // Lower diagonal matrix with
|
||||
curCol.setZero();
|
||||
irow.setLinSpaced(n,0,n-1);
|
||||
for (int i = colPtr[j] + 1; i < colPtr[j+1]; i++)
|
||||
{
|
||||
curCol(rowIdx[i]) = vals[i];
|
||||
irow(rowIdx[i]) = rowIdx[i];
|
||||
}
|
||||
|
||||
std::list<int>::iterator k;
|
||||
// Browse all previous columns that will update column j
|
||||
for(k = listCol[j].begin(); k != listCol[j].end(); k++)
|
||||
{
|
||||
int jk = firstElt(*k); // First element to use in the column
|
||||
Scalar a_jk = vals[jk];
|
||||
diag -= a_jk * a_jk;
|
||||
jk += 1;
|
||||
for (int i = jk; i < colPtr[*k]; i++)
|
||||
{
|
||||
curCol(rowIdx[i]) -= vals[i] * a_jk ;
|
||||
}
|
||||
firstElt(*k) = jk;
|
||||
if (jk < colPtr[*k+1])
|
||||
{
|
||||
// Add this column to the updating columns list for column *k+1
|
||||
listCol[rowIdx[jk]].push_back(*k);
|
||||
}
|
||||
}
|
||||
|
||||
// Select the largest p elements
|
||||
// p is the original number of elements in the column (without the diagonal)
|
||||
int p = colPtr[j+1] - colPtr[j] - 2 ;
|
||||
internal::QuickSplit(curCol, irow, p);
|
||||
if(RealScalar(diag) <= 0)
|
||||
{ //FIXME We can use heuristics (Kershaw, 1978 or above reference ) to get a dynamic shift
|
||||
m_info = NumericalIssue;
|
||||
return;
|
||||
}
|
||||
RealScalar rdiag = internal::sqrt(RealScalar(diag));
|
||||
Scalar scal = Scalar(1)/rdiag;
|
||||
vals[colPtr[j]] = rdiag;
|
||||
// Insert the largest p elements in the matrix and scale them meanwhile
|
||||
int cpt = 0;
|
||||
for (int i = colPtr[j]+1; i < colPtr[j+1]; i++)
|
||||
{
|
||||
vals[i] = curCol(cpt) * scal;
|
||||
rowIdx[i] = irow(cpt);
|
||||
cpt ++;
|
||||
}
|
||||
}
|
||||
m_factorizationIsOk = true;
|
||||
m_isInitialized = true;
|
||||
m_info = Success;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename _MatrixType, typename Rhs>
|
||||
struct solve_retval<IncompleteCholesky<_MatrixType>, Rhs>
|
||||
: solve_retval_base<IncompleteCholesky<_MatrixType>, Rhs>
|
||||
{
|
||||
typedef IncompleteCholesky<_MatrixType> Dec;
|
||||
EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
|
||||
|
||||
template<typename Dest> void evalTo(Dest& dst) const
|
||||
{
|
||||
dec()._solve(rhs(),dst);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif
|
@ -34,8 +34,8 @@ template<typename T>
|
||||
void test2dHyperbolicRotation(double tol)
|
||||
{
|
||||
Matrix<std::complex<T>,2,2> A, B, C;
|
||||
T angle, ch = std::cosh(1);
|
||||
std::complex<T> ish(0, std::sinh(1));
|
||||
T angle, ch = std::cosh((T)1);
|
||||
std::complex<T> ish(0, std::sinh((T)1));
|
||||
|
||||
A << ch, ish, -ish, ch;
|
||||
MatrixPower<Matrix<std::complex<T>,2,2> > Apow(A);
|
||||
|
Loading…
x
Reference in New Issue
Block a user