Initial commit
git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/math/trunk@476930 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c0b59b0810
commit
05195b77ca
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,103 @@
|
|||
Apache commons-math
|
||||
Copyright 2006 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
|
||||
|
||||
|
||||
This product includes software developed by
|
||||
Luc Maisonobe and licensed to the Apache Software Foundation.
|
||||
|
||||
|
||||
|
||||
This product includes software translated from the lmder, lmpar
|
||||
and qrsolv Fortran routines from the Minpack package and
|
||||
distributed under the following disclaimer:
|
||||
|
||||
---------- http://www.netlib.org/minpack/disclaimer ----------
|
||||
Minpack Copyright Notice (1999) University of Chicago. All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
3. The end-user documentation included with the
|
||||
redistribution, if any, must include the following
|
||||
acknowledgment:
|
||||
|
||||
"This product includes software developed by the
|
||||
University of Chicago, as Operator of Argonne National
|
||||
Laboratory.
|
||||
|
||||
Alternately, this acknowledgment may appear in the software
|
||||
itself, if and wherever such third-party acknowledgments
|
||||
normally appear.
|
||||
|
||||
4. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS"
|
||||
WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT HOLDER, THE
|
||||
UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND
|
||||
THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE
|
||||
OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY
|
||||
OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR
|
||||
USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF
|
||||
THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4)
|
||||
DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION
|
||||
UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL
|
||||
BE CORRECTED.
|
||||
|
||||
5. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT
|
||||
HOLDER, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF
|
||||
ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT,
|
||||
INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF
|
||||
ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER
|
||||
SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT
|
||||
(INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE,
|
||||
EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE
|
||||
POSSIBILITY OF SUCH LOSS OR DAMAGES.
|
||||
---------- http://www.netlib.org/minpack/disclaimer ----------
|
||||
|
||||
|
||||
|
||||
This product includes software translated from the odex Fortran routine
|
||||
developed by E. Hairer and G. Wanner and distributed under the following
|
||||
license:
|
||||
|
||||
---------- http://www.unige.ch/~hairer/prog/licence.txt ----------
|
||||
Copyright (c) 2004, Ernst Hairer
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------- http://www.unige.ch/~hairer/prog/licence.txt ----------
|
|
@ -0,0 +1,119 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.MissingResourceException;
|
||||
|
||||
/** This class is the base class for all specific exceptions thrown by
|
||||
* the mantissa classes.
|
||||
|
||||
* <p>When the mantissa classes throw exceptions that are specific to
|
||||
* the package, these exceptions are always subclasses of
|
||||
* MantissaException. When exceptions that are already covered by the
|
||||
* standard java API should be thrown, like
|
||||
* ArrayIndexOutOfBoundsException or IllegalArgumentException, these
|
||||
* standard exceptions are thrown rather than the mantissa specific
|
||||
* ones.</p>
|
||||
|
||||
* @version $Id: MantissaException.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class MantissaException
|
||||
extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static ResourceBundle resources
|
||||
= ResourceBundle.getBundle("org.spaceroots.mantissa.MessagesResources");
|
||||
|
||||
/** Translate a string.
|
||||
* @param s string to translate
|
||||
* @return translated string
|
||||
*/
|
||||
public static String translate(String s) {
|
||||
try {
|
||||
return resources.getString(s);
|
||||
} catch (MissingResourceException mre) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
/** Translate a message.
|
||||
* @param specifier format specifier (to be translated)
|
||||
* @param parts to insert in the format (no translation)
|
||||
* @return translated message
|
||||
*/
|
||||
public static String translate(String specifier, String[] parts) {
|
||||
return new MessageFormat(translate(specifier)).format(parts);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an exception with an empty message
|
||||
*/
|
||||
public MantissaException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an exception by translating the specified message
|
||||
* @param message message to translate
|
||||
*/
|
||||
public MantissaException(String message) {
|
||||
super(translate(message));
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an exception by translating and formating a message
|
||||
* @param specifier format specifier (to be translated)
|
||||
* @param parts to insert in the format (no translation)
|
||||
*/
|
||||
public MantissaException(String specifier, String[] parts) {
|
||||
super(translate(specifier, parts));
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an exception from a cause
|
||||
* @param cause cause of this exception
|
||||
*/
|
||||
public MantissaException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an exception from a message and a cause
|
||||
* @param message message to translate
|
||||
* @param cause cause of this exception
|
||||
*/
|
||||
public MantissaException(String message, Throwable cause) {
|
||||
super(translate(message), cause);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an exception from a message and a cause
|
||||
* @param specifier format specifier (to be translated)
|
||||
* @param parts to insert in the format (no translation)
|
||||
* @param cause cause of this exception
|
||||
*/
|
||||
public MantissaException(String specifier, String[] parts, Throwable cause) {
|
||||
super(translate(specifier, parts), cause);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa;
|
||||
|
||||
import java.util.ListResourceBundle;
|
||||
|
||||
/** This class gather the message resources for the mantissa library.
|
||||
* @version $Id: MessagesResources.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
*/
|
||||
|
||||
public class MessagesResources
|
||||
extends ListResourceBundle {
|
||||
|
||||
/** Simple constructor.
|
||||
*/
|
||||
public MessagesResources() {
|
||||
}
|
||||
|
||||
public Object[][] getContents() {
|
||||
return contents;
|
||||
}
|
||||
|
||||
static final Object[][] contents = {
|
||||
|
||||
// org.spaceroots.mantissa.estimation.GaussNewtonEstimator
|
||||
{ "unable to converge in {0} iterations",
|
||||
"unable to converge in {0} iterations" },
|
||||
|
||||
// org.spaceroots.mantissa.estimation.LevenbergMarquardtEstimator
|
||||
{ "cost relative tolerance is too small ({0}), no further reduction in the sum of squares is possible",
|
||||
"cost relative tolerance is too small ({0}), no further reduction in the sum of squares is possible" },
|
||||
{ "parameters relative tolerance is too small ({0}), no further improvement in the approximate solution is possible",
|
||||
"parameters relative tolerance is too small ({0}), no further improvement in the approximate solution is possible" },
|
||||
{ "orthogonality tolerance is too small ({0}), solution is orthogonal to the jacobian",
|
||||
"orthogonality tolerance is too small ({0}), solution is orthogonal to the jacobian" },
|
||||
{ "maximal number of evaluations exceeded ({0})",
|
||||
"maximal number of evaluations exceeded ({0})" },
|
||||
|
||||
// org.spaceroots.mantissa.fitting.HarmonicCoefficientsGuesser
|
||||
{ "unable to guess a first estimate",
|
||||
"unable to guess a first estimate" },
|
||||
|
||||
// org.spaceroots.mantissa.fitting.HarmonicFitter
|
||||
{ "sample must contain at least {0} points",
|
||||
"sample must contain at least {0} points" },
|
||||
|
||||
// org.spaceroots.mantissa.functions.ExhaustedSampleException
|
||||
{ "sample contains only {0} elements",
|
||||
"sample contains only {0} elements" },
|
||||
|
||||
// org.spaceroots.mantissa.geometry.CardanEulerSingularityException
|
||||
{ "Cardan angles singularity",
|
||||
"Cardan angles singularity" },
|
||||
{ "Euler angles singularity",
|
||||
"Euler angles singularity" },
|
||||
|
||||
// org.spaceroots.mantissa.geometry.Rotation
|
||||
{ "a {0}x{1} matrix cannot be a rotation matrix",
|
||||
"a {0}x{1} matrix cannot be a rotation matrix" },
|
||||
{ "the closest orthogonal matrix has a negative determinant {0}",
|
||||
"the closest orthogonal matrix has a negative determinant {0}" },
|
||||
{ "unable to orthogonalize matrix in {0} iterations",
|
||||
"unable to orthogonalize matrix in {0} iterations" },
|
||||
|
||||
// org.spaceroots.mantissa.linalg;.SingularMatrixException
|
||||
{ "singular matrix",
|
||||
"singular matrix" },
|
||||
|
||||
// org.spaceroots.mantissa.ode.AdaptiveStepsizeIntegrator
|
||||
{ "minimal step size ({0}) reached, integration needs {1}",
|
||||
"minimal step size ({0}) reached, integration needs {1}" },
|
||||
|
||||
// org.spaceroots.mantissa.ode.GraggBulirschStoerIntegrator,
|
||||
// org.spaceroots.mantissa.ode.RungeKuttaFehlbergIntegrator,
|
||||
// org.spaceroots.mantissa.ode.RungeKuttaIntegrator
|
||||
{ "dimensions mismatch: ODE problem has dimension {0},"
|
||||
+ " state vector has dimension {1}",
|
||||
"dimensions mismatch: ODE problem has dimension {0},"
|
||||
+ " state vector has dimension {1}" },
|
||||
{ "too small integration interval: length = {0}",
|
||||
"too small integration interval: length = {0}" },
|
||||
|
||||
// org.spaceroots.mantissa.optimization.DirectSearchOptimizer
|
||||
{ "none of the {0} start points lead to convergence",
|
||||
"none of the {0} start points lead to convergence" },
|
||||
|
||||
// org.spaceroots.mantissa.random.CorrelatedRandomVectorGenerator
|
||||
{ "dimension mismatch {0} != {1}",
|
||||
"dimension mismatch {0} != {1}" },
|
||||
|
||||
// org.spaceroots.mantissa.random.NotPositiveDefiniteMatrixException
|
||||
{ "not positive definite matrix",
|
||||
"not positive definite matrix" }
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa;
|
||||
|
||||
import java.util.ListResourceBundle;
|
||||
|
||||
/** This class gather the message resources for the mantissa library.
|
||||
* @version $Id: MessagesResources_fr.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
*/
|
||||
public class MessagesResources_fr
|
||||
extends ListResourceBundle {
|
||||
|
||||
/** Simple constructor.
|
||||
*/
|
||||
public MessagesResources_fr() {
|
||||
}
|
||||
|
||||
public Object[][] getContents() {
|
||||
return contents;
|
||||
}
|
||||
|
||||
static final Object[][] contents = {
|
||||
|
||||
// org.spaceroots.mantissa.estimation.GaussNewtonEstimator
|
||||
{ "unable to converge in {0} iterations",
|
||||
"pas de convergence apr\u00e8s {0} it\u00e9rations" },
|
||||
|
||||
// org.spaceroots.mantissa.estimation.LevenbergMarquardtEstimator
|
||||
{ "cost relative tolerance is too small ({0}), no further reduction in the sum of squares is possible",
|
||||
"trop petite tol\u00e9rance relative sur le co\u00fbt ({0}), aucune r\u00e9duction de la somme des carr\u00e9s n''est possible" },
|
||||
{ "parameters relative tolerance is too small ({0}), no further improvement in the approximate solution is possible",
|
||||
"trop petite tol\u00e9rance relative sur les param\u00e8tres ({0}), aucune am\u00e9lioration de la solution approximative n''est possible" },
|
||||
{ "orthogonality tolerance is too small ({0}), solution is orthogonal to the jacobian",
|
||||
"trop petite tol\u00e9rance sur l''orthogonalit\u00e9 ({0}), la solution est orthogonale \u00e0 la jacobienne" },
|
||||
{ "maximal number of evaluations exceeded ({0})",
|
||||
"nombre maximal d''\u00e9valuations d\u00e9pass\u00e9 ({0})" },
|
||||
|
||||
// org.spaceroots.mantissa.fitting.HarmonicCoefficientsGuesser
|
||||
{ "unable to guess a first estimate",
|
||||
"impossible de trouver une premi\u00e8re estim\u00e9e" },
|
||||
|
||||
// org.spaceroots.mantissa.fitting.HarmonicFitter
|
||||
{ "sample must contain at least {0} points",
|
||||
"l''\u00e9chantillon doit contenir au moins {0} points" },
|
||||
|
||||
// org.spaceroots.mantissa.functions.ExhaustedSampleException
|
||||
{ "sample contains only {0} elements",
|
||||
"l''\u00e9chantillon ne contient que {0} points" },
|
||||
|
||||
// org.spaceroots.mantissa.geometry.CardanEulerSingularityException
|
||||
{ "Cardan angles singularity",
|
||||
"singularit\u00e9 d''angles de Cardan" },
|
||||
{ "Euler angles singularity",
|
||||
"singularit\u00e9 d''angles d''Euler" },
|
||||
|
||||
// org.spaceroots.mantissa.geometry.Rotation
|
||||
{ "a {0}x{1} matrix cannot be a rotation matrix",
|
||||
"une matrice {0}x{1} ne peut pas \u00e9tre une matrice de rotation" },
|
||||
{ "the closest orthogonal matrix has a negative determinant {0}",
|
||||
"la matrice orthogonale la plus proche a un d\u00e9terminant n\u00e9gatif {0}" },
|
||||
{ "unable to orthogonalize matrix in {0} iterations",
|
||||
"impossible de rendre la matrice orthogonale en {0} it\u00e9rations" },
|
||||
|
||||
// org.spaceroots.mantissa.linalg;.SingularMatrixException
|
||||
{ "singular matrix",
|
||||
"matrice singuli\u00e8re" },
|
||||
|
||||
// org.spaceroots.mantissa.ode.AdaptiveStepsizeIntegrator
|
||||
{ "minimal step size ({0}) reached, integration needs {1}",
|
||||
"pas minimal ({0}) atteint, l''int\u00e9gration n\u00e9cessite {1}" },
|
||||
|
||||
// org.spaceroots.mantissa.ode.GraggBulirschStoerIntegrator,
|
||||
// org.spaceroots.mantissa.ode.RungeKuttaFehlbergIntegrator,
|
||||
// org.spaceroots.mantissa.ode.RungeKuttaIntegrator
|
||||
{ "dimensions mismatch: ODE problem has dimension {0},"
|
||||
+ " state vector has dimension {1}",
|
||||
"incompatibilit\u00e9 de dimensions entre le probl\u00e8me ODE ({0}),"
|
||||
+ " et le vecteur d'\u00e9tat ({1})" },
|
||||
{ "too small integration interval: length = {0}",
|
||||
"intervalle d''int\u00e9gration trop petit : {0}" },
|
||||
|
||||
// org.spaceroots.mantissa.optimization.DirectSearchOptimizer
|
||||
{ "none of the {0} start points lead to convergence",
|
||||
"aucun des {0} points de d\u00e9part n''aboutit \u00e0 une convergence" },
|
||||
|
||||
// org.spaceroots.mantissa.random.CorrelatedRandomVectorGenerator
|
||||
{ "dimension mismatch {0} != {1}",
|
||||
"dimensions incompatibles {0} != {1}" },
|
||||
|
||||
// org.spaceroots.mantissa.random.NotPositiveDefiniteMatrixException
|
||||
{ "not positive definite matrix",
|
||||
"matrice non d\u00e9finie positive" }
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.algebra;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class implements Chebyshev polynomials.
|
||||
|
||||
* <p>Chebyshev polynomials can be defined by the following recurrence
|
||||
* relations:
|
||||
* <pre>
|
||||
* T0(X) = 1
|
||||
* T1(X) = X
|
||||
* Tk+1(X) = 2X Tk(X) - Tk-1(X)
|
||||
* </pre></p>
|
||||
|
||||
* @version $Id: Chebyshev.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class Chebyshev
|
||||
extends OrthogonalPolynomial {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a degree 0 Chebyshev polynomial
|
||||
*/
|
||||
public Chebyshev() {
|
||||
super(0, l, maxDegree);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a degree d Chebyshev polynomial
|
||||
* @param d degree of the polynomial
|
||||
*/
|
||||
public Chebyshev(int d) {
|
||||
super(d, l, maxDegree);
|
||||
}
|
||||
|
||||
/** Initialize the recurrence coefficients.
|
||||
* The recurrence relation is
|
||||
* <pre>Tk+1(X) = 2X Tk(X) - Tk-1(X)</pre>
|
||||
* @param k index of the current step
|
||||
* @param b2k coefficient to initialize (b2k = a2k / a1k)
|
||||
* @param b3k coefficient to initialize (b3k = a3k / a1k)
|
||||
* @param b4k coefficient to initialize (b4k = a4k / a1k)
|
||||
*/
|
||||
protected void initRecurrenceCoefficients(int k,
|
||||
RationalNumber b2k,
|
||||
RationalNumber b3k,
|
||||
RationalNumber b4k) {
|
||||
b2k.reset(0l);
|
||||
b3k.reset(2l);
|
||||
b4k.reset(1l);
|
||||
}
|
||||
|
||||
/** Set the maximal degree of already computed polynomials.
|
||||
* @param d maximal degree of already computed polynomials
|
||||
*/
|
||||
protected void setMaxDegree(int d) {
|
||||
maxDegree = d;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 8367010179599693222L;
|
||||
|
||||
/** List holding the coefficients of the polynomials computed so far. */
|
||||
private static List l;
|
||||
|
||||
/** Maximal degree of the polynomials computed so far. */
|
||||
private static int maxDegree;
|
||||
|
||||
/** Build the first two polynomials. */
|
||||
static {
|
||||
|
||||
l = new ArrayList ();
|
||||
|
||||
// T0(X) = 1
|
||||
l.add(new RationalNumber(1l));
|
||||
|
||||
// T1(X) = X
|
||||
l.add(new RationalNumber(0l));
|
||||
l.add(new RationalNumber(1l));
|
||||
|
||||
maxDegree = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.algebra;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class implements Hermite polynomials.
|
||||
|
||||
* <p>Hermite polynomials can be defined by the following recurrence
|
||||
* relations:
|
||||
* <pre>
|
||||
* H0(X) = 1
|
||||
* H1(X) = 2X
|
||||
* Hk+1(X) = 2X Hk(X) - 2k Hk-1(X)
|
||||
* </pre></p>
|
||||
|
||||
* @version $Id: Hermite.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
public class Hermite
|
||||
extends OrthogonalPolynomial {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a degree 0 Hermite polynomial
|
||||
*/
|
||||
public Hermite() {
|
||||
super(0, l, maxDegree);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a degree d Hermite polynomial
|
||||
* @param d degree of the polynomial
|
||||
*/
|
||||
public Hermite(int d) {
|
||||
super(d, l, maxDegree);
|
||||
}
|
||||
|
||||
/** Initialize the recurrence coefficients.
|
||||
* The recurrence relation is
|
||||
* <pre>Hk+1(X) = 2X Hk(X) - 2k Hk-1(X)</pre>
|
||||
* @param k index of the current step
|
||||
* @param b2k coefficient to initialize (b2k = a2k / a1k)
|
||||
* @param b3k coefficient to initialize (b3k = a3k / a1k)
|
||||
* @param b4k coefficient to initialize (b4k = a4k / a1k)
|
||||
*/
|
||||
protected void initRecurrenceCoefficients(int k,
|
||||
RationalNumber b2k,
|
||||
RationalNumber b3k,
|
||||
RationalNumber b4k) {
|
||||
b2k.reset(0l);
|
||||
b3k.reset(2l);
|
||||
b4k.reset(2l * k);
|
||||
}
|
||||
|
||||
/** Set the maximal degree of already computed polynomials.
|
||||
* @param d maximal degree of already computed polynomials
|
||||
*/
|
||||
protected void setMaxDegree(int d) {
|
||||
maxDegree = d;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -4639726453485128770L;
|
||||
|
||||
/** Table holding the coefficients of the polynomials computed so far. */
|
||||
private static List l;
|
||||
|
||||
/** Maximal degree of the polynomials computed so far. */
|
||||
private static int maxDegree;
|
||||
|
||||
/** Build the first two polynomials. */
|
||||
static {
|
||||
|
||||
l = new ArrayList ();
|
||||
|
||||
// H0(X) = 1
|
||||
l.add(new RationalNumber(1l));
|
||||
|
||||
// H1(X) = 2X
|
||||
l.add(new RationalNumber(0l));
|
||||
l.add(new RationalNumber(2l));
|
||||
|
||||
maxDegree = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.algebra;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class implements Laguerre polynomials.
|
||||
|
||||
* <p>Laguerre polynomials can be defined by the following recurrence
|
||||
* relations:
|
||||
* <pre>
|
||||
* L0(X) = 1
|
||||
* L1(X) = 1 - X
|
||||
* (k+1) Lk+1(X) = (2k + 1 - X) Lk(X) - k Lk-1(X)
|
||||
* </pre></p>
|
||||
|
||||
* @version $Id: Laguerre.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
public class Laguerre
|
||||
extends OrthogonalPolynomial {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a degree 0 Laguerre polynomial
|
||||
*/
|
||||
public Laguerre() {
|
||||
super(0, l, maxDegree);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a degree d Laguerre polynomial
|
||||
* @param d degree of the polynomial
|
||||
*/
|
||||
public Laguerre(int d) {
|
||||
super(d, l, maxDegree);
|
||||
}
|
||||
|
||||
/** Initialize the recurrence coefficients.
|
||||
* The recurrence relation is
|
||||
* <pre>(k+1) Lk+1(X) = (2k + 1 - X) Lk(X) - k Lk-1(X)</pre>
|
||||
* @param k index of the current step
|
||||
* @param b2k coefficient to initialize (b2k = a2k / a1k)
|
||||
* @param b3k coefficient to initialize (b3k = a3k / a1k)
|
||||
* @param b4k coefficient to initialize (b4k = a4k / a1k)
|
||||
*/
|
||||
protected void initRecurrenceCoefficients(int k,
|
||||
RationalNumber b2k,
|
||||
RationalNumber b3k,
|
||||
RationalNumber b4k) {
|
||||
long kP1 = k + 1;
|
||||
b2k.reset(2 * k + 1, kP1);
|
||||
b3k.reset(-1l, kP1);
|
||||
b4k.reset(k, kP1);
|
||||
}
|
||||
|
||||
/** Set the maximal degree of already computed polynomials.
|
||||
* @param d maximal degree of already computed polynomials
|
||||
*/
|
||||
protected void setMaxDegree(int d) {
|
||||
maxDegree = d;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -750526984136835515L;
|
||||
|
||||
/** List holding the coefficients of the polynomials computed so far. */
|
||||
private static List l;
|
||||
|
||||
/** Maximal degree of the polynomials computed so far. */
|
||||
private static int maxDegree;
|
||||
|
||||
/** Build the first two polynomials. */
|
||||
static {
|
||||
|
||||
l = new ArrayList ();
|
||||
|
||||
// L0(X) = 1
|
||||
l.add(new RationalNumber(1l));
|
||||
|
||||
// L1(X) = 1 - X
|
||||
l.add(new RationalNumber(1l));
|
||||
l.add(new RationalNumber(-1l));
|
||||
|
||||
maxDegree = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.algebra;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class implements Legendre polynomials.
|
||||
|
||||
* <p>Legendre polynomials can be defined by the following recurrence
|
||||
* relations:
|
||||
* <pre>
|
||||
* P0(X) = 1
|
||||
* P1(X) = X
|
||||
* (k+1) Pk+1(X) = (2k+1) X Pk(X) - k Pk-1(X)
|
||||
* </pre></p>
|
||||
|
||||
* @version $Id: Legendre.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class Legendre
|
||||
extends OrthogonalPolynomial {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a degree 0 Legendre polynomial
|
||||
*/
|
||||
public Legendre() {
|
||||
super(0, l, maxDegree);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a degree d Legendre polynomial
|
||||
* @param d degree of the polynomial
|
||||
*/
|
||||
public Legendre(int d) {
|
||||
super(d, l, maxDegree);
|
||||
}
|
||||
|
||||
/** Initialize the recurrence coefficients.
|
||||
* The recurrence relation is
|
||||
* <pre>(k+1) Pk+1(X) = (2k+1) X Pk(X) - k Ok-1(X)</pre>
|
||||
* @param k index of the current step
|
||||
* @param b2k coefficient to initialize (b2k = a2k / a1k)
|
||||
* @param b3k coefficient to initialize (b3k = a3k / a1k)
|
||||
* @param b4k coefficient to initialize (b4k = a4k / a1k)
|
||||
*/
|
||||
protected void initRecurrenceCoefficients(int k,
|
||||
RationalNumber b2k,
|
||||
RationalNumber b3k,
|
||||
RationalNumber b4k) {
|
||||
long kP1 = k + 1;
|
||||
b2k.reset(0l);
|
||||
b3k.reset(2 * k + 1, kP1);
|
||||
b4k.reset(k, kP1);
|
||||
}
|
||||
|
||||
/** Set the maximal degree of already computed polynomials.
|
||||
* @param d maximal degree of already computed polynomials
|
||||
*/
|
||||
protected void setMaxDegree(int d) {
|
||||
maxDegree = d;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 428266828791532209L;
|
||||
|
||||
/** List holding the coefficients of the polynomials computed so far. */
|
||||
private static List l;
|
||||
|
||||
/** Maximal degree of the polynomials computed so far. */
|
||||
private static int maxDegree;
|
||||
|
||||
/** Build the first two polynomials. */
|
||||
static {
|
||||
|
||||
l = new ArrayList ();
|
||||
|
||||
// P0(X) = 1
|
||||
l.add(new RationalNumber(1l));
|
||||
|
||||
// P1(X) = X
|
||||
l.add(new RationalNumber(0l));
|
||||
l.add(new RationalNumber(1l));
|
||||
|
||||
maxDegree = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.algebra;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class is the base class for orthogonal polynomials.
|
||||
|
||||
* <p>Orthogonal polynomials can be defined by recurrence relations like:
|
||||
* <pre>
|
||||
* O0(X) = some 0 degree polynomial
|
||||
* O1(X) = some first degree polynomial
|
||||
* a1k Ok+1(X) = (a2k + a3k X) Ok(X) - a4k Ok-1(X)
|
||||
* </pre>
|
||||
* where a0k, a1k, a2k and a3k are simple expressions which either are
|
||||
* constants or depend on k.</p>
|
||||
|
||||
* @version $Id: OrthogonalPolynomial.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
public abstract class OrthogonalPolynomial
|
||||
extends Polynomial.Rational {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a degree d orthogonal polynomial
|
||||
* @param d degree of the polynomial
|
||||
* @param l list containing all coefficients already computed
|
||||
* @param maxDegree maximal degree of computed coefficients, this
|
||||
* coefficient <em>must</em> be greater or equal to 1, i.e. the
|
||||
* derived class <em>must</em> have initialized the first two
|
||||
* polynomials of degree 0 and 1 before this constructor can be
|
||||
* called.
|
||||
*/
|
||||
protected OrthogonalPolynomial(int d, List l, int maxDegree) {
|
||||
if (d > maxDegree) {
|
||||
computeUpToDegree(d, l, maxDegree);
|
||||
}
|
||||
|
||||
// coefficient for polynomial 0 is l [0]
|
||||
// coefficient for polynomial 1 are l [1] ... l [2] (degrees 0 ... 1)
|
||||
// coefficients for polynomial 2 are l [3] ... l [5] (degrees 0 ... 2)
|
||||
// coefficients for polynomial 3 are l [6] ... l [9] (degrees 0 ... 3)
|
||||
// coefficients for polynomial 4 are l[10] ... l[14] (degrees 0 ... 4)
|
||||
// coefficients for polynomial 5 are l[15] ... l[20] (degrees 0 ... 5)
|
||||
// coefficients for polynomial 6 are l[21] ... l[27] (degrees 0 ... 6)
|
||||
// ...
|
||||
int start = d * (d + 1) / 2;
|
||||
|
||||
a = new RationalNumber[d+1];
|
||||
for (int i = 0; i <= d; ++i) {
|
||||
a[i] = new RationalNumber((RationalNumber) l.get(start + i));
|
||||
}
|
||||
|
||||
unknown = null;
|
||||
|
||||
}
|
||||
|
||||
/** Initialize the recurrence coefficients.
|
||||
* The recurrence relation is
|
||||
* <pre>a1k Ok+1(X) = (a2k + a3k X) Ok(X) - a4k Ok-1(X)</pre>
|
||||
* @param k index of the current step
|
||||
* @param b2k coefficient to initialize (b2k = a2k / a1k)
|
||||
* @param b3k coefficient to initialize (b3k = a3k / a1k)
|
||||
* @param b4k coefficient to initialize (b4k = a4k / a1k)
|
||||
*/
|
||||
protected abstract void initRecurrenceCoefficients(int k,
|
||||
RationalNumber b2k,
|
||||
RationalNumber b3k,
|
||||
RationalNumber b4k);
|
||||
|
||||
/** Set the maximal degree of already computed polynomials.
|
||||
* @param d maximal degree of already computed polynomials
|
||||
*/
|
||||
protected abstract void setMaxDegree(int d);
|
||||
|
||||
/** Compute all the polynomial coefficients up to a given degree.
|
||||
* @param d maximal degree
|
||||
* @param l list containing all coefficients already computed
|
||||
* @param maxDegree maximal degree of computed coefficients
|
||||
*/
|
||||
protected void computeUpToDegree(int d, List l, int maxDegree) {
|
||||
|
||||
RationalNumber b2k = new RationalNumber();
|
||||
RationalNumber b3k = new RationalNumber();
|
||||
RationalNumber b4k = new RationalNumber();
|
||||
|
||||
int startK = (maxDegree - 1) * maxDegree / 2;
|
||||
for (int k = maxDegree; k < d; ++k) {
|
||||
|
||||
// start indices of two previous polynomials Ok(X) and Ok-1(X)
|
||||
int startKm1 = startK;
|
||||
startK += k;
|
||||
|
||||
// a1k Ok+1(X) = (a2k + a3k X) Ok(X) - a4k Ok-1(X)
|
||||
// we use bik = aik/a1k
|
||||
initRecurrenceCoefficients(k, b2k, b3k, b4k);
|
||||
|
||||
RationalNumber ckPrev = null;
|
||||
RationalNumber ck = (RationalNumber)l.get(startK);
|
||||
RationalNumber ckm1 = (RationalNumber)l.get(startKm1);
|
||||
|
||||
// degree 0 coefficient
|
||||
RationalNumber coeff = RationalNumber.multiply(ck, b2k);
|
||||
coeff.multiplyAndSubtractFromSelf(ckm1, b4k);
|
||||
l.add(coeff);
|
||||
|
||||
// degree 1 to degree k-1 coefficients
|
||||
for (int i = 1; i < k; ++i) {
|
||||
ckPrev = ck;
|
||||
ck = (RationalNumber)l.get(startK + i);
|
||||
ckm1 = (RationalNumber)l.get(startKm1 + i);
|
||||
coeff = RationalNumber.multiply(ck, b2k);
|
||||
coeff.multiplyAndAddToSelf(ckPrev, b3k);
|
||||
coeff.multiplyAndSubtractFromSelf(ckm1, b4k);
|
||||
l.add(coeff);
|
||||
}
|
||||
|
||||
// degree k coefficient
|
||||
ckPrev = ck;
|
||||
ck = (RationalNumber)l.get(startK + k);
|
||||
coeff = RationalNumber.multiply(ck, b2k);
|
||||
coeff.multiplyAndAddToSelf(ckPrev, b3k);
|
||||
l.add(coeff);
|
||||
|
||||
// degree k+1 coefficient
|
||||
l.add(RationalNumber.multiply(ck, b3k));
|
||||
|
||||
}
|
||||
|
||||
setMaxDegree(d);
|
||||
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,439 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.algebra;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* This class implements fractions of polynomials with one unknown and
|
||||
* rational coefficients.
|
||||
|
||||
* @version $Id: PolynomialFraction.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class PolynomialFraction {
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* Build a constant null fraction
|
||||
*/
|
||||
public PolynomialFraction() {
|
||||
this(new Polynomial.Rational(new RationalNumber(0l)),
|
||||
new Polynomial.Rational(new RationalNumber(1l)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* Build a fraction from a numerator and a denominator.
|
||||
* @param numerator numerator of the fraction
|
||||
* @param denominator denominator of the fraction
|
||||
* @exception ArithmeticException if the denominator is null
|
||||
*/
|
||||
public PolynomialFraction(long numerator, long denominator) {
|
||||
this(new Polynomial.Rational(new RationalNumber(numerator)),
|
||||
new Polynomial.Rational(new RationalNumber(denominator)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* Build a fraction from a numerator and a denominator.
|
||||
* @param numerator numerator of the fraction
|
||||
* @param denominator denominator of the fraction
|
||||
* @exception ArithmeticException if the denominator is null
|
||||
*/
|
||||
public PolynomialFraction(BigInteger numerator, BigInteger denominator) {
|
||||
this(new Polynomial.Rational(new RationalNumber(numerator)),
|
||||
new Polynomial.Rational(new RationalNumber(denominator)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* Build a fraction from a numerator and a denominator.
|
||||
* @param numerator numerator of the fraction
|
||||
* @param denominator denominator of the fraction
|
||||
* @exception ArithmeticException if the denominator is null
|
||||
*/
|
||||
public PolynomialFraction(RationalNumber numerator,
|
||||
RationalNumber denominator) {
|
||||
this(new Polynomial.Rational(numerator),
|
||||
new Polynomial.Rational(denominator));
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* Build a fraction from a numerator and a denominator.
|
||||
* @param numerator numerator of the fraction
|
||||
* @param denominator denominator of the fraction
|
||||
* @exception ArithmeticException if the denominator is null
|
||||
*/
|
||||
public PolynomialFraction(Polynomial.Rational numerator,
|
||||
Polynomial.Rational denominator) {
|
||||
|
||||
if (denominator.isZero()) {
|
||||
throw new ArithmeticException("null denominator");
|
||||
}
|
||||
|
||||
p = new Polynomial.Rational(numerator);
|
||||
q = new Polynomial.Rational(denominator);
|
||||
|
||||
RationalNumber[] a = q.getCoefficients();
|
||||
if (a[a.length - 1].isNegative()) {
|
||||
p.negateSelf();
|
||||
q.negateSelf();
|
||||
}
|
||||
|
||||
simplify();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* Build a fraction from a single integer
|
||||
* @param l value of the fraction
|
||||
*/
|
||||
public PolynomialFraction(long l) {
|
||||
this(l, 1l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* Build a fraction from a single integer
|
||||
* @param i value of the fraction
|
||||
*/
|
||||
public PolynomialFraction(BigInteger i) {
|
||||
this(i, BigInteger.ONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* Build a fraction from a single rational number
|
||||
* @param r value of the fraction
|
||||
*/
|
||||
public PolynomialFraction(RationalNumber r) {
|
||||
this(r.getNumerator(), r.getDenominator());
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* Build a fraction from a single Polynom
|
||||
* @param p value of the fraction
|
||||
*/
|
||||
public PolynomialFraction(Polynomial.Rational p) {
|
||||
this(p, new Polynomial.Rational(new RationalNumber(1l)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy-constructor.
|
||||
* @param f fraction to copy
|
||||
*/
|
||||
public PolynomialFraction(PolynomialFraction f) {
|
||||
p = new Polynomial.Rational(f.p);
|
||||
q = new Polynomial.Rational(f.q);
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate the instance
|
||||
*/
|
||||
public void negateSelf() {
|
||||
p.negateSelf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate a fraction.
|
||||
* @param f fraction to negate
|
||||
* @return a new fraction which is the opposite of f
|
||||
*/
|
||||
public static PolynomialFraction negate(PolynomialFraction f) {
|
||||
PolynomialFraction copy = new PolynomialFraction(f);
|
||||
copy.negateSelf();
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a fraction to the instance.
|
||||
* @param f fraction to add.
|
||||
*/
|
||||
public void addToSelf(PolynomialFraction f) {
|
||||
PolynomialFraction sum = add(this, f);
|
||||
p = sum.p;
|
||||
q = sum.q;
|
||||
}
|
||||
|
||||
/** Add two fractions.
|
||||
* @param f1 first fraction
|
||||
* @param f2 second fraction
|
||||
* @return a new fraction which is the sum of f1 and f2
|
||||
*/
|
||||
public static PolynomialFraction add(PolynomialFraction f1,
|
||||
PolynomialFraction f2) {
|
||||
Polynomial.Rational num =
|
||||
Polynomial.Rational.add(Polynomial.Rational.multiply(f1.p, f2.q),
|
||||
Polynomial.Rational.multiply(f2.p, f1.q));
|
||||
Polynomial.Rational den = Polynomial.Rational.multiply(f1.q, f2.q);
|
||||
return new PolynomialFraction(num, den);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract a fraction to the instance.
|
||||
* @param f fraction to subtract.
|
||||
*/
|
||||
public void subtractFromSelf(PolynomialFraction f) {
|
||||
PolynomialFraction diff = subtract(this, f);
|
||||
p = diff.p;
|
||||
q = diff.q;
|
||||
}
|
||||
|
||||
/** Subtract two fractions.
|
||||
* @param f1 first fraction
|
||||
* @param f2 second fraction
|
||||
* @return a new fraction which is the difference f1 minus f2
|
||||
*/
|
||||
public static PolynomialFraction subtract(PolynomialFraction f1,
|
||||
PolynomialFraction f2) {
|
||||
Polynomial.Rational num =
|
||||
Polynomial.Rational.subtract(Polynomial.Rational.multiply(f1.p, f2.q),
|
||||
Polynomial.Rational.multiply(f2.p, f1.q));
|
||||
Polynomial.Rational den = Polynomial.Rational.multiply(f1.q, f2.q);
|
||||
return new PolynomialFraction(num, den);
|
||||
}
|
||||
|
||||
/** Multiply the instance by a fraction.
|
||||
* @param f fraction to multiply by
|
||||
*/
|
||||
public void multiplySelf(PolynomialFraction f) {
|
||||
p.multiplySelf(f.p);
|
||||
q.multiplySelf(f.q);
|
||||
simplify();
|
||||
}
|
||||
|
||||
/** Multiply two fractions.
|
||||
* @param f1 first fraction
|
||||
* @param f2 second fraction
|
||||
* @return a new fraction which is the product of f1 and f2
|
||||
*/
|
||||
public static PolynomialFraction multiply(PolynomialFraction f1,
|
||||
PolynomialFraction f2) {
|
||||
PolynomialFraction copy = new PolynomialFraction(f1);
|
||||
copy.multiplySelf(f2);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/** Divide the instance by a fraction.
|
||||
* @param f fraction to divide by
|
||||
* @exception ArithmeticException if f is null
|
||||
*/
|
||||
public void divideSelf(PolynomialFraction f) {
|
||||
|
||||
if (f.p.isZero()) {
|
||||
throw new ArithmeticException("divide by zero");
|
||||
}
|
||||
|
||||
p.multiplySelf(f.q);
|
||||
q.multiplySelf(f.p);
|
||||
|
||||
RationalNumber[] a = q.getCoefficients();
|
||||
if (a[a.length - 1].isNegative()) {
|
||||
p.negateSelf();
|
||||
q.negateSelf();
|
||||
}
|
||||
|
||||
simplify();
|
||||
|
||||
}
|
||||
|
||||
/** Divide two fractions.
|
||||
* @param f1 first fraction
|
||||
* @param f2 second fraction
|
||||
* @return a new fraction which is the quotient of f1 by f2
|
||||
*/
|
||||
public static PolynomialFraction divide(PolynomialFraction f1,
|
||||
PolynomialFraction f2) {
|
||||
PolynomialFraction copy = new PolynomialFraction(f1);
|
||||
copy.divideSelf(f2);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/** Invert the instance.
|
||||
* Replace the instance by its inverse.
|
||||
* @exception ArithmeticException if the instance is null
|
||||
*/
|
||||
public void invertSelf() {
|
||||
|
||||
if (p.isZero()) {
|
||||
throw new ArithmeticException("divide by zero");
|
||||
}
|
||||
|
||||
Polynomial.Rational tmp = p;
|
||||
p = q;
|
||||
q = tmp;
|
||||
|
||||
RationalNumber[] a = q.getCoefficients();
|
||||
if (a[a.length - 1].isNegative()) {
|
||||
p.negateSelf();
|
||||
q.negateSelf();
|
||||
}
|
||||
|
||||
simplify();
|
||||
|
||||
}
|
||||
|
||||
/** Invert a fraction.
|
||||
* @param f fraction to invert
|
||||
* @return a new fraction which is the inverse of f
|
||||
*/
|
||||
public static PolynomialFraction invert(PolynomialFraction f) {
|
||||
PolynomialFraction copy = new PolynomialFraction(f);
|
||||
copy.invertSelf();
|
||||
return copy;
|
||||
}
|
||||
|
||||
/** Simplify a fraction.
|
||||
* If the denominator polynom is a constant polynom, then
|
||||
* simplification involves merging this constant in the rational
|
||||
* coefficients of the numerator in order to replace the denominator
|
||||
* by the constant 1. If the degree of the denominator is non null,
|
||||
* then simplification involves both removing common polynomial
|
||||
* factors (by euclidian division) and replacing rational
|
||||
* coefficients by integer coefficients (multiplying both numerator
|
||||
* and denominator by the proper value). The signs of both the
|
||||
* numerator and the denominator are adjusted in order to have a
|
||||
* positive leeding degree term in the denominator.
|
||||
*/
|
||||
private void simplify() {
|
||||
|
||||
Polynomial.Rational a = new Polynomial.Rational(p);
|
||||
Polynomial.Rational b = new Polynomial.Rational(q);
|
||||
if (a.getDegree() < b.getDegree()) {
|
||||
Polynomial.Rational tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
Polynomial.DivisionResult res =
|
||||
Polynomial.Rational.euclidianDivision(a, b);
|
||||
while (res.remainder.getDegree() != 0) {
|
||||
a = b;
|
||||
b = res.remainder;
|
||||
res = Polynomial.Rational.euclidianDivision(a, b);
|
||||
}
|
||||
|
||||
if (res.remainder.isZero()) {
|
||||
// there is a common factor we can remove
|
||||
p = Polynomial.Rational.euclidianDivision(p, b).quotient;
|
||||
q = Polynomial.Rational.euclidianDivision(q, b).quotient;
|
||||
}
|
||||
|
||||
if (q.getDegree() == 0) {
|
||||
if (! q.isOne()) {
|
||||
RationalNumber f = q.getCoefficients()[0];
|
||||
f.invertSelf();
|
||||
p.multiplySelf(f);
|
||||
q = new Polynomial.Rational(1l);
|
||||
}
|
||||
} else {
|
||||
|
||||
BigInteger lcm = p.getDenominatorsLCM();
|
||||
if (lcm.compareTo(BigInteger.ONE) != 0) {
|
||||
p.multiplySelf(lcm);
|
||||
q.multiplySelf(lcm);
|
||||
}
|
||||
|
||||
lcm = q.getDenominatorsLCM();
|
||||
if (lcm.compareTo(BigInteger.ONE) != 0) {
|
||||
p.multiplySelf(lcm);
|
||||
q.multiplySelf(lcm);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (q.getCoefficients()[q.getDegree()].isNegative()) {
|
||||
p.negateSelf();
|
||||
q.negateSelf();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the numerator.
|
||||
* @return the numerator
|
||||
*/
|
||||
public Polynomial.Rational getNumerator() {
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the denominator.
|
||||
* @return the denominator (leeding coefficient is always positive)
|
||||
*/
|
||||
public Polynomial.Rational getDenominator() {
|
||||
return q;
|
||||
}
|
||||
|
||||
/** Set the name of the unknown (to appear during conversions to
|
||||
* strings).
|
||||
* @param name name to set (if null, the default 'x' value will be
|
||||
* used)
|
||||
*/
|
||||
public void setUnknownName(String name) {
|
||||
p.setUnknownName(name);
|
||||
q.setUnknownName(name);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (p.isZero()) {
|
||||
return "0";
|
||||
} else if (q.isOne()) {
|
||||
return p.toString();
|
||||
} else {
|
||||
|
||||
StringBuffer s = new StringBuffer();
|
||||
|
||||
String pString = p.toString();
|
||||
if (pString.indexOf(' ') > 0) {
|
||||
s.append('(');
|
||||
s.append(pString);
|
||||
s.append(')');
|
||||
} else {
|
||||
s.append(pString);
|
||||
}
|
||||
|
||||
s.append('/');
|
||||
|
||||
String qString = q.toString();
|
||||
if (qString.indexOf(' ') > 0) {
|
||||
s.append('(');
|
||||
s.append(qString);
|
||||
s.append(')');
|
||||
} else {
|
||||
s.append(qString);
|
||||
}
|
||||
|
||||
return s.toString();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** Numerator. */
|
||||
private Polynomial.Rational p;
|
||||
|
||||
/** Denominator. */
|
||||
private Polynomial.Rational q;
|
||||
|
||||
}
|
|
@ -0,0 +1,536 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.algebra;
|
||||
|
||||
import java.math.BigInteger;
|
||||
/**
|
||||
* This class implements reduced rational numbers.
|
||||
|
||||
* @version $Id: RationalNumber.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class RationalNumber {
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* Build a null rational number
|
||||
*/
|
||||
public RationalNumber() {
|
||||
p = BigInteger.ZERO;
|
||||
q = BigInteger.ONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* Build a rational number from a numerator and a denominator.
|
||||
* @param numerator numerator of the rational number
|
||||
* @param denominator denominator of the rational number
|
||||
* @exception ArithmeticException if the denominator is zero
|
||||
*/
|
||||
public RationalNumber(long numerator, long denominator) {
|
||||
reset(numerator, denominator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* Build a rational number from a numerator and a denominator.
|
||||
* @param numerator numerator of the rational number
|
||||
* @param denominator denominator of the rational number
|
||||
* @exception ArithmeticException if the denominator is zero
|
||||
*/
|
||||
public RationalNumber(BigInteger numerator, BigInteger denominator) {
|
||||
reset(numerator, denominator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* Build a rational number from a single integer
|
||||
* @param l value of the rational number
|
||||
*/
|
||||
public RationalNumber(long l) {
|
||||
p = BigInteger.valueOf(l);
|
||||
q = BigInteger.ONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* Build a rational number from a single integer
|
||||
* @param i value of the rational number
|
||||
*/
|
||||
public RationalNumber(BigInteger i) {
|
||||
p = i;
|
||||
q = BigInteger.ONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy-constructor.
|
||||
* @param r rational number to copy
|
||||
*/
|
||||
public RationalNumber(RationalNumber r) {
|
||||
p = r.p;
|
||||
q = r.q;
|
||||
}
|
||||
|
||||
/** Reset the instance from a numerator and a denominator.
|
||||
* @param numerator numerator of the rational number
|
||||
* @param denominator denominator of the rational number
|
||||
* @exception ArithmeticException if the denominator is zero
|
||||
*/
|
||||
public void reset(long numerator, long denominator) {
|
||||
if (denominator == 0l) {
|
||||
throw new ArithmeticException("divide by zero");
|
||||
}
|
||||
|
||||
p = BigInteger.valueOf(numerator);
|
||||
q = BigInteger.valueOf(denominator);
|
||||
|
||||
if (q.signum() < 0) {
|
||||
p = p.negate();
|
||||
q = q.negate();
|
||||
}
|
||||
|
||||
simplify();
|
||||
|
||||
}
|
||||
|
||||
/** Reset the instance from a numerator and a denominator.
|
||||
* @param numerator numerator of the rational number
|
||||
* @param denominator denominator of the rational number
|
||||
* @exception ArithmeticException if the denominator is zero
|
||||
*/
|
||||
public void reset(BigInteger numerator, BigInteger denominator) {
|
||||
if (denominator.signum() == 0) {
|
||||
throw new ArithmeticException("divide by zero");
|
||||
}
|
||||
|
||||
p = numerator;
|
||||
q = denominator;
|
||||
|
||||
if (q.signum() < 0) {
|
||||
p = p.negate();
|
||||
q = q.negate();
|
||||
}
|
||||
|
||||
simplify();
|
||||
|
||||
}
|
||||
|
||||
/** Reset the instance from a single integer
|
||||
* @param l value of the rational number
|
||||
*/
|
||||
public void reset(long l) {
|
||||
p = BigInteger.valueOf(l);
|
||||
q = BigInteger.ONE;
|
||||
}
|
||||
|
||||
/** Reset the instance from a single integer
|
||||
* @param i value of the rational number
|
||||
*/
|
||||
public void reset(BigInteger i) {
|
||||
p = i;
|
||||
q = BigInteger.ONE;
|
||||
}
|
||||
|
||||
/** Reset the instance from another rational number.
|
||||
* @param r rational number to copy
|
||||
*/
|
||||
public void reset(RationalNumber r) {
|
||||
p = r.p;
|
||||
q = r.q;
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate the instance
|
||||
*/
|
||||
public void negateSelf() {
|
||||
p = p.negate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate a rational number.
|
||||
* @param r rational number to negate
|
||||
* @return a new rational number which is the opposite of r
|
||||
*/
|
||||
public static RationalNumber negate(RationalNumber r) {
|
||||
RationalNumber copy = new RationalNumber(r);
|
||||
copy.negateSelf();
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a rational number to the instance.
|
||||
* @param r rational number to add.
|
||||
*/
|
||||
public void addToSelf(RationalNumber r) {
|
||||
p = p.multiply(r.q).add(r.p.multiply(q));
|
||||
q = q.multiply(r.q);
|
||||
simplify();
|
||||
}
|
||||
|
||||
/** Add two rational numbers.
|
||||
* @param r1 first rational number
|
||||
* @param r2 second rational number
|
||||
* @return a new rational number which is the sum of r1 and r2
|
||||
*/
|
||||
public static RationalNumber add(RationalNumber r1, RationalNumber r2) {
|
||||
return new RationalNumber(r1.p.multiply(r2.q).add(r2.p.multiply(r1.q)),
|
||||
r1.q.multiply(r2.q));
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract a rational number to the instance.
|
||||
* @param r rational number to subtract.
|
||||
*/
|
||||
public void subtractFromSelf(RationalNumber r) {
|
||||
p = p.multiply(r.q).subtract(r.p.multiply(q));
|
||||
q = q.multiply(r.q);
|
||||
simplify();
|
||||
}
|
||||
|
||||
/** Subtract two rational numbers.
|
||||
* @param r1 first rational number
|
||||
* @param r2 second rational number
|
||||
* @return a new rational number which is the difference r1 minus r2
|
||||
*/
|
||||
public static RationalNumber subtract(RationalNumber r1, RationalNumber r2) {
|
||||
return new RationalNumber(r1.p.multiply(r2.q).subtract(r2.p.multiply(r1.q)),
|
||||
r1.q.multiply(r2.q));
|
||||
}
|
||||
|
||||
/** Multiply the instance by an integer.
|
||||
* @param l integer to multiply by
|
||||
*/
|
||||
public void multiplySelf(long l) {
|
||||
p = p.multiply(BigInteger.valueOf(l));
|
||||
simplify();
|
||||
}
|
||||
|
||||
/** Multiply the instance by an integer.
|
||||
* @param i integer to multiply by
|
||||
*/
|
||||
public void multiplySelf(BigInteger i) {
|
||||
p = p.multiply(i);
|
||||
simplify();
|
||||
}
|
||||
|
||||
/** Multiply a rational number by an integer.
|
||||
* @param l integer to multiply by
|
||||
*/
|
||||
public static RationalNumber multiply(RationalNumber r, long l) {
|
||||
return new RationalNumber(r.p.multiply(BigInteger.valueOf(l)), r.q);
|
||||
}
|
||||
|
||||
/** Multiply a rational number by an integer.
|
||||
* @param i integer to multiply by
|
||||
*/
|
||||
public static RationalNumber multiply(RationalNumber r, BigInteger i) {
|
||||
return new RationalNumber(r.p.multiply(i), r.q);
|
||||
}
|
||||
|
||||
/** Multiply the instance by a rational number.
|
||||
* @param r rational number to multiply by
|
||||
*/
|
||||
public void multiplySelf(RationalNumber r) {
|
||||
p = p.multiply(r.p);
|
||||
q = q.multiply(r.q);
|
||||
simplify();
|
||||
}
|
||||
|
||||
/** Multiply two rational numbers.
|
||||
* @param r1 first rational number
|
||||
* @param r2 second rational number
|
||||
* @return a new rational number which is the product of r1 and r2
|
||||
*/
|
||||
public static RationalNumber multiply(RationalNumber r1, RationalNumber r2) {
|
||||
return new RationalNumber(r1.p.multiply(r2.p),
|
||||
r1.q.multiply(r2.q));
|
||||
}
|
||||
|
||||
/** Divide the instance by an integer.
|
||||
* @param l integer to divide by
|
||||
* @exception ArithmeticException if l is zero
|
||||
*/
|
||||
public void divideSelf(long l) {
|
||||
|
||||
if (l == 0l) {
|
||||
throw new ArithmeticException("divide by zero");
|
||||
} else if (l > 0l) {
|
||||
q = q.multiply(BigInteger.valueOf(l));
|
||||
} else {
|
||||
p = p.negate();
|
||||
q = q.multiply(BigInteger.valueOf(-l));
|
||||
}
|
||||
|
||||
simplify();
|
||||
|
||||
}
|
||||
|
||||
/** Divide the instance by an integer.
|
||||
* @param i integer to divide by
|
||||
* @exception ArithmeticException if l is zero
|
||||
*/
|
||||
public void divideSelf(BigInteger i) {
|
||||
|
||||
if (i.signum() == 0) {
|
||||
throw new ArithmeticException("divide by zero");
|
||||
} else if (i.signum() > 0) {
|
||||
q = q.multiply(i);
|
||||
} else {
|
||||
p = p.negate();
|
||||
q = q.multiply(i.negate());
|
||||
}
|
||||
|
||||
simplify();
|
||||
|
||||
}
|
||||
|
||||
/** Divide a rational number by an integer
|
||||
* @param r rational number
|
||||
* @param l integer
|
||||
* @return a new rational number which is the quotient of r by l
|
||||
* @exception ArithmeticException if l is zero
|
||||
*/
|
||||
public static RationalNumber divide(RationalNumber r, long l) {
|
||||
RationalNumber copy = new RationalNumber(r);
|
||||
copy.divideSelf(l);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/** Divide a rational number by an integer
|
||||
* @param r rational number
|
||||
* @param i integer
|
||||
* @return a new rational number which is the quotient of r by l
|
||||
* @exception ArithmeticException if l is zero
|
||||
*/
|
||||
public static RationalNumber divide(RationalNumber r, BigInteger i) {
|
||||
RationalNumber copy = new RationalNumber(r);
|
||||
copy.divideSelf(i);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/** Divide the instance by a rational number.
|
||||
* @param r rational number to divide by
|
||||
* @exception ArithmeticException if r is zero
|
||||
*/
|
||||
public void divideSelf(RationalNumber r) {
|
||||
|
||||
if (r.p.signum() == 0) {
|
||||
throw new ArithmeticException("divide by zero");
|
||||
}
|
||||
|
||||
p = p.multiply(r.q);
|
||||
q = q.multiply(r.p);
|
||||
|
||||
if (q.signum() < 0) {
|
||||
p = p.negate();
|
||||
q = q.negate();
|
||||
}
|
||||
|
||||
simplify();
|
||||
|
||||
}
|
||||
|
||||
/** Divide two rational numbers.
|
||||
* @param r1 first rational number
|
||||
* @param r2 second rational number
|
||||
* @return a new rational number which is the quotient of r1 by r2
|
||||
* @exception ArithmeticException if r2 is zero
|
||||
*/
|
||||
public static RationalNumber divide(RationalNumber r1, RationalNumber r2) {
|
||||
RationalNumber copy = new RationalNumber(r1);
|
||||
copy.divideSelf(r2);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/** Invert the instance.
|
||||
* Replace the instance by its inverse.
|
||||
* @exception ArithmeticException if the instance is zero
|
||||
*/
|
||||
public void invertSelf() {
|
||||
|
||||
if (p.signum() == 0) {
|
||||
throw new ArithmeticException("divide by zero");
|
||||
}
|
||||
|
||||
BigInteger tmp = p;
|
||||
p = q;
|
||||
q = tmp;
|
||||
|
||||
if (q.signum() < 0) {
|
||||
p = p.negate();
|
||||
q = q.negate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Invert a rational number.
|
||||
* @param r rational number to invert
|
||||
* @return a new rational number which is the inverse of r
|
||||
* @exception ArithmeticException if r is zero
|
||||
*/
|
||||
public static RationalNumber invert(RationalNumber r) {
|
||||
return new RationalNumber(r.q, r.p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the product of two rational numbers to the instance.
|
||||
* This operation is equivalent to
|
||||
* <code>addToSelf(RationalNumber.multiply(r1, r2))</code> except
|
||||
* that no intermediate simplification is attempted.
|
||||
* @param r1 first term of the product to add
|
||||
* @param r2 second term of the product to add
|
||||
*/
|
||||
public void multiplyAndAddToSelf(RationalNumber r1, RationalNumber r2) {
|
||||
BigInteger r1qr2q = r1.q.multiply(r2.q);
|
||||
p = p.multiply(r1qr2q).add(r1.p.multiply(r2.p).multiply(q));
|
||||
q = q.multiply(r1qr2q);
|
||||
simplify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract the product of two rational numbers from the instance.
|
||||
* This operation is equivalent to
|
||||
* <code>subtractFromSelf(RationalNumber.multiply(r1, r2))</code>
|
||||
* except that no intermediate simplification is attempted.
|
||||
* @param r1 first term of the product to subtract
|
||||
* @param r2 second term of the product to subtract
|
||||
*/
|
||||
public void multiplyAndSubtractFromSelf(RationalNumber r1, RationalNumber r2) {
|
||||
BigInteger r1qr2q = r1.q.multiply(r2.q);
|
||||
p = p.multiply(r1qr2q).subtract(r1.p.multiply(r2.p).multiply(q));
|
||||
q = q.multiply(r1qr2q);
|
||||
simplify();
|
||||
}
|
||||
|
||||
/** Simplify a rational number by removing common factors.
|
||||
*/
|
||||
private void simplify() {
|
||||
if (p.signum() == 0) {
|
||||
q = BigInteger.ONE;
|
||||
} else {
|
||||
BigInteger gcd = p.gcd(q);
|
||||
p = p.divide(gcd);
|
||||
q = q.divide(gcd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the numerator.
|
||||
* @return the signed numerator
|
||||
*/
|
||||
public BigInteger getNumerator() {
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the denominator.
|
||||
* @return the denominator (always positive)
|
||||
*/
|
||||
public BigInteger getDenominator() {
|
||||
return q;
|
||||
}
|
||||
|
||||
/** Check if the number is zero.
|
||||
* @return true if the number is zero
|
||||
*/
|
||||
public boolean isZero() {
|
||||
return p.signum() == 0;
|
||||
}
|
||||
|
||||
/** Check if the number is one.
|
||||
* @return true if the number is one
|
||||
*/
|
||||
public boolean isOne() {
|
||||
return (p.compareTo(BigInteger.ONE) == 0)
|
||||
&& (q.compareTo(BigInteger.ONE) == 0);
|
||||
}
|
||||
|
||||
/** Check if the number is integer.
|
||||
* @return true if the number is an integer
|
||||
*/
|
||||
public boolean isInteger() {
|
||||
return q.compareTo(BigInteger.ONE) == 0;
|
||||
}
|
||||
|
||||
/** Check if the number is negative.
|
||||
* @return true if the number is negative
|
||||
*/
|
||||
public boolean isNegative() {
|
||||
return p.signum() < 0;
|
||||
}
|
||||
|
||||
/** Get the absolute value of a rational number.
|
||||
* @param r rational number from which we want the absolute value
|
||||
* @return a new rational number which is the absolute value of r
|
||||
*/
|
||||
public static RationalNumber abs(RationalNumber r) {
|
||||
return new RationalNumber(r.p.abs(), r.q);
|
||||
}
|
||||
|
||||
/** Return the <code>double</code> value of the instance.
|
||||
* @return the double value of the instance
|
||||
*/
|
||||
public double doubleValue() {
|
||||
BigInteger[] result = p.divideAndRemainder(q);
|
||||
return result[0].doubleValue()
|
||||
+ (result[1].doubleValue() / q.doubleValue());
|
||||
}
|
||||
|
||||
/** Check if the instance is equal to another rational number.
|
||||
* Equality here is having the same value.
|
||||
* @return true if the object is a rational number which has the
|
||||
* same value as the instance
|
||||
*/
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof RationalNumber) {
|
||||
RationalNumber r = (RationalNumber) o;
|
||||
return (p.compareTo(r.p) == 0) && (q.compareTo(r.q) == 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns a hash code value for the object.
|
||||
* The hash code value is computed from the reduced numerator and
|
||||
* denominator, hence equal rational numbers have the same hash code,
|
||||
* as required by the method specification.
|
||||
* @return a hash code value for this object.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return p.hashCode() ^ q.hashCode();
|
||||
}
|
||||
|
||||
/** Returns a string representation of the rational number.
|
||||
* The representation is reduced: there is no common factor left
|
||||
* between the numerator and the denominator. The '/' character and
|
||||
* the denominator are displayed only if the denominator is not
|
||||
* one. The sign is on the numerator.
|
||||
* @return string representation of the rational number
|
||||
*/
|
||||
public String toString() {
|
||||
return p + ((q.compareTo(BigInteger.ONE) == 0) ? "" : ("/" + q));
|
||||
}
|
||||
|
||||
/** Numerator. */
|
||||
private BigInteger p;
|
||||
|
||||
/** Denominator. */
|
||||
private BigInteger q;
|
||||
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.estimation;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** This class represent the estimated parameters of an estimation problem.
|
||||
|
||||
* <p>The parameters of an estimation problem have a name, a value and
|
||||
* a bound flag. The value of bound parameters is considered trusted
|
||||
* and the solvers should not adjust them. On the other hand, the
|
||||
* solvers should adjust the value of unbounds parameters until they
|
||||
* satisfy convergence criterions specific to each solver.</p>
|
||||
|
||||
* @version $Id: EstimatedParameter.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class EstimatedParameter
|
||||
implements Serializable {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an instance from a first estimate of the parameter,
|
||||
* initially considered unbound.
|
||||
* @param name name of the parameter
|
||||
* @param firstEstimate first estimate of the parameter
|
||||
*/
|
||||
public EstimatedParameter(String name, double firstEstimate) {
|
||||
this.name = name;
|
||||
estimate = firstEstimate;
|
||||
bound = false;
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an instance from a first estimate of the parameter and a
|
||||
* bound flag
|
||||
* @param name name of the parameter
|
||||
* @param firstEstimate first estimate of the parameter
|
||||
* @param bound flag, should be true if the parameter is bound
|
||||
*/
|
||||
public EstimatedParameter(String name,
|
||||
double firstEstimate,
|
||||
boolean bound) {
|
||||
this.name = name;
|
||||
estimate = firstEstimate;
|
||||
this.bound = bound;
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* Build a copy of a parameter
|
||||
* @param parameter instance to copy
|
||||
*/
|
||||
public EstimatedParameter(EstimatedParameter parameter) {
|
||||
name = parameter.name;
|
||||
estimate = parameter.estimate;
|
||||
bound = parameter.bound;
|
||||
}
|
||||
|
||||
/** Set a new estimated value for the parameter.
|
||||
* @param estimate new estimate for the parameter
|
||||
*/
|
||||
public void setEstimate(double estimate) {
|
||||
this.estimate = estimate;
|
||||
}
|
||||
|
||||
/** Get the current estimate of the parameter
|
||||
* @return current estimate
|
||||
*/
|
||||
public double getEstimate() {
|
||||
return estimate;
|
||||
}
|
||||
|
||||
/** get the name of the parameter
|
||||
* @return parameter name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/** Set the bound flag of the parameter
|
||||
* @param bound this flag should be set to true if the parameter is
|
||||
* bound (i.e. if it should not be adjusted by the solver).
|
||||
*/
|
||||
public void setBound(boolean bound) {
|
||||
this.bound = bound;
|
||||
}
|
||||
|
||||
/** Check if the parameter is bound
|
||||
* @return true if the parameter is bound */
|
||||
public boolean isBound() {
|
||||
return bound;
|
||||
}
|
||||
|
||||
/** Name of the parameter */
|
||||
private String name;
|
||||
|
||||
/** Current value of the parameter */
|
||||
protected double estimate;
|
||||
|
||||
/** Indicator for bound parameters
|
||||
* (ie parameters that should not be estimated)
|
||||
*/
|
||||
private boolean bound;
|
||||
|
||||
private static final long serialVersionUID = -555440800213416949L;
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.estimation;
|
||||
|
||||
import org.spaceroots.mantissa.MantissaException;
|
||||
|
||||
/** This class represents exceptions thrown by the estimation solvers.
|
||||
|
||||
* @version $Id: EstimationException.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class EstimationException
|
||||
extends MantissaException {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an exception by translating the specified message
|
||||
* @param message message to translate
|
||||
*/
|
||||
public EstimationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an exception by translating and formating a message
|
||||
* @param specifier format specifier (to be translated)
|
||||
* @param parts to insert in the format (no translation)
|
||||
*/
|
||||
public EstimationException(String specifier, String[] parts) {
|
||||
super(specifier, parts);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an exception from a cause
|
||||
* @param cause cause of this exception
|
||||
*/
|
||||
public EstimationException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1613719630569355278L;
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.estimation;
|
||||
|
||||
/** This interface represents an estimation problem.
|
||||
|
||||
* <p>This interface should be implemented by all real estimation
|
||||
* problems before they can be handled by the estimators through the
|
||||
* {@link Estimator#estimate Estimator.estimate} method.</p>
|
||||
|
||||
* <p>An estimation problem, as seen by a solver is a set of
|
||||
* parameters and a set of measurements. The parameters are adjusted
|
||||
* during the estimation through the {@link #getUnboundParameters
|
||||
* getUnboundParameters} and {@link EstimatedParameter#setEstimate
|
||||
* EstimatedParameter.setEstimate} methods. The measurements both have
|
||||
* a measured value which is generally fixed at construction and a
|
||||
* theoretical value which depends on the model and hence varies as
|
||||
* the parameters are adjusted. The purpose of the solver is to reduce
|
||||
* the residual between these values, it can retrieve the measurements
|
||||
* through the {@link #getMeasurements getMeasurements} method.</p>
|
||||
|
||||
* @see Estimator
|
||||
* @see WeightedMeasurement
|
||||
|
||||
* @version $Id: EstimationProblem.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public interface EstimationProblem {
|
||||
/** Get the measurements of an estimation problem.
|
||||
* @return measurements
|
||||
*/
|
||||
public WeightedMeasurement[] getMeasurements();
|
||||
|
||||
/** Get the unbound parameters of the problem.
|
||||
* @return unbound parameters
|
||||
*/
|
||||
public EstimatedParameter[] getUnboundParameters();
|
||||
|
||||
/** Get all the parameters of the problem.
|
||||
* @return parameters
|
||||
*/
|
||||
public EstimatedParameter[] getAllParameters();
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.estimation;
|
||||
|
||||
/** This interface represents solvers for estimation problems.
|
||||
|
||||
* <p>The classes which are devoted to solve estimation problems
|
||||
* should implement this interface. The problems which can be handled
|
||||
* should implement the {@link EstimationProblem} interface which
|
||||
* gather all the information needed by the solver.</p>
|
||||
|
||||
* <p>The interface is composed only of the {@link #estimate estimate}
|
||||
* method.</p>
|
||||
|
||||
* @see EstimationProblem
|
||||
|
||||
* @version $Id: Estimator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public interface Estimator {
|
||||
|
||||
/** Solve an estimation problem.
|
||||
|
||||
* <p>The method should set the parameters of the problem to several
|
||||
* trial values until it reaches convergence. If this method returns
|
||||
* normally (i.e. without throwing an exception), then the best
|
||||
* estimate of the parameters can be retrieved from the problem
|
||||
* itself, through the {@link EstimationProblem#getAllParameters
|
||||
* EstimationProblem.getAllParameters} method.</p>
|
||||
|
||||
* @param problem estimation problem to solve
|
||||
* @exception EstimationException if the problem cannot be solved
|
||||
|
||||
*/
|
||||
public void estimate(EstimationProblem problem)
|
||||
throws EstimationException;
|
||||
|
||||
/** Get the Root Mean Square value.
|
||||
* Get the Root Mean Square value, i.e. the root of the arithmetic
|
||||
* mean of the square of all weighted residuals. This is related to the
|
||||
* criterion that is minimized by the estimator as follows: if
|
||||
* <em>c</em> if the criterion, and <em>n</em> is the number of
|
||||
* measurements, the the RMS is <em>sqrt (c/n)</em>.
|
||||
* @param problem estimation problem
|
||||
* @return RMS value
|
||||
*/
|
||||
public double getRMS(EstimationProblem problem);
|
||||
|
||||
}
|
|
@ -0,0 +1,230 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.estimation;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.spaceroots.mantissa.linalg.Matrix;
|
||||
import org.spaceroots.mantissa.linalg.GeneralMatrix;
|
||||
import org.spaceroots.mantissa.linalg.SymetricalMatrix;
|
||||
import org.spaceroots.mantissa.linalg.SingularMatrixException;
|
||||
|
||||
/** This class implements a solver for estimation problems.
|
||||
|
||||
* <p>This class solves estimation problems using a weighted least
|
||||
* squares criterion on the measurement residuals. It uses a
|
||||
* Gauss-Newton algorithm.</p>
|
||||
|
||||
* @version $Id: GaussNewtonEstimator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class GaussNewtonEstimator
|
||||
implements Estimator, Serializable {
|
||||
|
||||
/** Simple constructor.
|
||||
|
||||
* <p>This constructor build an estimator and store its convergence
|
||||
* characteristics.</p>
|
||||
|
||||
* <p>An estimator is considered to have converged whenever either
|
||||
* the criterion goes below a physical threshold under which
|
||||
* improvements are considered useless or when the algorithm is
|
||||
* unable to improve it (even if it is still high). The first
|
||||
* condition that is met stops the iterations.</p>
|
||||
|
||||
* <p>The fact an estimator has converged does not mean that the
|
||||
* model accurately fits the measurements. It only means no better
|
||||
* solution can be found, it does not mean this one is good. Such an
|
||||
* analysis is left to the caller.</p>
|
||||
|
||||
* <p>If neither conditions are fulfilled before a given number of
|
||||
* iterations, the algorithm is considered to have failed and an
|
||||
* {@link EstimationException} is thrown.</p>
|
||||
|
||||
* @param maxIterations maximum number of iterations allowed
|
||||
* @param convergence criterion threshold below which we do not need
|
||||
* to improve the criterion anymore
|
||||
* @param steadyStateThreshold steady state detection threshold, the
|
||||
* problem has converged has reached a steady state if
|
||||
* <code>Math.abs (Jn - Jn-1) < Jn * convergence</code>, where
|
||||
* <code>Jn</code> and <code>Jn-1</code> are the current and
|
||||
* preceding criterion value (square sum of the weighted residuals
|
||||
* of considered measurements).
|
||||
* @param epsilon threshold under which the matrix of the linearized
|
||||
* problem is considered singular (see {@link
|
||||
* org.spaceroots.mantissa.linalg.SquareMatrix#solve(Matrix,double)
|
||||
* SquareMatrix.solve}). */
|
||||
public GaussNewtonEstimator(int maxIterations,
|
||||
double convergence,
|
||||
double steadyStateThreshold,
|
||||
double epsilon) {
|
||||
this.maxIterations = maxIterations;
|
||||
this.steadyStateThreshold = steadyStateThreshold;
|
||||
this.convergence = convergence;
|
||||
this.epsilon = epsilon;
|
||||
}
|
||||
|
||||
/** Solve an estimation problem using a least squares criterion.
|
||||
|
||||
* <p>This method set the unbound parameters of the given problem
|
||||
* starting from their current values through several iterations. At
|
||||
* each step, the unbound parameters are changed in order to
|
||||
* minimize a weighted least square criterion based on the
|
||||
* measurements of the problem.</p>
|
||||
|
||||
* <p>The iterations are stopped either when the criterion goes
|
||||
* below a physical threshold under which improvement are considered
|
||||
* useless or when the algorithm is unable to improve it (even if it
|
||||
* is still high). The first condition that is met stops the
|
||||
* iterations. If the convergence it nos reached before the maximum
|
||||
* number of iterations, an {@link EstimationException} is
|
||||
* thrown.</p>
|
||||
|
||||
* @param problem estimation problem to solve
|
||||
* @exception EstimationException if the problem cannot be solved
|
||||
|
||||
* @see EstimationProblem
|
||||
|
||||
*/
|
||||
public void estimate(EstimationProblem problem)
|
||||
throws EstimationException {
|
||||
int iterations = 0;
|
||||
double previous = 0.0;
|
||||
double current = 0.0;
|
||||
|
||||
// iterate until convergence is reached
|
||||
do {
|
||||
|
||||
if (++iterations > maxIterations) {
|
||||
throw new EstimationException ("unable to converge in {0} iterations",
|
||||
new String[] {
|
||||
Integer.toString(maxIterations)
|
||||
});
|
||||
}
|
||||
|
||||
// perform one iteration
|
||||
linearEstimate(problem);
|
||||
|
||||
previous = current;
|
||||
current = evaluateCriterion(problem);
|
||||
|
||||
} while ((iterations < 2)
|
||||
|| (Math.abs(previous - current) > (current * steadyStateThreshold)
|
||||
&& (Math.abs(current) > convergence)));
|
||||
|
||||
}
|
||||
|
||||
/** Estimate the solution of a linear least square problem.
|
||||
|
||||
* <p>The Gauss-Newton algorithm is iterative. Each iteration
|
||||
* consist in solving a linearized least square problem. Several
|
||||
* iterations are needed for general problems since the
|
||||
* linearization is only an approximation of the problem
|
||||
* behaviour. However, for linear problems one iteration is enough
|
||||
* to get the solution. This method is provided in the public
|
||||
* interface in order to handle more efficiently these linear
|
||||
* problems.</p>
|
||||
|
||||
* @param problem estimation problem to solve
|
||||
* @exception EstimationException if the problem cannot be solved
|
||||
|
||||
*/
|
||||
public void linearEstimate(EstimationProblem problem)
|
||||
throws EstimationException {
|
||||
|
||||
EstimatedParameter[] parameters = problem.getUnboundParameters();
|
||||
WeightedMeasurement[] measurements = problem.getMeasurements();
|
||||
|
||||
// build the linear problem
|
||||
GeneralMatrix b = new GeneralMatrix(parameters.length, 1);
|
||||
SymetricalMatrix a = new SymetricalMatrix(parameters.length);
|
||||
for (int i = 0; i < measurements.length; ++i) {
|
||||
if (! measurements [i].isIgnored()) {
|
||||
double weight = measurements[i].getWeight();
|
||||
double residual = measurements[i].getResidual();
|
||||
|
||||
// compute the normal equation
|
||||
double[] grad = new double[parameters.length];
|
||||
Matrix bDecrement = new GeneralMatrix(parameters.length, 1);
|
||||
for (int j = 0; j < parameters.length; ++j) {
|
||||
grad[j] = measurements[i].getPartial(parameters[j]);
|
||||
bDecrement.setElement(j, 0, weight * residual * grad[j]);
|
||||
}
|
||||
|
||||
// update the matrices
|
||||
a.selfAddWAAt(weight, grad);
|
||||
b.selfAdd(bDecrement);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
// solve the linearized least squares problem
|
||||
Matrix dX = a.solve(b, epsilon);
|
||||
|
||||
// update the estimated parameters
|
||||
for (int i = 0; i < parameters.length; ++i) {
|
||||
parameters[i].setEstimate(parameters[i].getEstimate()
|
||||
+ dX.getElement(i, 0));
|
||||
}
|
||||
|
||||
} catch(SingularMatrixException e) {
|
||||
throw new EstimationException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private double evaluateCriterion(EstimationProblem problem) {
|
||||
double criterion = 0.0;
|
||||
WeightedMeasurement[] measurements = problem.getMeasurements();
|
||||
|
||||
for (int i = 0; i < measurements.length; ++i) {
|
||||
double residual = measurements[i].getResidual();
|
||||
criterion += measurements[i].getWeight() * residual * residual;
|
||||
}
|
||||
|
||||
return criterion;
|
||||
|
||||
}
|
||||
|
||||
/** Get the Root Mean Square value.
|
||||
* Get the Root Mean Square value, i.e. the root of the arithmetic
|
||||
* mean of the square of all weighted residuals. This is related to the
|
||||
* criterion that is minimized by the estimator as follows: if
|
||||
* <em>c</em> if the criterion, and <em>n</em> is the number of
|
||||
* measurements, then the RMS is <em>sqrt (c/n)</em>.
|
||||
* @param problem estimation problem
|
||||
* @return RMS value
|
||||
*/
|
||||
public double getRMS(EstimationProblem problem) {
|
||||
double criterion = evaluateCriterion(problem);
|
||||
int n = problem.getMeasurements().length;
|
||||
return Math.sqrt(criterion / n);
|
||||
}
|
||||
|
||||
private int maxIterations;
|
||||
private double steadyStateThreshold;
|
||||
private double convergence;
|
||||
private double epsilon;
|
||||
|
||||
private static final long serialVersionUID = -7606628156644194170L;
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.estimation;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** This class implements a solver for estimation problems.
|
||||
* @deprecated this class has been replaced by the {@link
|
||||
* org.spaceroots.mantissa.estimation.GaussNewtonEstimator GaussNewtonEstimator}
|
||||
* class. It is now a simple wrapper delegating everything to {@link
|
||||
* org.spaceroots.mantissa.estimation.GaussNewtonEstimator GaussNewtonEstimator}
|
||||
* @version $Id: LeastSquaresEstimator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
*/
|
||||
public class LeastSquaresEstimator implements Estimator, Serializable {
|
||||
|
||||
/** Simple constructor.
|
||||
* @see org.spaceroots.mantissa.estimation.GaussNewtonEstimator#GaussNewtonEstimator(int,
|
||||
* double, double, double)
|
||||
*/
|
||||
public LeastSquaresEstimator(int maxIterations,
|
||||
double convergence,
|
||||
double steadyStateThreshold,
|
||||
double epsilon) {
|
||||
estimator = new GaussNewtonEstimator(maxIterations,
|
||||
convergence,
|
||||
steadyStateThreshold,
|
||||
epsilon);
|
||||
}
|
||||
|
||||
/** Solve an estimation problem using a least squares criterion.
|
||||
* @see org.spaceroots.mantissa.estimation.GaussNewtonEstimator#estimate
|
||||
*/
|
||||
public void estimate(EstimationProblem problem)
|
||||
throws EstimationException {
|
||||
estimator.estimate(problem);
|
||||
}
|
||||
|
||||
/** Estimate the solution of a linear least square problem.
|
||||
* @see org.spaceroots.mantissa.estimation.GaussNewtonEstimator#linearEstimate
|
||||
*/
|
||||
public void linearEstimate(EstimationProblem problem)
|
||||
throws EstimationException {
|
||||
estimator.linearEstimate(problem);
|
||||
}
|
||||
|
||||
/** Get the Root Mean Square value.
|
||||
* @see org.spaceroots.mantissa.estimation.GaussNewtonEstimator#getRMS
|
||||
*/
|
||||
public double getRMS(EstimationProblem problem) {
|
||||
return estimator.getRMS(problem);
|
||||
}
|
||||
|
||||
private GaussNewtonEstimator estimator;
|
||||
|
||||
private static final long serialVersionUID = -7542643494637247770L;
|
||||
|
||||
}
|
|
@ -0,0 +1,972 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.estimation;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
|
||||
/** This class solves a least squares problem.
|
||||
|
||||
* <p>This implementation <em>should</em> work even for over-determined systems
|
||||
* (i.e. systems having more variables than equations). Over-determined systems
|
||||
* are solved by ignoring the variables which have the smallest impact according
|
||||
* to their jacobian column norm. Only the rank of the matrix and some loop bounds
|
||||
* are changed to implement this. This feature has undergone only basic testing
|
||||
* for now and should still be considered experimental.</p>
|
||||
|
||||
* <p>The resolution engine is a simple translation of the MINPACK <a
|
||||
* href="http://www.netlib.org/minpack/lmder.f">lmder</a> routine with minor
|
||||
* changes. The changes include the over-determined resolution and the Q.R.
|
||||
* decomposition which has been rewritten following the algorithm described in the
|
||||
* P. Lascaux and R. Theodor book <i>Analyse numérique matricielle
|
||||
* appliquée à l'art de l'ingénieur</i>, Masson 1986. The
|
||||
* redistribution policy for MINPACK is available <a
|
||||
* href="http://www.netlib.org/minpack/disclaimer">here</a>, for convenience, it
|
||||
* is reproduced below.</p>
|
||||
|
||||
* <table border="0" width="80%" cellpadding="10" align="center" bgcolor="#E0E0E0">
|
||||
* <tr><td>
|
||||
* Minpack Copyright Notice (1999) University of Chicago.
|
||||
* All rights reserved
|
||||
* </td></tr>
|
||||
* <tr><td>
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* <ol>
|
||||
* <li>Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.</li>
|
||||
* <li>Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.</li>
|
||||
* <li>The end-user documentation included with the redistribution, if any,
|
||||
* must include the following acknowledgment:
|
||||
* <code>This product includes software developed by the University of
|
||||
* Chicago, as Operator of Argonne National Laboratory.</code>
|
||||
* Alternately, this acknowledgment may appear in the software itself,
|
||||
* if and wherever such third-party acknowledgments normally appear.</li>
|
||||
* <li><strong>WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS"
|
||||
* WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT HOLDER, THE
|
||||
* UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND
|
||||
* THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE
|
||||
* OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY
|
||||
* OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR
|
||||
* USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF
|
||||
* THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4)
|
||||
* DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION
|
||||
* UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL
|
||||
* BE CORRECTED.</strong></li>
|
||||
* <li><strong>LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT
|
||||
* HOLDER, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF
|
||||
* ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT,
|
||||
* INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF
|
||||
* ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
* PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER
|
||||
* SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT
|
||||
* (INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE,
|
||||
* EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE
|
||||
* POSSIBILITY OF SUCH LOSS OR DAMAGES.</strong></li>
|
||||
* <ol></td></tr>
|
||||
* </table>
|
||||
|
||||
* @author Argonne National Laboratory. MINPACK project. March 1980 (original fortran)
|
||||
* @author Burton S. Garbow (original fortran)
|
||||
* @author Kenneth E. Hillstrom (original fortran)
|
||||
* @author Jorge J. More (original fortran)
|
||||
* @author Luc Maisonobe (Java translation)
|
||||
*/
|
||||
public class LevenbergMarquardtEstimator implements Serializable, Estimator {
|
||||
|
||||
/** Build an estimator for least squares problems.
|
||||
* <p>The default values for the algorithm settings are:
|
||||
* <ul>
|
||||
* <li>{@link #setInitialStepBoundFactor initial step bound factor}: 100.0</li>
|
||||
* <li>{@link #setMaxCostEval maximal cost evaluations}: 1000</li>
|
||||
* <li>{@link #setCostRelativeTolerance cost relative tolerance}: 1.0e-10</li>
|
||||
* <li>{@link #setParRelativeTolerance parameters relative tolerance}: 1.0e-10</li>
|
||||
* <li>{@link #setOrthoTolerance orthogonality tolerance}: 1.0e-10</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*/
|
||||
public LevenbergMarquardtEstimator() {
|
||||
// default values for the tuning parameters
|
||||
setInitialStepBoundFactor(100.0);
|
||||
setMaxCostEval(1000);
|
||||
setCostRelativeTolerance(1.0e-10);
|
||||
setParRelativeTolerance(1.0e-10);
|
||||
setOrthoTolerance(1.0e-10);
|
||||
}
|
||||
|
||||
/** Set the positive input variable used in determining the initial step bound.
|
||||
* This bound is set to the product of initialStepBoundFactor and the euclidean norm of diag*x if nonzero,
|
||||
* or else to initialStepBoundFactor itself. In most cases factor should lie
|
||||
* in the interval (0.1, 100.0). 100.0 is a generally recommended value
|
||||
* @param initialStepBoundFactor initial step bound factor
|
||||
* @see #estimate
|
||||
*/
|
||||
public void setInitialStepBoundFactor(double initialStepBoundFactor) {
|
||||
this.initialStepBoundFactor = initialStepBoundFactor;
|
||||
}
|
||||
|
||||
/** Set the maximal number of cost evaluations.
|
||||
* @param maxCostEval maximal number of cost evaluations
|
||||
* @see #estimate
|
||||
*/
|
||||
public void setMaxCostEval(int maxCostEval) {
|
||||
this.maxCostEval = maxCostEval;
|
||||
}
|
||||
|
||||
/** Set the desired relative error in the sum of squares.
|
||||
* @param costRelativeTolerance desired relative error in the sum of squares
|
||||
* @see #estimate
|
||||
*/
|
||||
public void setCostRelativeTolerance(double costRelativeTolerance) {
|
||||
this.costRelativeTolerance = costRelativeTolerance;
|
||||
}
|
||||
|
||||
/** Set the desired relative error in the approximate solution parameters.
|
||||
* @param parRelativeTolerance desired relative error
|
||||
* in the approximate solution parameters
|
||||
* @see #estimate
|
||||
*/
|
||||
public void setParRelativeTolerance(double parRelativeTolerance) {
|
||||
this.parRelativeTolerance = parRelativeTolerance;
|
||||
}
|
||||
|
||||
/** Set the desired max cosine on the orthogonality.
|
||||
* @param orthoTolerance desired max cosine on the orthogonality
|
||||
* between the function vector and the columns of the jacobian
|
||||
* @see #estimate
|
||||
*/
|
||||
public void setOrthoTolerance(double orthoTolerance) {
|
||||
this.orthoTolerance = orthoTolerance;
|
||||
}
|
||||
|
||||
/** Get the number of cost evaluations.
|
||||
* @return number of cost evaluations
|
||||
* */
|
||||
public int getCostEvaluations() {
|
||||
return costEvaluations;
|
||||
}
|
||||
|
||||
/** Get the number of jacobian evaluations.
|
||||
* @return number of jacobian evaluations
|
||||
* */
|
||||
public int getJacobianEvaluations() {
|
||||
return jacobianEvaluations;
|
||||
}
|
||||
|
||||
/** Update the jacobian matrix.
|
||||
*/
|
||||
private void updateJacobian() {
|
||||
++jacobianEvaluations;
|
||||
Arrays.fill(jacobian, 0);
|
||||
for (int i = 0, index = 0; i < rows; i++) {
|
||||
WeightedMeasurement wm = measurements[i];
|
||||
double factor = -Math.sqrt(wm.getWeight());
|
||||
for (int j = 0; j < cols; ++j) {
|
||||
jacobian[index++] = factor * wm.getPartial(parameters[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Update the residuals array and cost function value.
|
||||
*/
|
||||
private void updateResidualsAndCost() {
|
||||
++costEvaluations;
|
||||
cost = 0;
|
||||
for (int i = 0, index = 0; i < rows; i++, index += cols) {
|
||||
WeightedMeasurement wm = measurements[i];
|
||||
double residual = wm.getResidual();
|
||||
residuals[i] = Math.sqrt(wm.getWeight()) * residual;
|
||||
cost += wm.getWeight() * residual * residual;
|
||||
}
|
||||
cost = Math.sqrt(cost);
|
||||
}
|
||||
|
||||
/** Get the Root Mean Square value.
|
||||
* Get the Root Mean Square value, i.e. the root of the arithmetic
|
||||
* mean of the square of all weighted residuals. This is related to the
|
||||
* criterion that is minimized by the estimator as follows: if
|
||||
* <em>c</em> if the criterion, and <em>n</em> is the number of
|
||||
* measurements, then the RMS is <em>sqrt (c/n)</em>.
|
||||
* @param problem estimation problem
|
||||
* @return RMS value
|
||||
*/
|
||||
public double getRMS(EstimationProblem problem) {
|
||||
WeightedMeasurement[] wm = problem.getMeasurements();
|
||||
double criterion = 0;
|
||||
for (int i = 0; i < wm.length; ++i) {
|
||||
double residual = wm[i].getResidual();
|
||||
criterion += wm[i].getWeight() * residual * residual;
|
||||
}
|
||||
return Math.sqrt(criterion / wm.length);
|
||||
}
|
||||
|
||||
/** Solve an estimation problem using the Levenberg-Marquardt algorithm.
|
||||
* <p>The algorithm used is a modified Levenberg-Marquardt one, based
|
||||
* on the MINPACK <a href="http://www.netlib.org/minpack/lmder.f">lmder</a>
|
||||
* routine. The algorithm settings must have been set up before this method
|
||||
* is called with the {@link #setInitialStepBoundFactor},
|
||||
* {@link #setMaxCostEval}, {@link #setCostRelativeTolerance},
|
||||
* {@link #setParRelativeTolerance} and {@link #setOrthoTolerance} methods.
|
||||
* If these methods have not been called, the default values set up by the
|
||||
* {@link #LevenbergMarquardtEstimator() constructor} will be used.</p>
|
||||
* <p>The authors of the original fortran function are:</p>
|
||||
* <ul>
|
||||
* <li>Argonne National Laboratory. MINPACK project. March 1980</li>
|
||||
* <li>Burton S. Garbow</li>
|
||||
* <li>Kenneth E. Hillstrom</li>
|
||||
* <li>Jorge J. More</li>
|
||||
* </ul>
|
||||
* <p>Luc Maisonobe did the Java translation.</p>
|
||||
* @param problem estimation problem to solve
|
||||
* @exception EstimationException if convergence cannot be
|
||||
* reached with the specified algorithm settings or if there are more variables
|
||||
* than equations
|
||||
* @see #setInitialStepBoundFactor
|
||||
* @see #setMaxCostEval
|
||||
* @see #setCostRelativeTolerance
|
||||
* @see #setParRelativeTolerance
|
||||
* @see #setOrthoTolerance
|
||||
*/
|
||||
public void estimate(EstimationProblem problem)
|
||||
throws EstimationException {
|
||||
|
||||
// retrieve the equations and the parameters
|
||||
measurements = problem.getMeasurements();
|
||||
parameters = problem.getUnboundParameters();
|
||||
|
||||
// arrays shared with the other private methods
|
||||
rows = measurements.length;
|
||||
cols = parameters.length;
|
||||
solvedCols = Math.min(rows, cols);
|
||||
jacobian = new double[rows * cols];
|
||||
diagR = new double[cols];
|
||||
jacNorm = new double[cols];
|
||||
beta = new double[cols];
|
||||
permutation = new int[cols];
|
||||
lmDir = new double[cols];
|
||||
residuals = new double[rows];
|
||||
|
||||
// local variables
|
||||
double delta = 0, xNorm = 0;
|
||||
double[] diag = new double[cols];
|
||||
double[] oldX = new double[cols];
|
||||
double[] oldRes = new double[rows];
|
||||
double[] work1 = new double[cols];
|
||||
double[] work2 = new double[cols];
|
||||
double[] work3 = new double[cols];
|
||||
|
||||
// evaluate the function at the starting point and calculate its norm
|
||||
updateResidualsAndCost();
|
||||
|
||||
// outer loop
|
||||
lmPar = 0;
|
||||
costEvaluations = 0;
|
||||
jacobianEvaluations = 0;
|
||||
boolean firstIteration = true;
|
||||
while (costEvaluations < maxCostEval) {
|
||||
|
||||
// compute the Q.R. decomposition of the jacobian matrix
|
||||
updateJacobian();
|
||||
qrDecomposition();
|
||||
|
||||
// compute Qt.res
|
||||
qTy(residuals);
|
||||
|
||||
// now we don't need Q anymore,
|
||||
// so let jacobian contain the R matrix with its diagonal elements
|
||||
for (int k = 0; k < solvedCols; ++k) {
|
||||
int pk = permutation[k];
|
||||
jacobian[k * cols + pk] = diagR[pk];
|
||||
}
|
||||
|
||||
if (firstIteration) {
|
||||
|
||||
// scale the variables according to the norms of the columns
|
||||
// of the initial jacobian
|
||||
xNorm = 0;
|
||||
for (int k = 0; k < cols; ++k) {
|
||||
double dk = jacNorm[k];
|
||||
if (dk == 0) {
|
||||
dk = 1.0;
|
||||
}
|
||||
double xk = dk * parameters[k].getEstimate();
|
||||
xNorm += xk * xk;
|
||||
diag[k] = dk;
|
||||
}
|
||||
xNorm = Math.sqrt(xNorm);
|
||||
|
||||
// initialize the step bound delta
|
||||
delta = (xNorm == 0)
|
||||
? initialStepBoundFactor : (initialStepBoundFactor * xNorm);
|
||||
|
||||
}
|
||||
|
||||
// check orthogonality between function vector and jacobian columns
|
||||
double maxCosine = 0;
|
||||
if (cost != 0) {
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
int pj = permutation[j];
|
||||
double s = jacNorm[pj];
|
||||
if (s != 0) {
|
||||
double sum = 0;
|
||||
for (int i = 0, index = pj; i <= j; ++i, index += cols) {
|
||||
sum += jacobian[index] * residuals[i];
|
||||
}
|
||||
maxCosine = Math.max(maxCosine, Math.abs(sum) / (s * cost));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (maxCosine <= orthoTolerance) {
|
||||
return;
|
||||
}
|
||||
|
||||
// rescale if necessary
|
||||
for (int j = 0; j < cols; ++j) {
|
||||
diag[j] = Math.max(diag[j], jacNorm[j]);
|
||||
}
|
||||
|
||||
// inner loop
|
||||
for (double ratio = 0; ratio < 1.0e-4;) {
|
||||
|
||||
// save the state
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
int pj = permutation[j];
|
||||
oldX[pj] = parameters[pj].getEstimate();
|
||||
}
|
||||
double previousCost = cost;
|
||||
double[] tmpVec = residuals;
|
||||
residuals = oldRes;
|
||||
oldRes = tmpVec;
|
||||
|
||||
// determine the Levenberg-Marquardt parameter
|
||||
determineLMParameter(oldRes, delta, diag, work1, work2, work3);
|
||||
|
||||
// compute the new point and the norm of the evolution direction
|
||||
double lmNorm = 0;
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
int pj = permutation[j];
|
||||
lmDir[pj] = -lmDir[pj];
|
||||
parameters[pj].setEstimate(oldX[pj] + lmDir[pj]);
|
||||
double s = diag[pj] * lmDir[pj];
|
||||
lmNorm += s * s;
|
||||
}
|
||||
lmNorm = Math.sqrt(lmNorm);
|
||||
|
||||
// on the first iteration, adjust the initial step bound.
|
||||
if (firstIteration) {
|
||||
delta = Math.min(delta, lmNorm);
|
||||
}
|
||||
|
||||
// evaluate the function at x + p and calculate its norm
|
||||
updateResidualsAndCost();
|
||||
|
||||
// compute the scaled actual reduction
|
||||
double actRed = -1.0;
|
||||
if (0.1 * cost < previousCost) {
|
||||
double r = cost / previousCost;
|
||||
actRed = 1.0 - r * r;
|
||||
}
|
||||
|
||||
// compute the scaled predicted reduction
|
||||
// and the scaled directional derivative
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
int pj = permutation[j];
|
||||
double dirJ = lmDir[pj];
|
||||
work1[j] = 0;
|
||||
for (int i = 0, index = pj; i <= j; ++i, index += cols) {
|
||||
work1[i] += jacobian[index] * dirJ;
|
||||
}
|
||||
}
|
||||
double coeff1 = 0;
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
coeff1 += work1[j] * work1[j];
|
||||
}
|
||||
double pc2 = previousCost * previousCost;
|
||||
coeff1 = coeff1 / pc2;
|
||||
double coeff2 = lmPar * lmNorm * lmNorm / pc2;
|
||||
double preRed = coeff1 + 2 * coeff2;
|
||||
double dirDer = -(coeff1 + coeff2);
|
||||
|
||||
// ratio of the actual to the predicted reduction
|
||||
ratio = (preRed == 0) ? 0 : (actRed / preRed);
|
||||
|
||||
// update the step bound
|
||||
if (ratio <= 0.25) {
|
||||
double tmp =
|
||||
(actRed < 0) ? (0.5 * dirDer / (dirDer + 0.5 * actRed)) : 0.5;
|
||||
if ((0.1 * cost >= previousCost) || (tmp < 0.1)) {
|
||||
tmp = 0.1;
|
||||
}
|
||||
delta = tmp * Math.min(delta, 10.0 * lmNorm);
|
||||
lmPar /= tmp;
|
||||
} else if ((lmPar == 0) || (ratio >= 0.75)) {
|
||||
delta = 2 * lmNorm;
|
||||
lmPar *= 0.5;
|
||||
}
|
||||
|
||||
// test for successful iteration.
|
||||
if (ratio >= 1.0e-4) {
|
||||
// successful iteration, update the norm
|
||||
firstIteration = false;
|
||||
xNorm = 0;
|
||||
for (int k = 0; k < cols; ++k) {
|
||||
double xK = diag[k] * parameters[k].getEstimate();
|
||||
xNorm += xK * xK;
|
||||
}
|
||||
xNorm = Math.sqrt(xNorm);
|
||||
} else {
|
||||
// failed iteration, reset the previous values
|
||||
cost = previousCost;
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
int pj = permutation[j];
|
||||
parameters[pj].setEstimate(oldX[pj]);
|
||||
}
|
||||
tmpVec = residuals;
|
||||
residuals = oldRes;
|
||||
oldRes = tmpVec;
|
||||
}
|
||||
|
||||
// tests for convergence.
|
||||
if (((Math.abs(actRed) <= costRelativeTolerance)
|
||||
&& (preRed <= costRelativeTolerance)
|
||||
&& (ratio <= 2.0))
|
||||
|| (delta <= parRelativeTolerance * xNorm)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// tests for termination and stringent tolerances
|
||||
// (2.2204e-16 is the machine epsilon for IEEE754)
|
||||
if (costEvaluations >= maxCostEval) {
|
||||
break;
|
||||
}
|
||||
if ((Math.abs(actRed) <= 2.2204e-16)
|
||||
&& (preRed <= 2.2204e-16)
|
||||
&& (ratio <= 2.0)) {
|
||||
throw new EstimationException("cost relative tolerance is too small ({0}),"
|
||||
+ " no further reduction in the"
|
||||
+ " sum of squares is possible",
|
||||
new String[] {
|
||||
Double.toString(costRelativeTolerance)
|
||||
});
|
||||
} else if (delta <= 2.2204e-16 * xNorm) {
|
||||
throw new EstimationException("parameters relative tolerance is too small"
|
||||
+ " ({0}), no further improvement in"
|
||||
+ " the approximate solution is possible",
|
||||
new String[] {
|
||||
Double.toString(parRelativeTolerance)
|
||||
});
|
||||
} else if (maxCosine <= 2.2204e-16) {
|
||||
throw new EstimationException("orthogonality tolerance is too small ({0}),"
|
||||
+ " solution is orthogonal to the jacobian",
|
||||
new String[] {
|
||||
Double.toString(orthoTolerance)
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
throw new EstimationException("maximal number of evaluations exceeded ({0})",
|
||||
new String[] {
|
||||
Integer.toString(maxCostEval)
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/** Determine the Levenberg-Marquardt parameter.
|
||||
* <p>This implementation is a translation in Java of the MINPACK
|
||||
* <a href="http://www.netlib.org/minpack/lmpar.f">lmpar</a>
|
||||
* routine.</p>
|
||||
* <p>This method sets the lmPar and lmDir attributes.</p>
|
||||
* <p>The authors of the original fortran function are:</p>
|
||||
* <ul>
|
||||
* <li>Argonne National Laboratory. MINPACK project. March 1980</li>
|
||||
* <li>Burton S. Garbow</li>
|
||||
* <li>Kenneth E. Hillstrom</li>
|
||||
* <li>Jorge J. More</li>
|
||||
* </ul>
|
||||
* <p>Luc Maisonobe did the Java translation.</p>
|
||||
* @param qy array containing qTy
|
||||
* @param delta upper bound on the euclidean norm of diagR * lmDir
|
||||
* @param diag diagonal matrix
|
||||
* @param work1 work array
|
||||
* @param work2 work array
|
||||
* @param work3 work array
|
||||
*/
|
||||
private void determineLMParameter(double[] qy, double delta, double[] diag,
|
||||
double[] work1, double[] work2, double[] work3) {
|
||||
|
||||
// compute and store in x the gauss-newton direction, if the
|
||||
// jacobian is rank-deficient, obtain a least squares solution
|
||||
for (int j = 0; j < rank; ++j) {
|
||||
lmDir[permutation[j]] = qy[j];
|
||||
}
|
||||
for (int j = rank; j < cols; ++j) {
|
||||
lmDir[permutation[j]] = 0;
|
||||
}
|
||||
for (int k = rank - 1; k >= 0; --k) {
|
||||
int pk = permutation[k];
|
||||
double ypk = lmDir[pk] / diagR[pk];
|
||||
for (int i = 0, index = pk; i < k; ++i, index += cols) {
|
||||
lmDir[permutation[i]] -= ypk * jacobian[index];
|
||||
}
|
||||
lmDir[pk] = ypk;
|
||||
}
|
||||
|
||||
// evaluate the function at the origin, and test
|
||||
// for acceptance of the Gauss-Newton direction
|
||||
double dxNorm = 0;
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
int pj = permutation[j];
|
||||
double s = diag[pj] * lmDir[pj];
|
||||
work1[pj] = s;
|
||||
dxNorm += s * s;
|
||||
}
|
||||
dxNorm = Math.sqrt(dxNorm);
|
||||
double fp = dxNorm - delta;
|
||||
if (fp <= 0.1 * delta) {
|
||||
lmPar = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// if the jacobian is not rank deficient, the Newton step provides
|
||||
// a lower bound, parl, for the zero of the function,
|
||||
// otherwise set this bound to zero
|
||||
double sum2, parl = 0;
|
||||
if (rank == solvedCols) {
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
int pj = permutation[j];
|
||||
work1[pj] *= diag[pj] / dxNorm;
|
||||
}
|
||||
sum2 = 0;
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
int pj = permutation[j];
|
||||
double sum = 0;
|
||||
for (int i = 0, index = pj; i < j; ++i, index += cols) {
|
||||
sum += jacobian[index] * work1[permutation[i]];
|
||||
}
|
||||
double s = (work1[pj] - sum) / diagR[pj];
|
||||
work1[pj] = s;
|
||||
sum2 += s * s;
|
||||
}
|
||||
parl = fp / (delta * sum2);
|
||||
}
|
||||
|
||||
// calculate an upper bound, paru, for the zero of the function
|
||||
sum2 = 0;
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
int pj = permutation[j];
|
||||
double sum = 0;
|
||||
for (int i = 0, index = pj; i <= j; ++i, index += cols) {
|
||||
sum += jacobian[index] * qy[i];
|
||||
}
|
||||
sum /= diag[pj];
|
||||
sum2 += sum * sum;
|
||||
}
|
||||
double gNorm = Math.sqrt(sum2);
|
||||
double paru = gNorm / delta;
|
||||
if (paru == 0) {
|
||||
// 2.2251e-308 is the smallest positive real for IEE754
|
||||
paru = 2.2251e-308 / Math.min(delta, 0.1);
|
||||
}
|
||||
|
||||
// if the input par lies outside of the interval (parl,paru),
|
||||
// set par to the closer endpoint
|
||||
lmPar = Math.min(paru, Math.max(lmPar, parl));
|
||||
if (lmPar == 0) {
|
||||
lmPar = gNorm / dxNorm;
|
||||
}
|
||||
|
||||
for (int countdown = 10; countdown >= 0; --countdown) {
|
||||
|
||||
// evaluate the function at the current value of lmPar
|
||||
if (lmPar == 0) {
|
||||
lmPar = Math.max(2.2251e-308, 0.001 * paru);
|
||||
}
|
||||
double sPar = Math.sqrt(lmPar);
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
int pj = permutation[j];
|
||||
work1[pj] = sPar * diag[pj];
|
||||
}
|
||||
determineLMDirection(qy, work1, work2, work3);
|
||||
|
||||
dxNorm = 0;
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
int pj = permutation[j];
|
||||
double s = diag[pj] * lmDir[pj];
|
||||
work3[pj] = s;
|
||||
dxNorm += s * s;
|
||||
}
|
||||
dxNorm = Math.sqrt(dxNorm);
|
||||
double previousFP = fp;
|
||||
fp = dxNorm - delta;
|
||||
|
||||
// if the function is small enough, accept the current value
|
||||
// of lmPar, also test for the exceptional cases where parl is zero
|
||||
if ((Math.abs(fp) <= 0.1 * delta)
|
||||
|| ((parl == 0) && (fp <= previousFP) && (previousFP < 0))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// compute the Newton correction
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
int pj = permutation[j];
|
||||
work1[pj] = work3[pj] * diag[pj] / dxNorm;
|
||||
}
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
int pj = permutation[j];
|
||||
work1[pj] /= work2[j];
|
||||
double tmp = work1[pj];
|
||||
for (int i = j + 1; i < solvedCols; ++i) {
|
||||
work1[permutation[i]] -= jacobian[i * cols + pj] * tmp;
|
||||
}
|
||||
}
|
||||
sum2 = 0;
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
double s = work1[permutation[j]];
|
||||
sum2 += s * s;
|
||||
}
|
||||
double correction = fp / (delta * sum2);
|
||||
|
||||
// depending on the sign of the function, update parl or paru.
|
||||
if (fp > 0) {
|
||||
parl = Math.max(parl, lmPar);
|
||||
} else if (fp < 0) {
|
||||
paru = Math.min(paru, lmPar);
|
||||
}
|
||||
|
||||
// compute an improved estimate for lmPar
|
||||
lmPar = Math.max(parl, lmPar + correction);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** Solve a*x = b and d*x = 0 in the least squares sense.
|
||||
* <p>This implementation is a translation in Java of the MINPACK
|
||||
* <a href="http://www.netlib.org/minpack/qrsolv.f">qrsolv</a>
|
||||
* routine.</p>
|
||||
* <p>This method sets the lmDir and lmDiag attributes.</p>
|
||||
* <p>The authors of the original fortran function are:</p>
|
||||
* <ul>
|
||||
* <li>Argonne National Laboratory. MINPACK project. March 1980</li>
|
||||
* <li>Burton S. Garbow</li>
|
||||
* <li>Kenneth E. Hillstrom</li>
|
||||
* <li>Jorge J. More</li>
|
||||
* </ul>
|
||||
* <p>Luc Maisonobe did the Java translation.</p>
|
||||
* @param qy array containing qTy
|
||||
* @param diag diagonal matrix
|
||||
* @param lmDiag diagonal elements associated with lmDir
|
||||
* @param work work array
|
||||
*/
|
||||
private void determineLMDirection(double[] qy, double[] diag,
|
||||
double[] lmDiag, double[] work) {
|
||||
|
||||
// copy R and Qty to preserve input and initialize s
|
||||
// in particular, save the diagonal elements of R in lmDir
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
int pj = permutation[j];
|
||||
for (int i = j + 1; i < solvedCols; ++i) {
|
||||
jacobian[i * cols + pj] = jacobian[j * cols + permutation[i]];
|
||||
}
|
||||
lmDir[j] = diagR[pj];
|
||||
work[j] = qy[j];
|
||||
}
|
||||
|
||||
// eliminate the diagonal matrix d using a Givens rotation
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
|
||||
// prepare the row of d to be eliminated, locating the
|
||||
// diagonal element using p from the Q.R. factorization
|
||||
int pj = permutation[j];
|
||||
double dpj = diag[pj];
|
||||
if (dpj != 0) {
|
||||
Arrays.fill(lmDiag, j + 1, lmDiag.length, 0);
|
||||
}
|
||||
lmDiag[j] = dpj;
|
||||
|
||||
// the transformations to eliminate the row of d
|
||||
// modify only a single element of Qty
|
||||
// beyond the first n, which is initially zero.
|
||||
double qtbpj = 0;
|
||||
for (int k = j; k < solvedCols; ++k) {
|
||||
int pk = permutation[k];
|
||||
|
||||
// determine a Givens rotation which eliminates the
|
||||
// appropriate element in the current row of d
|
||||
if (lmDiag[k] != 0) {
|
||||
|
||||
double sin, cos;
|
||||
double rkk = jacobian[k * cols + pk];
|
||||
if (Math.abs(rkk) < Math.abs(lmDiag[k])) {
|
||||
double cotan = rkk / lmDiag[k];
|
||||
sin = 1.0 / Math.sqrt(1.0 + cotan * cotan);
|
||||
cos = sin * cotan;
|
||||
} else {
|
||||
double tan = lmDiag[k] / rkk;
|
||||
cos = 1.0 / Math.sqrt(1.0 + tan * tan);
|
||||
sin = cos * tan;
|
||||
}
|
||||
|
||||
// compute the modified diagonal element of R and
|
||||
// the modified element of (Qty,0)
|
||||
jacobian[k * cols + pk] = cos * rkk + sin * lmDiag[k];
|
||||
double temp = cos * work[k] + sin * qtbpj;
|
||||
qtbpj = -sin * work[k] + cos * qtbpj;
|
||||
work[k] = temp;
|
||||
|
||||
// accumulate the tranformation in the row of s
|
||||
for (int i = k + 1; i < solvedCols; ++i) {
|
||||
double rik = jacobian[i * cols + pk];
|
||||
temp = cos * rik + sin * lmDiag[i];
|
||||
lmDiag[i] = -sin * rik + cos * lmDiag[i];
|
||||
jacobian[i * cols + pk] = temp;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// store the diagonal element of s and restore
|
||||
// the corresponding diagonal element of R
|
||||
int index = j * cols + permutation[j];
|
||||
lmDiag[j] = jacobian[index];
|
||||
jacobian[index] = lmDir[j];
|
||||
|
||||
}
|
||||
|
||||
// solve the triangular system for z, if the system is
|
||||
// singular, then obtain a least squares solution
|
||||
int nSing = solvedCols;
|
||||
for (int j = 0; j < solvedCols; ++j) {
|
||||
if ((lmDiag[j] == 0) && (nSing == solvedCols)) {
|
||||
nSing = j;
|
||||
}
|
||||
if (nSing < solvedCols) {
|
||||
work[j] = 0;
|
||||
}
|
||||
}
|
||||
if (nSing > 0) {
|
||||
for (int j = nSing - 1; j >= 0; --j) {
|
||||
int pj = permutation[j];
|
||||
double sum = 0;
|
||||
for (int i = j + 1; i < nSing; ++i) {
|
||||
sum += jacobian[i * cols + pj] * work[i];
|
||||
}
|
||||
work[j] = (work[j] - sum) / lmDiag[j];
|
||||
}
|
||||
}
|
||||
|
||||
// permute the components of z back to components of lmDir
|
||||
for (int j = 0; j < lmDir.length; ++j) {
|
||||
lmDir[permutation[j]] = work[j];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Decompose a matrix A as A.P = Q.R using Householder transforms.
|
||||
* <p>As suggested in the P. Lascaux and R. Theodor book
|
||||
* <i>Analyse numérique matricielle appliquée à
|
||||
* l'art de l'ingénieur</i> (Masson, 1986), instead of representing
|
||||
* the Householder transforms with u<sub>k</sub> unit vectors such that:
|
||||
* <pre>
|
||||
* H<sub>k</sub> = I - 2u<sub>k</sub>.u<sub>k</sub><sup>t</sup>
|
||||
* </pre>
|
||||
* we use <sub>k</sub> non-unit vectors such that:
|
||||
* <pre>
|
||||
* H<sub>k</sub> = I - beta<sub>k</sub>v<sub>k</sub>.v<sub>k</sub><sup>t</sup>
|
||||
* </pre>
|
||||
* where v<sub>k</sub> = a<sub>k</sub> - alpha<sub>k</sub> e<sub>k</sub>.
|
||||
* The beta<sub>k</sub> coefficients are provided upon exit as recomputing
|
||||
* them from the v<sub>k</sub> vectors would be costly.</p>
|
||||
* <p>This decomposition handles rank deficient cases since the tranformations
|
||||
* are performed in non-increasing columns norms order thanks to columns
|
||||
* pivoting. The diagonal elements of the R matrix are therefore also in
|
||||
* non-increasing absolute values order.</p>
|
||||
*/
|
||||
private void qrDecomposition() {
|
||||
|
||||
// initializations
|
||||
for (int k = 0; k < cols; ++k) {
|
||||
permutation[k] = k;
|
||||
double norm2 = 0;
|
||||
for (int index = k; index < jacobian.length; index += cols) {
|
||||
double akk = jacobian[index];
|
||||
norm2 += akk * akk;
|
||||
}
|
||||
jacNorm[k] = Math.sqrt(norm2);
|
||||
}
|
||||
|
||||
// transform the matrix column after column
|
||||
for (int k = 0; k < cols; ++k) {
|
||||
|
||||
// select the column with the greatest norm on active components
|
||||
int nextColumn = -1;
|
||||
double ak2 = Double.NEGATIVE_INFINITY;
|
||||
for (int i = k; i < cols; ++i) {
|
||||
double norm2 = 0;
|
||||
int iDiag = k * cols + permutation[i];
|
||||
for (int index = iDiag; index < jacobian.length; index += cols) {
|
||||
double aki = jacobian[index];
|
||||
norm2 += aki * aki;
|
||||
}
|
||||
if (norm2 > ak2) {
|
||||
nextColumn = i;
|
||||
ak2 = norm2;
|
||||
}
|
||||
}
|
||||
if (ak2 == 0) {
|
||||
rank = k;
|
||||
return;
|
||||
}
|
||||
int pk = permutation[nextColumn];
|
||||
permutation[nextColumn] = permutation[k];
|
||||
permutation[k] = pk;
|
||||
|
||||
// choose alpha such that Hk.u = alpha ek
|
||||
int kDiag = k * cols + pk;
|
||||
double akk = jacobian[kDiag];
|
||||
double alpha = (akk > 0) ? -Math.sqrt(ak2) : Math.sqrt(ak2);
|
||||
double betak = 1.0 / (ak2 - akk * alpha);
|
||||
beta[pk] = betak;
|
||||
|
||||
// transform the current column
|
||||
diagR[pk] = alpha;
|
||||
jacobian[kDiag] -= alpha;
|
||||
|
||||
// transform the remaining columns
|
||||
for (int dk = cols - 1 - k; dk > 0; --dk) {
|
||||
int dkp = permutation[k + dk] - pk;
|
||||
double gamma = 0;
|
||||
for (int index = kDiag; index < jacobian.length; index += cols) {
|
||||
gamma += jacobian[index] * jacobian[index + dkp];
|
||||
}
|
||||
gamma *= betak;
|
||||
for (int index = kDiag; index < jacobian.length; index += cols) {
|
||||
jacobian[index + dkp] -= gamma * jacobian[index];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rank = solvedCols;
|
||||
|
||||
}
|
||||
|
||||
/** Compute the product Qt.y for some Q.R. decomposition.
|
||||
* @param y vector to multiply (will be overwritten with the result)
|
||||
*/
|
||||
private void qTy(double[] y) {
|
||||
for (int k = 0; k < cols; ++k) {
|
||||
int pk = permutation[k];
|
||||
int kDiag = k * cols + pk;
|
||||
double gamma = 0;
|
||||
for (int i = k, index = kDiag; i < rows; ++i, index += cols) {
|
||||
gamma += jacobian[index] * y[i];
|
||||
}
|
||||
gamma *= beta[pk];
|
||||
for (int i = k, index = kDiag; i < rows; ++i, index += cols) {
|
||||
y[i] -= gamma * jacobian[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Array of measurements. */
|
||||
private WeightedMeasurement[] measurements;
|
||||
|
||||
/** Array of parameters. */
|
||||
private EstimatedParameter[] parameters;
|
||||
|
||||
/** Jacobian matrix.
|
||||
* <p>Depending on the computation phase, this matrix is either in
|
||||
* canonical form (just after the calls to updateJacobian) or in
|
||||
* Q.R. decomposed form (after calls to qrDecomposition)</p>
|
||||
*/
|
||||
private double[] jacobian;
|
||||
|
||||
/** Number of columns of the jacobian matrix. */
|
||||
private int cols;
|
||||
|
||||
/** Number of solved variables. */
|
||||
private int solvedCols;
|
||||
|
||||
/** Number of rows of the jacobian matrix. */
|
||||
private int rows;
|
||||
|
||||
/** Diagonal elements of the R matrix in the Q.R. decomposition. */
|
||||
private double[] diagR;
|
||||
|
||||
/** Norms of the columns of the jacobian matrix. */
|
||||
private double[] jacNorm;
|
||||
|
||||
/** Coefficients of the Householder transforms vectors. */
|
||||
private double[] beta;
|
||||
|
||||
/** Columns permutation array. */
|
||||
private int[] permutation;
|
||||
|
||||
/** Rank of the jacobian matrix. */
|
||||
private int rank;
|
||||
|
||||
/** Levenberg-Marquardt parameter. */
|
||||
private double lmPar;
|
||||
|
||||
/** Parameters evolution direction associated with lmPar. */
|
||||
private double[] lmDir;
|
||||
|
||||
/** Residuals array.
|
||||
* <p>Depending on the computation phase, this array is either in
|
||||
* canonical form (just after the calls to updateResiduals) or in
|
||||
* premultiplied by Qt form (just after calls to qTy)</p>
|
||||
*/
|
||||
private double[] residuals;
|
||||
|
||||
/** Cost value (square root of the sum of the residuals). */
|
||||
private double cost;
|
||||
|
||||
/** Positive input variable used in determining the initial step bound. */
|
||||
private double initialStepBoundFactor;
|
||||
|
||||
/** Maximal number of cost evaluations. */
|
||||
private int maxCostEval;
|
||||
|
||||
/** Number of cost evaluations. */
|
||||
private int costEvaluations;
|
||||
|
||||
/** Number of jacobian evaluations. */
|
||||
private int jacobianEvaluations;
|
||||
|
||||
/** Desired relative error in the sum of squares. */
|
||||
private double costRelativeTolerance;
|
||||
|
||||
/** Desired relative error in the approximate solution parameters. */
|
||||
private double parRelativeTolerance;
|
||||
|
||||
/** Desired max cosine on the orthogonality between the function vector
|
||||
* and the columns of the jacobian. */
|
||||
private double orthoTolerance;
|
||||
|
||||
private static final long serialVersionUID = 5387476316105068340L;
|
||||
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.estimation;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** This class represents measurements in estimation problems.
|
||||
|
||||
* <p>This abstract class implements all the methods needed to handle
|
||||
* measurements in a general way. It defines neither the {@link
|
||||
* #getTheoreticalValue getTheoreticalValue} nor the {@link
|
||||
* #getPartial getPartial} methods, which should be defined by
|
||||
* sub-classes according to the specific problem.</p>
|
||||
|
||||
* <p>The {@link #getTheoreticalValue getTheoreticalValue} and {@link
|
||||
* #getPartial getPartial} methods must always use the current
|
||||
* estimate of the parameters set by the solver in the problem. These
|
||||
* parameters can be retrieved through the {@link
|
||||
* EstimationProblem#getAllParameters
|
||||
* EstimationProblem.getAllParameters} method if the measurements are
|
||||
* independant of the problem, or directly if they are implemented as
|
||||
* inner classes of the problem.</p>
|
||||
|
||||
* <p>The instances for which the <code>ignored</code> flag is set
|
||||
* through the {@link #setIgnored setIgnored} method are ignored by the
|
||||
* solvers. This can be used to reject wrong measurements at some
|
||||
* steps of the estimation.</p>
|
||||
|
||||
* @see EstimationProblem
|
||||
|
||||
* @version $Id: WeightedMeasurement.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public abstract class WeightedMeasurement implements Serializable {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a measurement with the given parameters, and set its ignore
|
||||
* flag to false.
|
||||
* @param weight weight of the measurement in the least squares problem
|
||||
* (two common choices are either to use 1.0 for all measurements, or to
|
||||
* use a value proportional to the inverse of the variance of the measurement
|
||||
* type)
|
||||
* @param measuredValue measured value
|
||||
*/
|
||||
public WeightedMeasurement(double weight, double measuredValue) {
|
||||
this.weight = weight;
|
||||
this.measuredValue = measuredValue;
|
||||
ignored = false;
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a measurement with the given parameters
|
||||
* @param weight weight of the measurement in the least squares problem
|
||||
* @param measuredValue measured value
|
||||
* @param ignored true if the measurement should be ignored
|
||||
*/
|
||||
public WeightedMeasurement(double weight, double measuredValue,
|
||||
boolean ignored) {
|
||||
this.weight = weight;
|
||||
this.measuredValue = measuredValue;
|
||||
this.ignored = ignored;
|
||||
}
|
||||
|
||||
/** Get the weight of the measurement in the least squares problem
|
||||
* @return weight
|
||||
*/
|
||||
public double getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
/** Get the measured value
|
||||
* @return measured value
|
||||
*/
|
||||
public double getMeasuredValue() {
|
||||
return measuredValue;
|
||||
}
|
||||
|
||||
/** Get the residual for this measurement
|
||||
* The residual is the measured value minus the theoretical value.
|
||||
* @return residual
|
||||
*/
|
||||
public double getResidual() {
|
||||
return measuredValue - getTheoreticalValue();
|
||||
}
|
||||
|
||||
/** Get the theoretical value expected for this measurement
|
||||
* <p>The theoretical value is the value expected for this measurement
|
||||
* if the model and its parameter were all perfectly known.</p>
|
||||
* <p>The value must be computed using the current estimate of the parameters
|
||||
* set by the solver in the problem.</p>
|
||||
* @return theoretical value
|
||||
*/
|
||||
public abstract double getTheoreticalValue();
|
||||
|
||||
/** Get the partial derivative of the {@link #getTheoreticalValue
|
||||
* theoretical value} according to the parameter.
|
||||
* <p>The value must be computed using the current estimate of the parameters
|
||||
* set by the solver in the problem.</p>
|
||||
* @param parameter parameter against which the partial derivative
|
||||
* should be computed
|
||||
* @return partial derivative of the {@link #getTheoreticalValue
|
||||
* theoretical value}
|
||||
*/
|
||||
public abstract double getPartial(EstimatedParameter parameter);
|
||||
|
||||
/** Set the ignore flag to the specified value
|
||||
* Setting the ignore flag to true allow to reject wrong
|
||||
* measurements, which sometimes can be detected only rather late.
|
||||
* @param ignored value for the ignore flag
|
||||
*/
|
||||
public void setIgnored(boolean ignored) {
|
||||
this.ignored = ignored;
|
||||
}
|
||||
|
||||
/** Check if this measurement should be ignored
|
||||
* @return true if the measurement should be ignored
|
||||
*/
|
||||
public boolean isIgnored() {
|
||||
return ignored;
|
||||
}
|
||||
|
||||
private final double weight;
|
||||
private final double measuredValue;
|
||||
private boolean ignored;
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version = "1.0" encoding = "ISO-8859-1" ?>
|
||||
<!DOCTYPE argo SYSTEM "argo.dtd" >
|
||||
<argo>
|
||||
<documentation>
|
||||
<authorname></authorname>
|
||||
<version></version>
|
||||
<description>
|
||||
|
||||
</description>
|
||||
</documentation>
|
||||
|
||||
<searchpath href="PROJECT_DIR" />
|
||||
<member
|
||||
type="pgml"
|
||||
name="estimation_classdiagram1.pgml"
|
||||
/>
|
||||
<member
|
||||
type="xmi"
|
||||
name="estimation.xmi"
|
||||
/>
|
||||
<historyfile name="" />
|
||||
<stats>
|
||||
<stat name="clicksInToDoPane"
|
||||
value="0" />
|
||||
<stat name="dblClicksInToDoPane"
|
||||
value="0" />
|
||||
<stat name="longestToDoList"
|
||||
value="39" />
|
||||
<stat name="longestAdd"
|
||||
value="0" />
|
||||
<stat name="longestHot"
|
||||
value="0" />
|
||||
<stat name="numCriticsFired"
|
||||
value="16084" />
|
||||
<stat name="numNotValid"
|
||||
value="1" />
|
||||
<stat name="numCriticsApplied"
|
||||
value="0" />
|
||||
<stat name="toDoPerspectivesChanged"
|
||||
value="1" />
|
||||
<stat name="navPerspectivesChanged"
|
||||
value="1" />
|
||||
<stat name="clicksInNavPane"
|
||||
value="0" />
|
||||
<stat name="numFinds"
|
||||
value="1" />
|
||||
<stat name="numJumpToRelated"
|
||||
value="0" />
|
||||
<stat name="numDecisionModel"
|
||||
value="0" />
|
||||
<stat name="numGoalsModel"
|
||||
value="0" />
|
||||
<stat name="numCriticBrowser"
|
||||
value="0" />
|
||||
<stat name="numNavConfig"
|
||||
value="0" />
|
||||
<stat name="numHushes"
|
||||
value="0" />
|
||||
<stat name="numChecks"
|
||||
value="0" />
|
||||
<stat name="Num_Button_Clicks"
|
||||
value="0" />
|
||||
<stat name="Drags_To_New"
|
||||
value="0" />
|
||||
<stat name="Drags_To_Existing"
|
||||
value="0" />
|
||||
</stats>
|
||||
</argo>
|
|
@ -0,0 +1,868 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<XMI xmi.version="1.0">
|
||||
<XMI.header>
|
||||
<XMI.documentation>
|
||||
<XMI.exporter>Novosoft UML Library</XMI.exporter>
|
||||
<XMI.exporterVersion>0.4.17</XMI.exporterVersion>
|
||||
</XMI.documentation>
|
||||
<XMI.metamodel xmi.name="UML" xmi.version="1.3"/>
|
||||
</XMI.header>
|
||||
<XMI.content>
|
||||
<Model_Management.Model xmi.id="xmi.1" xmi.uuid="25af9f:e3b707cd28:-8000">
|
||||
<Foundation.Core.ModelElement.name>estimation</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Namespace.ownedElement>
|
||||
<Foundation.Core.Class xmi.id="xmi.2" xmi.uuid="25af9f:e3b707cd28:-7fff">
|
||||
<Foundation.Core.ModelElement.name>WeightedMeasurement</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="true"/>
|
||||
<Foundation.Core.Class.isActive xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.ModelElement.clientDependency>
|
||||
<Foundation.Core.Dependency xmi.idref="xmi.3"/>
|
||||
</Foundation.Core.ModelElement.clientDependency>
|
||||
<Foundation.Core.GeneralizableElement.specialization>
|
||||
<Foundation.Core.Generalization xmi.idref="xmi.4"/>
|
||||
<Foundation.Core.Generalization xmi.idref="xmi.5"/>
|
||||
</Foundation.Core.GeneralizableElement.specialization>
|
||||
<Foundation.Core.Classifier.feature>
|
||||
<Foundation.Core.Attribute xmi.id="xmi.6">
|
||||
<Foundation.Core.ModelElement.name>weight_</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="protected"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.2"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.StructuralFeature.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.7"/>
|
||||
</Foundation.Core.StructuralFeature.type>
|
||||
</Foundation.Core.Attribute>
|
||||
<Foundation.Core.Attribute xmi.id="xmi.8">
|
||||
<Foundation.Core.ModelElement.name>measuredValue_</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="protected"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.2"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.StructuralFeature.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.7"/>
|
||||
</Foundation.Core.StructuralFeature.type>
|
||||
</Foundation.Core.Attribute>
|
||||
<Foundation.Core.Attribute xmi.id="xmi.9">
|
||||
<Foundation.Core.ModelElement.name>ignored_</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="protected"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.2"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.StructuralFeature.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.10"/>
|
||||
</Foundation.Core.StructuralFeature.type>
|
||||
</Foundation.Core.Attribute>
|
||||
<Foundation.Core.Operation xmi.id="xmi.11">
|
||||
<Foundation.Core.ModelElement.name>getWeight</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="public"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.BehavioralFeature.isQuery xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.2"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.BehavioralFeature.parameter>
|
||||
<Foundation.Core.Parameter xmi.id="xmi.12">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Parameter.kind xmi.value="return"/>
|
||||
<Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.BehavioralFeature xmi.idref="xmi.11"/>
|
||||
</Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.Parameter.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.7"/>
|
||||
</Foundation.Core.Parameter.type>
|
||||
</Foundation.Core.Parameter>
|
||||
</Foundation.Core.BehavioralFeature.parameter>
|
||||
</Foundation.Core.Operation>
|
||||
<Foundation.Core.Operation xmi.id="xmi.13">
|
||||
<Foundation.Core.ModelElement.name>getMeasuredValue</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="public"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.BehavioralFeature.isQuery xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.2"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.BehavioralFeature.parameter>
|
||||
<Foundation.Core.Parameter xmi.id="xmi.14">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Parameter.kind xmi.value="return"/>
|
||||
<Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.BehavioralFeature xmi.idref="xmi.13"/>
|
||||
</Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.Parameter.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.7"/>
|
||||
</Foundation.Core.Parameter.type>
|
||||
</Foundation.Core.Parameter>
|
||||
</Foundation.Core.BehavioralFeature.parameter>
|
||||
</Foundation.Core.Operation>
|
||||
<Foundation.Core.Operation xmi.id="xmi.15">
|
||||
<Foundation.Core.ModelElement.name>setIgnored</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="public"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.BehavioralFeature.isQuery xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.2"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.BehavioralFeature.parameter>
|
||||
<Foundation.Core.Parameter xmi.id="xmi.16">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Parameter.kind xmi.value="return"/>
|
||||
<Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.BehavioralFeature xmi.idref="xmi.15"/>
|
||||
</Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.Parameter.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.17"/>
|
||||
</Foundation.Core.Parameter.type>
|
||||
</Foundation.Core.Parameter>
|
||||
<Foundation.Core.Parameter xmi.id="xmi.18">
|
||||
<Foundation.Core.ModelElement.name>ignored</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Parameter.kind xmi.value="in"/>
|
||||
<Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.BehavioralFeature xmi.idref="xmi.15"/>
|
||||
</Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.Parameter.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.10"/>
|
||||
</Foundation.Core.Parameter.type>
|
||||
</Foundation.Core.Parameter>
|
||||
</Foundation.Core.BehavioralFeature.parameter>
|
||||
</Foundation.Core.Operation>
|
||||
<Foundation.Core.Operation xmi.id="xmi.19">
|
||||
<Foundation.Core.ModelElement.name>isIgnored</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="public"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.BehavioralFeature.isQuery xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.2"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.BehavioralFeature.parameter>
|
||||
<Foundation.Core.Parameter xmi.id="xmi.20">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Parameter.kind xmi.value="return"/>
|
||||
<Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.BehavioralFeature xmi.idref="xmi.19"/>
|
||||
</Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.Parameter.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.10"/>
|
||||
</Foundation.Core.Parameter.type>
|
||||
</Foundation.Core.Parameter>
|
||||
</Foundation.Core.BehavioralFeature.parameter>
|
||||
</Foundation.Core.Operation>
|
||||
<Foundation.Core.Operation xmi.id="xmi.21">
|
||||
<Foundation.Core.ModelElement.name>getTheoreticalValue</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="public"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.BehavioralFeature.isQuery xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.2"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.BehavioralFeature.parameter>
|
||||
<Foundation.Core.Parameter xmi.id="xmi.22">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Parameter.kind xmi.value="return"/>
|
||||
<Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.BehavioralFeature xmi.idref="xmi.21"/>
|
||||
</Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.Parameter.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.7"/>
|
||||
</Foundation.Core.Parameter.type>
|
||||
</Foundation.Core.Parameter>
|
||||
</Foundation.Core.BehavioralFeature.parameter>
|
||||
</Foundation.Core.Operation>
|
||||
<Foundation.Core.Operation xmi.id="xmi.23">
|
||||
<Foundation.Core.ModelElement.name>getResidual</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="public"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.BehavioralFeature.isQuery xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.2"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.BehavioralFeature.parameter>
|
||||
<Foundation.Core.Parameter xmi.id="xmi.24">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Parameter.kind xmi.value="return"/>
|
||||
<Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.BehavioralFeature xmi.idref="xmi.23"/>
|
||||
</Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.Parameter.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.7"/>
|
||||
</Foundation.Core.Parameter.type>
|
||||
</Foundation.Core.Parameter>
|
||||
</Foundation.Core.BehavioralFeature.parameter>
|
||||
</Foundation.Core.Operation>
|
||||
<Foundation.Core.Operation xmi.id="xmi.25">
|
||||
<Foundation.Core.ModelElement.name>getPartial</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="public"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.BehavioralFeature.isQuery xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.2"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.BehavioralFeature.parameter>
|
||||
<Foundation.Core.Parameter xmi.id="xmi.26">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Parameter.kind xmi.value="return"/>
|
||||
<Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.BehavioralFeature xmi.idref="xmi.25"/>
|
||||
</Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.Parameter.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.7"/>
|
||||
</Foundation.Core.Parameter.type>
|
||||
</Foundation.Core.Parameter>
|
||||
<Foundation.Core.Parameter xmi.id="xmi.27">
|
||||
<Foundation.Core.ModelElement.name>parameter</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Parameter.kind xmi.value="in"/>
|
||||
<Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.BehavioralFeature xmi.idref="xmi.25"/>
|
||||
</Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.Parameter.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.28"/>
|
||||
</Foundation.Core.Parameter.type>
|
||||
</Foundation.Core.Parameter>
|
||||
</Foundation.Core.BehavioralFeature.parameter>
|
||||
</Foundation.Core.Operation>
|
||||
</Foundation.Core.Classifier.feature>
|
||||
</Foundation.Core.Class>
|
||||
<Foundation.Core.DataType xmi.id="xmi.7">
|
||||
<Foundation.Core.ModelElement.name>double</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
</Foundation.Core.DataType>
|
||||
<Foundation.Core.DataType xmi.id="xmi.10">
|
||||
<Foundation.Core.ModelElement.name>boolean</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
</Foundation.Core.DataType>
|
||||
<Foundation.Core.DataType xmi.id="xmi.29">
|
||||
<Foundation.Core.ModelElement.name>EstimatedParameter[]</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
</Foundation.Core.DataType>
|
||||
<Foundation.Core.DataType xmi.id="xmi.30">
|
||||
<Foundation.Core.ModelElement.name>WeightedMeasurement[]</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
</Foundation.Core.DataType>
|
||||
<Foundation.Core.DataType xmi.id="xmi.17">
|
||||
<Foundation.Core.ModelElement.name>void</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
</Foundation.Core.DataType>
|
||||
<Foundation.Core.Dependency xmi.id="xmi.31" xmi.uuid="25af9f:e3b707cd28:-7ffb">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Dependency.client>
|
||||
<Foundation.Core.ModelElement xmi.idref="xmi.32"/>
|
||||
</Foundation.Core.Dependency.client>
|
||||
<Foundation.Core.Dependency.supplier>
|
||||
<Foundation.Core.ModelElement xmi.idref="xmi.33"/>
|
||||
</Foundation.Core.Dependency.supplier>
|
||||
</Foundation.Core.Dependency>
|
||||
<Foundation.Core.Association xmi.id="xmi.34" xmi.uuid="25af9f:e3b707cd28:-7ffa">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Association.connection>
|
||||
<Foundation.Core.AssociationEnd xmi.id="xmi.35">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.AssociationEnd.isNavigable xmi.value="false"/>
|
||||
<Foundation.Core.AssociationEnd.aggregation xmi.value="none"/>
|
||||
<Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.Association xmi.idref="xmi.34"/>
|
||||
</Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.AssociationEnd.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.32"/>
|
||||
</Foundation.Core.AssociationEnd.type>
|
||||
</Foundation.Core.AssociationEnd>
|
||||
<Foundation.Core.AssociationEnd xmi.id="xmi.36">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.AssociationEnd.isNavigable xmi.value="true"/>
|
||||
<Foundation.Core.AssociationEnd.aggregation xmi.value="none"/>
|
||||
<Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.Association xmi.idref="xmi.34"/>
|
||||
</Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.AssociationEnd.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.2"/>
|
||||
</Foundation.Core.AssociationEnd.type>
|
||||
</Foundation.Core.AssociationEnd>
|
||||
</Foundation.Core.Association.connection>
|
||||
</Foundation.Core.Association>
|
||||
<Foundation.Core.Class xmi.id="xmi.37" xmi.uuid="25af9f:e3b707cd28:-7ff9">
|
||||
<Foundation.Core.ModelElement.name>LeastSquaresEstimator</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Class.isActive xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.ModelElement.clientDependency>
|
||||
<Foundation.Core.Dependency xmi.idref="xmi.38"/>
|
||||
</Foundation.Core.ModelElement.clientDependency>
|
||||
<Foundation.Core.Classifier.feature>
|
||||
<Foundation.Core.Attribute xmi.id="xmi.39">
|
||||
<Foundation.Core.ModelElement.name>maxIterations_</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="private"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.37"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.StructuralFeature.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.40"/>
|
||||
</Foundation.Core.StructuralFeature.type>
|
||||
</Foundation.Core.Attribute>
|
||||
<Foundation.Core.Attribute xmi.id="xmi.41">
|
||||
<Foundation.Core.ModelElement.name>convergence_</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="private"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.37"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.StructuralFeature.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.7"/>
|
||||
</Foundation.Core.StructuralFeature.type>
|
||||
</Foundation.Core.Attribute>
|
||||
</Foundation.Core.Classifier.feature>
|
||||
</Foundation.Core.Class>
|
||||
<Foundation.Core.Abstraction xmi.id="xmi.38" xmi.uuid="25af9f:e3b707cd28:-7ff8">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Dependency.client>
|
||||
<Foundation.Core.ModelElement xmi.idref="xmi.37"/>
|
||||
</Foundation.Core.Dependency.client>
|
||||
<Foundation.Core.Dependency.supplier>
|
||||
<Foundation.Core.ModelElement xmi.idref="xmi.33"/>
|
||||
</Foundation.Core.Dependency.supplier>
|
||||
</Foundation.Core.Abstraction>
|
||||
<Foundation.Extension_Mechanisms.Stereotype xmi.id="xmi.42">
|
||||
<Foundation.Core.ModelElement.name>realize</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Extension_Mechanisms.Stereotype.extendedElement>
|
||||
<Foundation.Core.ModelElement xmi.idref="xmi.38"/>
|
||||
</Foundation.Extension_Mechanisms.Stereotype.extendedElement>
|
||||
</Foundation.Extension_Mechanisms.Stereotype>
|
||||
<Foundation.Core.Class xmi.id="xmi.43" xmi.uuid="3a34af:e3c5366c0a:-7fff">
|
||||
<Foundation.Core.ModelElement.name>MyProblem</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Class.isActive xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.ModelElement.clientDependency>
|
||||
<Foundation.Core.Dependency xmi.idref="xmi.44"/>
|
||||
</Foundation.Core.ModelElement.clientDependency>
|
||||
</Foundation.Core.Class>
|
||||
<Foundation.Core.Abstraction xmi.id="xmi.44" xmi.uuid="3a34af:e3c5366c0a:-7ffe">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Dependency.client>
|
||||
<Foundation.Core.ModelElement xmi.idref="xmi.43"/>
|
||||
</Foundation.Core.Dependency.client>
|
||||
<Foundation.Core.Dependency.supplier>
|
||||
<Foundation.Core.ModelElement xmi.idref="xmi.32"/>
|
||||
</Foundation.Core.Dependency.supplier>
|
||||
</Foundation.Core.Abstraction>
|
||||
<Foundation.Extension_Mechanisms.Stereotype xmi.id="xmi.45">
|
||||
<Foundation.Core.ModelElement.name>realize</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Extension_Mechanisms.Stereotype.extendedElement>
|
||||
<Foundation.Core.ModelElement xmi.idref="xmi.44"/>
|
||||
</Foundation.Extension_Mechanisms.Stereotype.extendedElement>
|
||||
</Foundation.Extension_Mechanisms.Stereotype>
|
||||
<Foundation.Core.Class xmi.id="xmi.46" xmi.uuid="3a34af:e3c5366c0a:-7ffd">
|
||||
<Foundation.Core.ModelElement.name>MyFirstMeasurementType</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Class.isActive xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.GeneralizableElement.generalization>
|
||||
<Foundation.Core.Generalization xmi.idref="xmi.4"/>
|
||||
</Foundation.Core.GeneralizableElement.generalization>
|
||||
</Foundation.Core.Class>
|
||||
<Foundation.Core.Generalization xmi.id="xmi.4" xmi.uuid="3a34af:e3c5366c0a:-7ffc">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Generalization.child>
|
||||
<Foundation.Core.GeneralizableElement xmi.idref="xmi.46"/>
|
||||
</Foundation.Core.Generalization.child>
|
||||
<Foundation.Core.Generalization.parent>
|
||||
<Foundation.Core.GeneralizableElement xmi.idref="xmi.2"/>
|
||||
</Foundation.Core.Generalization.parent>
|
||||
</Foundation.Core.Generalization>
|
||||
<Foundation.Core.Class xmi.id="xmi.47" xmi.uuid="3a34af:e3c5366c0a:-7ffb">
|
||||
<Foundation.Core.ModelElement.name>MySecondMeasurementType</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Class.isActive xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.GeneralizableElement.generalization>
|
||||
<Foundation.Core.Generalization xmi.idref="xmi.5"/>
|
||||
</Foundation.Core.GeneralizableElement.generalization>
|
||||
</Foundation.Core.Class>
|
||||
<Foundation.Core.Generalization xmi.id="xmi.5" xmi.uuid="3a34af:e3c5366c0a:-7ffa">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Generalization.child>
|
||||
<Foundation.Core.GeneralizableElement xmi.idref="xmi.47"/>
|
||||
</Foundation.Core.Generalization.child>
|
||||
<Foundation.Core.Generalization.parent>
|
||||
<Foundation.Core.GeneralizableElement xmi.idref="xmi.2"/>
|
||||
</Foundation.Core.Generalization.parent>
|
||||
</Foundation.Core.Generalization>
|
||||
<Foundation.Core.Association xmi.id="xmi.48" xmi.uuid="3a34af:e3c5366c0a:-7ff9">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Association.connection>
|
||||
<Foundation.Core.AssociationEnd xmi.id="xmi.49">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.AssociationEnd.isNavigable xmi.value="true"/>
|
||||
<Foundation.Core.AssociationEnd.aggregation xmi.value="none"/>
|
||||
<Foundation.Core.AssociationEnd.multiplicity>
|
||||
<Foundation.Data_Types.Multiplicity xmi.id="xmi.50">
|
||||
<Foundation.Data_Types.Multiplicity.range>
|
||||
<Foundation.Data_Types.MultiplicityRange xmi.id="xmi.51">
|
||||
<Foundation.Data_Types.MultiplicityRange.lower>1</Foundation.Data_Types.MultiplicityRange.lower>
|
||||
<Foundation.Data_Types.MultiplicityRange.upper>-1</Foundation.Data_Types.MultiplicityRange.upper>
|
||||
</Foundation.Data_Types.MultiplicityRange>
|
||||
</Foundation.Data_Types.Multiplicity.range>
|
||||
</Foundation.Data_Types.Multiplicity>
|
||||
</Foundation.Core.AssociationEnd.multiplicity>
|
||||
<Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.Association xmi.idref="xmi.48"/>
|
||||
</Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.AssociationEnd.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.47"/>
|
||||
</Foundation.Core.AssociationEnd.type>
|
||||
</Foundation.Core.AssociationEnd>
|
||||
<Foundation.Core.AssociationEnd xmi.id="xmi.52">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.AssociationEnd.isNavigable xmi.value="true"/>
|
||||
<Foundation.Core.AssociationEnd.aggregation xmi.value="composite"/>
|
||||
<Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.Association xmi.idref="xmi.48"/>
|
||||
</Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.AssociationEnd.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.43"/>
|
||||
</Foundation.Core.AssociationEnd.type>
|
||||
</Foundation.Core.AssociationEnd>
|
||||
</Foundation.Core.Association.connection>
|
||||
</Foundation.Core.Association>
|
||||
<Foundation.Core.Association xmi.id="xmi.53" xmi.uuid="3a34af:e3c5366c0a:-7ff8">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Association.connection>
|
||||
<Foundation.Core.AssociationEnd xmi.id="xmi.54">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.AssociationEnd.isNavigable xmi.value="true"/>
|
||||
<Foundation.Core.AssociationEnd.aggregation xmi.value="none"/>
|
||||
<Foundation.Core.AssociationEnd.multiplicity>
|
||||
<Foundation.Data_Types.Multiplicity xmi.idref="xmi.50"/>
|
||||
</Foundation.Core.AssociationEnd.multiplicity>
|
||||
<Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.Association xmi.idref="xmi.53"/>
|
||||
</Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.AssociationEnd.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.46"/>
|
||||
</Foundation.Core.AssociationEnd.type>
|
||||
</Foundation.Core.AssociationEnd>
|
||||
<Foundation.Core.AssociationEnd xmi.id="xmi.55">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.AssociationEnd.isNavigable xmi.value="true"/>
|
||||
<Foundation.Core.AssociationEnd.aggregation xmi.value="composite"/>
|
||||
<Foundation.Core.AssociationEnd.multiplicity>
|
||||
<Foundation.Data_Types.Multiplicity xmi.id="xmi.56">
|
||||
<Foundation.Data_Types.Multiplicity.range>
|
||||
<Foundation.Data_Types.MultiplicityRange xmi.id="xmi.57">
|
||||
<Foundation.Data_Types.MultiplicityRange.lower>1</Foundation.Data_Types.MultiplicityRange.lower>
|
||||
<Foundation.Data_Types.MultiplicityRange.upper>1</Foundation.Data_Types.MultiplicityRange.upper>
|
||||
</Foundation.Data_Types.MultiplicityRange>
|
||||
</Foundation.Data_Types.Multiplicity.range>
|
||||
</Foundation.Data_Types.Multiplicity>
|
||||
</Foundation.Core.AssociationEnd.multiplicity>
|
||||
<Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.Association xmi.idref="xmi.53"/>
|
||||
</Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.AssociationEnd.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.43"/>
|
||||
</Foundation.Core.AssociationEnd.type>
|
||||
</Foundation.Core.AssociationEnd>
|
||||
</Foundation.Core.Association.connection>
|
||||
</Foundation.Core.Association>
|
||||
<Foundation.Core.Class xmi.id="xmi.40">
|
||||
<Foundation.Core.ModelElement.name>int</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Class.isActive xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
</Foundation.Core.Class>
|
||||
<Foundation.Core.Class xmi.id="xmi.28" xmi.uuid="148603:e3c5d490c2:-7fff">
|
||||
<Foundation.Core.ModelElement.name>EstimatedParameter</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Class.isActive xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.ModelElement.supplierDependency>
|
||||
<Foundation.Core.Dependency xmi.idref="xmi.3"/>
|
||||
</Foundation.Core.ModelElement.supplierDependency>
|
||||
<Foundation.Core.Classifier.feature>
|
||||
<Foundation.Core.Attribute xmi.id="xmi.58">
|
||||
<Foundation.Core.ModelElement.name>name_</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="private"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.28"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.StructuralFeature.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.59"/>
|
||||
</Foundation.Core.StructuralFeature.type>
|
||||
</Foundation.Core.Attribute>
|
||||
<Foundation.Core.Attribute xmi.id="xmi.60">
|
||||
<Foundation.Core.ModelElement.name>estimate_</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="private"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.28"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.StructuralFeature.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.7"/>
|
||||
</Foundation.Core.StructuralFeature.type>
|
||||
</Foundation.Core.Attribute>
|
||||
<Foundation.Core.Attribute xmi.id="xmi.61">
|
||||
<Foundation.Core.ModelElement.name>bound_</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="private"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.28"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.StructuralFeature.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.10"/>
|
||||
</Foundation.Core.StructuralFeature.type>
|
||||
</Foundation.Core.Attribute>
|
||||
<Foundation.Core.Operation xmi.id="xmi.62">
|
||||
<Foundation.Core.ModelElement.name>setEstimate</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="public"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.BehavioralFeature.isQuery xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.28"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.BehavioralFeature.parameter>
|
||||
<Foundation.Core.Parameter xmi.id="xmi.63">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Parameter.kind xmi.value="return"/>
|
||||
<Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.BehavioralFeature xmi.idref="xmi.62"/>
|
||||
</Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.Parameter.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.17"/>
|
||||
</Foundation.Core.Parameter.type>
|
||||
</Foundation.Core.Parameter>
|
||||
<Foundation.Core.Parameter xmi.id="xmi.64">
|
||||
<Foundation.Core.ModelElement.name>estimate</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Parameter.kind xmi.value="in"/>
|
||||
<Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.BehavioralFeature xmi.idref="xmi.62"/>
|
||||
</Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.Parameter.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.7"/>
|
||||
</Foundation.Core.Parameter.type>
|
||||
</Foundation.Core.Parameter>
|
||||
</Foundation.Core.BehavioralFeature.parameter>
|
||||
</Foundation.Core.Operation>
|
||||
<Foundation.Core.Operation xmi.id="xmi.65">
|
||||
<Foundation.Core.ModelElement.name>getEstimate</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="public"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.BehavioralFeature.isQuery xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.28"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.BehavioralFeature.parameter>
|
||||
<Foundation.Core.Parameter xmi.id="xmi.66">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Parameter.kind xmi.value="return"/>
|
||||
<Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.BehavioralFeature xmi.idref="xmi.65"/>
|
||||
</Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.Parameter.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.7"/>
|
||||
</Foundation.Core.Parameter.type>
|
||||
</Foundation.Core.Parameter>
|
||||
</Foundation.Core.BehavioralFeature.parameter>
|
||||
</Foundation.Core.Operation>
|
||||
<Foundation.Core.Operation xmi.id="xmi.67">
|
||||
<Foundation.Core.ModelElement.name>isBound</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.visibility xmi.value="public"/>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.BehavioralFeature.isQuery xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.Operation.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.28"/>
|
||||
</Foundation.Core.Feature.owner>
|
||||
<Foundation.Core.BehavioralFeature.parameter>
|
||||
<Foundation.Core.Parameter xmi.id="xmi.68">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.Parameter.kind xmi.value="return"/>
|
||||
<Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.BehavioralFeature xmi.idref="xmi.67"/>
|
||||
</Foundation.Core.Parameter.behavioralFeature>
|
||||
<Foundation.Core.Parameter.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.10"/>
|
||||
</Foundation.Core.Parameter.type>
|
||||
</Foundation.Core.Parameter>
|
||||
</Foundation.Core.BehavioralFeature.parameter>
|
||||
</Foundation.Core.Operation>
|
||||
</Foundation.Core.Classifier.feature>
|
||||
</Foundation.Core.Class>
|
||||
<Foundation.Core.Class xmi.id="xmi.59">
|
||||
<Foundation.Core.ModelElement.name>String</Foundation.Core.ModelElement.name>
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.Class.isActive xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
</Foundation.Core.Class>
|
||||
<Foundation.Core.Association xmi.id="xmi.69" xmi.uuid="148603:e3c5d490c2:-7ffd">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Association.connection>
|
||||
<Foundation.Core.AssociationEnd xmi.id="xmi.70">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.AssociationEnd.isNavigable xmi.value="false"/>
|
||||
<Foundation.Core.AssociationEnd.aggregation xmi.value="none"/>
|
||||
<Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.Association xmi.idref="xmi.69"/>
|
||||
</Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.AssociationEnd.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.32"/>
|
||||
</Foundation.Core.AssociationEnd.type>
|
||||
</Foundation.Core.AssociationEnd>
|
||||
<Foundation.Core.AssociationEnd xmi.id="xmi.71">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.AssociationEnd.isNavigable xmi.value="true"/>
|
||||
<Foundation.Core.AssociationEnd.aggregation xmi.value="none"/>
|
||||
<Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.Association xmi.idref="xmi.69"/>
|
||||
</Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.AssociationEnd.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.28"/>
|
||||
</Foundation.Core.AssociationEnd.type>
|
||||
</Foundation.Core.AssociationEnd>
|
||||
</Foundation.Core.Association.connection>
|
||||
</Foundation.Core.Association>
|
||||
<Foundation.Core.Dependency xmi.id="xmi.3" xmi.uuid="148603:e3c5d490c2:-7ffc">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Dependency.client>
|
||||
<Foundation.Core.ModelElement xmi.idref="xmi.2"/>
|
||||
</Foundation.Core.Dependency.client>
|
||||
<Foundation.Core.Dependency.supplier>
|
||||
<Foundation.Core.ModelElement xmi.idref="xmi.28"/>
|
||||
</Foundation.Core.Dependency.supplier>
|
||||
</Foundation.Core.Dependency>
|
||||
<Foundation.Core.Association xmi.id="xmi.72" xmi.uuid="148603:e3c5d490c2:-7ffb">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Association.connection>
|
||||
<Foundation.Core.AssociationEnd xmi.id="xmi.73">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.AssociationEnd.isNavigable xmi.value="true"/>
|
||||
<Foundation.Core.AssociationEnd.aggregation xmi.value="composite"/>
|
||||
<Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.Association xmi.idref="xmi.72"/>
|
||||
</Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.AssociationEnd.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.43"/>
|
||||
</Foundation.Core.AssociationEnd.type>
|
||||
</Foundation.Core.AssociationEnd>
|
||||
<Foundation.Core.AssociationEnd xmi.id="xmi.74">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.AssociationEnd.isNavigable xmi.value="true"/>
|
||||
<Foundation.Core.AssociationEnd.aggregation xmi.value="none"/>
|
||||
<Foundation.Core.AssociationEnd.multiplicity>
|
||||
<Foundation.Data_Types.Multiplicity xmi.idref="xmi.50"/>
|
||||
</Foundation.Core.AssociationEnd.multiplicity>
|
||||
<Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.Association xmi.idref="xmi.72"/>
|
||||
</Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.AssociationEnd.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.28"/>
|
||||
</Foundation.Core.AssociationEnd.type>
|
||||
</Foundation.Core.AssociationEnd>
|
||||
</Foundation.Core.Association.connection>
|
||||
</Foundation.Core.Association>
|
||||
<Foundation.Core.Association xmi.id="xmi.75" xmi.uuid="127-0-0-2-2d6513:e47a7c3046:-7fff">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isRoot xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isLeaf xmi.value="false"/>
|
||||
<Foundation.Core.GeneralizableElement.isAbstract xmi.value="false"/>
|
||||
<Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Namespace xmi.idref="xmi.1"/>
|
||||
</Foundation.Core.ModelElement.namespace>
|
||||
<Foundation.Core.Association.connection>
|
||||
<Foundation.Core.AssociationEnd xmi.id="xmi.76">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.AssociationEnd.isNavigable xmi.value="true"/>
|
||||
<Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.Association xmi.idref="xmi.75"/>
|
||||
</Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.AssociationEnd.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.2"/>
|
||||
</Foundation.Core.AssociationEnd.type>
|
||||
</Foundation.Core.AssociationEnd>
|
||||
<Foundation.Core.AssociationEnd xmi.id="xmi.77">
|
||||
<Foundation.Core.ModelElement.isSpecification xmi.value="false"/>
|
||||
<Foundation.Core.AssociationEnd.isNavigable xmi.value="true"/>
|
||||
<Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.Association xmi.idref="xmi.75"/>
|
||||
</Foundation.Core.AssociationEnd.association>
|
||||
<Foundation.Core.AssociationEnd.type>
|
||||
<Foundation.Core.Classifier xmi.idref="xmi.46"/>
|
||||
</Foundation.Core.AssociationEnd.type>
|
||||
</Foundation.Core.AssociationEnd>
|
||||
</Foundation.Core.Association.connection>
|
||||
</Foundation.Core.Association>
|
||||
</Foundation.Core.Namespace.ownedElement>
|
||||
</Model_Management.Model>
|
||||
</XMI.content>
|
||||
</XMI>
|
|
@ -0,0 +1,815 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE pgml SYSTEM "pgml.dtd">
|
||||
<pgml description="org.argouml.uml.diagram.static_structure.ui.UMLClassDiagram|25af9f:e3b707cd28:-8000"
|
||||
name="overview"
|
||||
>
|
||||
<group name="Fig0"
|
||||
description="org.argouml.uml.diagram.static_structure.ui.FigClass[16, 168, 268, 156]"
|
||||
href="25af9f:e3b707cd28:-7fff"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
|
||||
<rectangle name="Fig0.0"
|
||||
x="16"
|
||||
y="168"
|
||||
width="268"
|
||||
height="155"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
/>
|
||||
<text name="Fig0.1"
|
||||
x="10"
|
||||
y="10"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
></text>
|
||||
<text name="Fig0.2"
|
||||
x="16"
|
||||
y="168"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog.italic"
|
||||
textsize="9"
|
||||
>WeightedMeasurement</text>
|
||||
<rectangle name="Fig0.3"
|
||||
x="10"
|
||||
y="15"
|
||||
width="2"
|
||||
height="60"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-1"
|
||||
/>
|
||||
<text name="Fig0.4"
|
||||
x="16"
|
||||
y="193"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
>protected double weight_
|
||||
protected double measuredValue_
|
||||
protected boolean ignored_</text>
|
||||
<text name="Fig0.5"
|
||||
x="16"
|
||||
y="238"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
>public double getWeight()
|
||||
public double getMeasuredValue()
|
||||
public void setIgnored(boolean ignored)
|
||||
public boolean isIgnored()
|
||||
public double getTheoreticalValue()
|
||||
public double getResidual()
|
||||
public double getPartial(EstimatedParameter parameter)</text>
|
||||
</group>
|
||||
<group name="Fig1"
|
||||
description="org.argouml.uml.diagram.static_structure.ui.FigInterface[288, 96, 271, 62]"
|
||||
href="25af9f:e3b707cd28:-7ffd"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
|
||||
<rectangle name="Fig1.0"
|
||||
x="289"
|
||||
y="97"
|
||||
width="269"
|
||||
height="60"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
/>
|
||||
<rectangle name="Fig1.1"
|
||||
x="288"
|
||||
y="96"
|
||||
width="271"
|
||||
height="26"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
/>
|
||||
<text name="Fig1.2"
|
||||
x="289"
|
||||
y="97"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="0"
|
||||
strokecolor="-16777216"
|
||||
font="Lucida Sans"
|
||||
textsize="10"
|
||||
><<Interface>></text>
|
||||
<text name="Fig1.3"
|
||||
x="289"
|
||||
y="109"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="0"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
>EstimationProblem</text>
|
||||
<text name="Fig1.4"
|
||||
x="288"
|
||||
y="121"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
>public WeightedMeasurement[] getMeasurements()
|
||||
public EstimatedParameter[] getUnboundParameters()
|
||||
public EstimatedParameter[] getAllParameters()</text>
|
||||
</group>
|
||||
<group name="Fig2"
|
||||
description="org.argouml.uml.diagram.static_structure.ui.FigInterface[112, 0, 237, 64]"
|
||||
href="25af9f:e3b707cd28:-7ffc"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
|
||||
<rectangle name="Fig2.0"
|
||||
x="113"
|
||||
y="1"
|
||||
width="235"
|
||||
height="62"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
/>
|
||||
<rectangle name="Fig2.1"
|
||||
x="112"
|
||||
y="0"
|
||||
width="237"
|
||||
height="26"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
/>
|
||||
<text name="Fig2.2"
|
||||
x="113"
|
||||
y="1"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="0"
|
||||
strokecolor="-16777216"
|
||||
font="Lucida Sans"
|
||||
textsize="10"
|
||||
><<Interface>></text>
|
||||
<text name="Fig2.3"
|
||||
x="113"
|
||||
y="13"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="0"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
>Estimator</text>
|
||||
<text name="Fig2.4"
|
||||
x="112"
|
||||
y="25"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
>public void estimate(EstimationProblem problem)</text>
|
||||
</group>
|
||||
<group name="Fig3"
|
||||
description="org.argouml.uml.diagram.static_structure.ui.FigClass[459, 4, 140, 62]"
|
||||
href="25af9f:e3b707cd28:-7ff9"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
|
||||
<rectangle name="Fig3.0"
|
||||
x="459"
|
||||
y="4"
|
||||
width="140"
|
||||
height="61"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
/>
|
||||
<text name="Fig3.1"
|
||||
x="10"
|
||||
y="10"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
></text>
|
||||
<text name="Fig3.2"
|
||||
x="459"
|
||||
y="4"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
>LeastSquaresEstimator</text>
|
||||
<rectangle name="Fig3.3"
|
||||
x="10"
|
||||
y="15"
|
||||
width="2"
|
||||
height="60"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-1"
|
||||
/>
|
||||
<text name="Fig3.4"
|
||||
x="459"
|
||||
y="21"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
>private int maxIterations_
|
||||
private double convergence_</text>
|
||||
<text name="Fig3.5"
|
||||
x="459"
|
||||
y="48"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
></text>
|
||||
</group>
|
||||
<group name="Fig4"
|
||||
description="org.argouml.uml.diagram.static_structure.ui.FigClass[168, 436, 214, 43]"
|
||||
href="3a34af:e3c5366c0a:-7fff"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
|
||||
<rectangle name="Fig4.0"
|
||||
x="168"
|
||||
y="436"
|
||||
width="214"
|
||||
height="42"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
/>
|
||||
<text name="Fig4.1"
|
||||
x="10"
|
||||
y="10"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
></text>
|
||||
<text name="Fig4.2"
|
||||
x="168"
|
||||
y="436"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
>MyProblem</text>
|
||||
<rectangle name="Fig4.3"
|
||||
x="10"
|
||||
y="15"
|
||||
width="2"
|
||||
height="60"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-256"
|
||||
/>
|
||||
<text name="Fig4.4"
|
||||
x="168"
|
||||
y="450"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
></text>
|
||||
<text name="Fig4.5"
|
||||
x="168"
|
||||
y="464"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
></text>
|
||||
</group>
|
||||
<group name="Fig5"
|
||||
description="org.argouml.uml.diagram.static_structure.ui.FigClass[24, 349, 125, 43]"
|
||||
href="3a34af:e3c5366c0a:-7ffd"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
|
||||
<rectangle name="Fig5.0"
|
||||
x="24"
|
||||
y="349"
|
||||
width="125"
|
||||
height="42"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
/>
|
||||
<text name="Fig5.1"
|
||||
x="10"
|
||||
y="10"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
></text>
|
||||
<text name="Fig5.2"
|
||||
x="24"
|
||||
y="349"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
>MyFirstMeasurementType</text>
|
||||
<rectangle name="Fig5.3"
|
||||
x="10"
|
||||
y="15"
|
||||
width="2"
|
||||
height="60"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-256"
|
||||
/>
|
||||
<text name="Fig5.4"
|
||||
x="24"
|
||||
y="363"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
></text>
|
||||
<text name="Fig5.5"
|
||||
x="24"
|
||||
y="377"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
></text>
|
||||
</group>
|
||||
<group name="Fig6"
|
||||
description="org.argouml.uml.diagram.static_structure.ui.FigClass[168, 349, 137, 43]"
|
||||
href="3a34af:e3c5366c0a:-7ffb"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
|
||||
<rectangle name="Fig6.0"
|
||||
x="168"
|
||||
y="349"
|
||||
width="137"
|
||||
height="42"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
/>
|
||||
<text name="Fig6.1"
|
||||
x="10"
|
||||
y="10"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
></text>
|
||||
<text name="Fig6.2"
|
||||
x="168"
|
||||
y="349"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
>MySecondMeasurementType</text>
|
||||
<rectangle name="Fig6.3"
|
||||
x="10"
|
||||
y="15"
|
||||
width="2"
|
||||
height="60"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-256"
|
||||
/>
|
||||
<text name="Fig6.4"
|
||||
x="168"
|
||||
y="363"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
></text>
|
||||
<text name="Fig6.5"
|
||||
x="168"
|
||||
y="377"
|
||||
fill="1"
|
||||
fillcolor="-256"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
></text>
|
||||
</group>
|
||||
<group name="Fig7"
|
||||
description="org.argouml.uml.diagram.static_structure.ui.FigClass[320, 240, 197, 89]"
|
||||
href="148603:e3c5d490c2:-7fff"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
|
||||
<rectangle name="Fig7.0"
|
||||
x="320"
|
||||
y="240"
|
||||
width="197"
|
||||
height="88"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
/>
|
||||
<text name="Fig7.1"
|
||||
x="10"
|
||||
y="10"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
></text>
|
||||
<text name="Fig7.2"
|
||||
x="320"
|
||||
y="240"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
>EstimatedParameter</text>
|
||||
<rectangle name="Fig7.3"
|
||||
x="10"
|
||||
y="15"
|
||||
width="2"
|
||||
height="60"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-1"
|
||||
/>
|
||||
<text name="Fig7.4"
|
||||
x="320"
|
||||
y="256"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
>private String name_
|
||||
private double estimate_
|
||||
private boolean bound_</text>
|
||||
<text name="Fig7.5"
|
||||
x="320"
|
||||
y="292"
|
||||
fill="1"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
font="dialog"
|
||||
textsize="9"
|
||||
>public void setEstimate(double estimate)
|
||||
public double getEstimate()
|
||||
public boolean isBound()</text>
|
||||
</group>
|
||||
<group name="Fig8"
|
||||
description="org.argouml.uml.diagram.ui.FigDependency"
|
||||
href="25af9f:e3b707cd28:-7ffb"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
<path name="LAYER_NULL"
|
||||
description="org.tigris.gef.presentation.FigPoly"
|
||||
fill="0"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<moveto x="0"
|
||||
y="0" />
|
||||
</path>
|
||||
</group>
|
||||
<group name="Fig9"
|
||||
description="org.argouml.uml.diagram.ui.FigAssociation"
|
||||
href="25af9f:e3b707cd28:-7ffa"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
<path name="LAYER_NULL"
|
||||
description="org.tigris.gef.presentation.FigPoly"
|
||||
fill="0"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<moveto x="0"
|
||||
y="0" />
|
||||
</path>
|
||||
</group>
|
||||
<group name="Fig10"
|
||||
description="org.argouml.uml.diagram.ui.FigDependency"
|
||||
href="25af9f:e3b707cd28:-7ff8"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
<path name="LAYER_NULL"
|
||||
description="org.tigris.gef.presentation.FigPoly"
|
||||
fill="0"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<moveto x="0"
|
||||
y="0" />
|
||||
</path>
|
||||
</group>
|
||||
<group name="Fig11"
|
||||
description="org.argouml.uml.diagram.ui.FigDependency"
|
||||
href="3a34af:e3c5366c0a:-7ffe"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
<path name="LAYER_NULL"
|
||||
description="org.tigris.gef.presentation.FigPoly"
|
||||
fill="0"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<moveto x="0"
|
||||
y="0" />
|
||||
</path>
|
||||
</group>
|
||||
<group name="Fig12"
|
||||
description="org.argouml.uml.diagram.ui.FigGeneralization"
|
||||
href="3a34af:e3c5366c0a:-7ffc"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
<path name="LAYER_NULL"
|
||||
description="org.tigris.gef.presentation.FigPoly"
|
||||
fill="0"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<moveto x="0"
|
||||
y="0" />
|
||||
</path>
|
||||
</group>
|
||||
<group name="Fig13"
|
||||
description="org.argouml.uml.diagram.ui.FigGeneralization"
|
||||
href="3a34af:e3c5366c0a:-7ffa"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
<path name="LAYER_NULL"
|
||||
description="org.tigris.gef.presentation.FigPoly"
|
||||
fill="0"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<moveto x="0"
|
||||
y="0" />
|
||||
</path>
|
||||
</group>
|
||||
<group name="Fig14"
|
||||
description="org.argouml.uml.diagram.ui.FigAssociation"
|
||||
href="3a34af:e3c5366c0a:-7ff9"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
<path name="LAYER_NULL"
|
||||
description="org.tigris.gef.presentation.FigPoly"
|
||||
fill="0"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<moveto x="0"
|
||||
y="0" />
|
||||
</path>
|
||||
</group>
|
||||
<group name="Fig15"
|
||||
description="org.argouml.uml.diagram.ui.FigAssociation"
|
||||
href="3a34af:e3c5366c0a:-7ff8"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
<path name="LAYER_NULL"
|
||||
description="org.tigris.gef.presentation.FigPoly"
|
||||
fill="0"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<moveto x="0"
|
||||
y="0" />
|
||||
</path>
|
||||
</group>
|
||||
<group name="Fig16"
|
||||
description="org.argouml.uml.diagram.ui.FigAssociation"
|
||||
href="148603:e3c5d490c2:-7ffd"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
<path name="LAYER_NULL"
|
||||
description="org.tigris.gef.presentation.FigPoly"
|
||||
fill="0"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<moveto x="0"
|
||||
y="0" />
|
||||
</path>
|
||||
</group>
|
||||
<group name="Fig17"
|
||||
description="org.argouml.uml.diagram.ui.FigDependency"
|
||||
href="148603:e3c5d490c2:-7ffc"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
<path name="LAYER_NULL"
|
||||
description="org.tigris.gef.presentation.FigPoly"
|
||||
fill="0"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<moveto x="0"
|
||||
y="0" />
|
||||
</path>
|
||||
</group>
|
||||
<group name="Fig18"
|
||||
description="org.argouml.uml.diagram.ui.FigAssociation"
|
||||
href="148603:e3c5d490c2:-7ffb"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
</private>
|
||||
<path name="LAYER_NULL"
|
||||
description="org.tigris.gef.presentation.FigPoly"
|
||||
fill="0"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<moveto x="0"
|
||||
y="0" />
|
||||
</path>
|
||||
</group>
|
||||
<group name="Fig19"
|
||||
description="org.argouml.uml.diagram.ui.FigAssociation"
|
||||
href="127-0-0-2-2d6513:e47a7c3046:-7fff"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<private>
|
||||
sourcePortFig="Fig0.0"
|
||||
destPortFig="Fig5.0"
|
||||
sourceFigNode="Fig0"
|
||||
destFigNode="Fig5"
|
||||
</private>
|
||||
<path name="Fig19.1"
|
||||
description="org.tigris.gef.presentation.FigPoly"
|
||||
fill="0"
|
||||
fillcolor="-1"
|
||||
stroke="1"
|
||||
strokecolor="-16777216"
|
||||
>
|
||||
<moveto x="224"
|
||||
y="323" />
|
||||
<lineto x="224"
|
||||
y="336" />
|
||||
<lineto x="48"
|
||||
y="336" />
|
||||
<lineto x="48"
|
||||
y="349" />
|
||||
</path>
|
||||
</group>
|
||||
</pgml>
|
Binary file not shown.
|
@ -0,0 +1,52 @@
|
|||
<html>
|
||||
<body>
|
||||
This package provides classes to solve estimation problems.
|
||||
|
||||
<p>The estimation problems considered here are parametric problems where a user model
|
||||
depends on initially unknown scalar parameters and several measurements made on
|
||||
values that depend on the model are available. As an example, one can consider the
|
||||
flow rate of a river given rain data on its vicinity, or the center and radius of a
|
||||
circle given points on a ring.</p>
|
||||
|
||||
<p>One important class of estimation problems is weighted least squares problems.
|
||||
They basically consist in finding the values for some parameters p<sub>k</sub> such
|
||||
that a cost function J = sum(w<sub>i</sub> r<sub>i</sub><sup>2</sup>) is minimized.
|
||||
The various r<sub>i</sub> terms represent the deviation r<sub>i</sub> =
|
||||
mes<sub>i</sub> - mod<sub>i</sub> between the measurements and the parameterized
|
||||
models. The w<sub>i</sub> factors are the measurements weights, they are often chosen
|
||||
either all equal to 1.0 or proportional to the inverse of the variance of the
|
||||
measurement type. The solver adjusts the values of the estimated parameters
|
||||
p<sub>k</sub> which are not bound. It does not touch the parameters which have been
|
||||
put in a bound state by the user.</p>
|
||||
|
||||
<p>This package provides the {@link
|
||||
org.spaceroots.mantissa.estimation.EstimatedParameter EstimatedParameter} class to
|
||||
represent each estimated parameter, and the {@link
|
||||
org.spaceroots.mantissa.estimation.WeightedMeasurement WeightedMeasurement} abstract
|
||||
class the user can extend to define its measurements. All parameters and measurements
|
||||
are then provided to some {@link org.spaceroots.mantissa.estimation.Estimator
|
||||
Estimator} packed together in an {@link
|
||||
org.spaceroots.mantissa.estimation.EstimationProblem EstimationProblem} instance
|
||||
which acts only as a container. The package provides two common estimators for
|
||||
weighted least squares problems, one based on the {@link
|
||||
org.spaceroots.mantissa.estimation.GaussNewtonEstimator Gauss-Newton} method and the
|
||||
other one based on the {@link
|
||||
org.spaceroots.mantissa.estimation.LevenbergMarquardtEstimator Levenberg-Marquardt}
|
||||
method.</p>
|
||||
|
||||
<p>The class diagram for the public classes of this package is displayed below. The
|
||||
orange boxes <code>UserProblem</code>, <code>UserFirstMeasurementType</code> and
|
||||
<code>UserSecondMeasurementType</code> are exemple of what the user should create to
|
||||
use this package: implement his own problem and measurement types using the {@link
|
||||
org.spaceroots.mantissa.estimation.EstimationProblem} interface and {@link
|
||||
org.spaceroots.mantissa.estimation.WeightedMeasurement} abstract class, and then use
|
||||
one of the provided estimators (for example {@link
|
||||
org.spaceroots.mantissa.estimation.GaussNewtonEstimator} or {@link
|
||||
org.spaceroots.mantissa.estimation.LevenbergMarquardtEstimator}) to solve it. The
|
||||
white boxes are the interfaces and classes already provided by the library.</p>
|
||||
|
||||
<img src="doc-files/org_spaceroots_mantissa_estimation_classes.png" />
|
||||
|
||||
@author L. Maisonobe
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,286 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.fitting;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.spaceroots.mantissa.estimation.*;
|
||||
|
||||
/** This class is the base class for all curve fitting classes in the package.
|
||||
|
||||
* <p>This class handles all common features of curve fitting like the
|
||||
* sample points handling. It declares two methods ({@link
|
||||
* #valueAt} and {@link #partial}) which should be implemented by
|
||||
* sub-classes to define the precise shape of the curve they
|
||||
* represent.</p>
|
||||
|
||||
* @version $Id: AbstractCurveFitter.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public abstract class AbstractCurveFitter
|
||||
implements EstimationProblem, Serializable {
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* @param n number of coefficients in the underlying function
|
||||
* @param maxIterations maximum number of iterations allowed
|
||||
* @param convergence criterion threshold below which we do not need
|
||||
* to improve the criterion anymore
|
||||
* @param steadyStateThreshold steady state detection threshold, the
|
||||
* problem has reached a steady state (read converged) if
|
||||
* <code>Math.abs (Jn - Jn-1) < Jn * convergence</code>, where
|
||||
* <code>Jn</code> and <code>Jn-1</code> are the current and
|
||||
* preceding criterion value (square sum of the weighted residuals
|
||||
* of considered measurements).
|
||||
* @param epsilon threshold under which the matrix of the linearized
|
||||
* problem is considered singular (see {@link
|
||||
* org.spaceroots.mantissa.linalg.SquareMatrix#solve(
|
||||
* org.spaceroots.mantissa.linalg.Matrix,double) SquareMatrix.solve}).
|
||||
*/
|
||||
protected AbstractCurveFitter(int n,
|
||||
int maxIterations,
|
||||
double convergence,
|
||||
double steadyStateThreshold,
|
||||
double epsilon) {
|
||||
|
||||
coefficients = new EstimatedParameter[n];
|
||||
measurements = new ArrayList();
|
||||
measurementsArray = null;
|
||||
this.maxIterations = maxIterations;
|
||||
this.steadyStateThreshold = steadyStateThreshold;
|
||||
this.convergence = convergence;
|
||||
this.epsilon = epsilon;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* @param coefficients first estimate of the coefficients. A
|
||||
* reference to this array is hold by the newly created object. Its
|
||||
* elements will be adjusted during the fitting process and they will
|
||||
* be set to the adjusted coefficients at the end.
|
||||
* @param maxIterations maximum number of iterations allowed
|
||||
* @param convergence criterion threshold below which we do not need
|
||||
* to improve the criterion anymore
|
||||
* @param steadyStateThreshold steady state detection threshold, the
|
||||
* problem has reached a steady state (read converged) if
|
||||
* <code>Math.abs (Jn - Jn-1) < Jn * convergence</code>, where
|
||||
* <code>Jn</code> and <code>Jn-1</code> are the current and
|
||||
* preceding criterion value (square sum of the weighted residuals
|
||||
* of considered measurements).
|
||||
* @param epsilon threshold under which the matrix of the linearized
|
||||
* problem is considered singular (see {@link
|
||||
* org.spaceroots.mantissa.linalg.SquareMatrix#solve(
|
||||
* org.spaceroots.mantissa.linalg.Matrix,double) SquareMatrix.solve}).
|
||||
*/
|
||||
protected AbstractCurveFitter(EstimatedParameter[] coefficients,
|
||||
int maxIterations,
|
||||
double convergence,
|
||||
double steadyStateThreshold,
|
||||
double epsilon) {
|
||||
|
||||
this.coefficients = coefficients;
|
||||
measurements = new ArrayList();
|
||||
measurementsArray = null;
|
||||
this.maxIterations = maxIterations;
|
||||
this.steadyStateThreshold = steadyStateThreshold;
|
||||
this.convergence = convergence;
|
||||
this.epsilon = epsilon;
|
||||
}
|
||||
|
||||
/** Add a weighted (x,y) pair to the sample.
|
||||
* @param weight weight of this pair in the fit
|
||||
* @param x abscissa
|
||||
* @param y ordinate, we have <code>y = f (x)</code>
|
||||
*/
|
||||
public void addWeightedPair(double weight, double x, double y) {
|
||||
measurementsArray = null;
|
||||
measurements.add(new FitMeasurement(weight, x, y));
|
||||
}
|
||||
|
||||
/** Perform the fitting.
|
||||
|
||||
* <p>This method compute the coefficients of the curve that best
|
||||
* fit the sample of weighted pairs previously given through calls
|
||||
* to the {@link #addWeightedPair addWeightedPair} method.</p>
|
||||
|
||||
* @return coefficients of the curve
|
||||
* @exception EstimationException if the fitting is not possible
|
||||
* (for example if the sample has to few independant points)
|
||||
|
||||
*/
|
||||
public double[] fit()
|
||||
throws EstimationException {
|
||||
// perform the fit using a linear least square estimator
|
||||
new GaussNewtonEstimator(maxIterations, convergence,
|
||||
steadyStateThreshold, epsilon).estimate(this);
|
||||
|
||||
// extract the coefficients
|
||||
double[] fittedCoefficients = new double[coefficients.length];
|
||||
for (int i = 0; i < coefficients.length; ++i) {
|
||||
fittedCoefficients[i] = coefficients[i].getEstimate();
|
||||
}
|
||||
|
||||
return fittedCoefficients;
|
||||
|
||||
}
|
||||
|
||||
public WeightedMeasurement[] getMeasurements() {
|
||||
if (measurementsArray == null) {
|
||||
measurementsArray = new FitMeasurement[measurements.size()];
|
||||
int i = 0;
|
||||
for (Iterator iterator = measurements.iterator(); iterator.hasNext(); ++i) {
|
||||
measurementsArray[i] = (FitMeasurement) iterator.next();
|
||||
}
|
||||
}
|
||||
return measurementsArray;
|
||||
}
|
||||
|
||||
/** Get the unbound parameters of the problem.
|
||||
* For a curve fitting, none of the function coefficient is bound.
|
||||
* @return unbound parameters
|
||||
*/
|
||||
public EstimatedParameter[] getUnboundParameters() {
|
||||
return coefficients;
|
||||
}
|
||||
|
||||
/** Get all the parameters of the problem.
|
||||
* @return parameters
|
||||
*/
|
||||
public EstimatedParameter[] getAllParameters() {
|
||||
return coefficients;
|
||||
}
|
||||
|
||||
/** Utility method to sort the measurements with respect to the abscissa.
|
||||
|
||||
* <p>This method is provided as a utility for derived classes. As
|
||||
* an example, the {@link HarmonicFitter} class needs it in order to
|
||||
* compute a first guess of the coefficients to initialize the
|
||||
* estimation algorithm.</p>
|
||||
|
||||
*/
|
||||
protected void sortMeasurements() {
|
||||
|
||||
// Since the samples are almost always already sorted, this
|
||||
// method is implemented as an insertion sort that reorders the
|
||||
// elements in place. Insertion sort is very efficient in this case.
|
||||
FitMeasurement curr = (FitMeasurement) measurements.get(0);
|
||||
for (int j = 1; j < measurements.size (); ++j) {
|
||||
FitMeasurement prec = curr;
|
||||
curr = (FitMeasurement) measurements.get(j);
|
||||
if (curr.x < prec.x) {
|
||||
// the current element should be inserted closer to the beginning
|
||||
int i = j - 1;
|
||||
FitMeasurement mI = (FitMeasurement) measurements.get(i);
|
||||
while ((i >= 0) && (curr.x < mI.x)) {
|
||||
measurements.set(i + 1, mI);
|
||||
if (i-- != 0) {
|
||||
mI = (FitMeasurement) measurements.get(i);
|
||||
} else {
|
||||
mI = null;
|
||||
}
|
||||
}
|
||||
measurements.set(i + 1, curr);
|
||||
curr = (FitMeasurement) measurements.get(j);
|
||||
}
|
||||
}
|
||||
|
||||
// make sure subsequent calls to getMeasurements
|
||||
// will not use the unsorted array
|
||||
measurementsArray = null;
|
||||
|
||||
}
|
||||
|
||||
/** Get the value of the function at x according to the current parameters value.
|
||||
* @param x abscissa at which the theoretical value is requested
|
||||
* @return theoretical value at x
|
||||
*/
|
||||
public abstract double valueAt(double x);
|
||||
|
||||
/** Get the derivative of the function at x with respect to parameter p.
|
||||
* @param x abscissa at which the partial derivative is requested
|
||||
* @param p parameter with respect to which the derivative is requested
|
||||
* @return partial derivative
|
||||
*/
|
||||
public abstract double partial(double x, EstimatedParameter p);
|
||||
|
||||
/** This class represents the fit measurements.
|
||||
* One measurement is a weighted pair (x, y), where <code>y = f
|
||||
* (x)</code> is the value of the function at x abscissa. This class
|
||||
* is an inner class because the methods related to the computation
|
||||
* of f values and derivative are proveded by the fitter
|
||||
* implementations.
|
||||
*/
|
||||
public class FitMeasurement
|
||||
extends WeightedMeasurement {
|
||||
|
||||
/** Simple constructor.
|
||||
* @param weight weight of the measurement in the fitting process
|
||||
* @param x abscissa of the measurement
|
||||
* @param y ordinate of the measurement
|
||||
*/
|
||||
public FitMeasurement(double weight, double x, double y) {
|
||||
super(weight, y);
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
/** Get the value of the fitted function at x.
|
||||
* @return theoretical value at the measurement abscissa
|
||||
*/
|
||||
public double getTheoreticalValue() {
|
||||
return valueAt(x);
|
||||
}
|
||||
|
||||
/** Partial derivative with respect to one function coefficient.
|
||||
* @param p parameter with respect to which the derivative is requested
|
||||
* @return partial derivative
|
||||
*/
|
||||
public double getPartial(EstimatedParameter p) {
|
||||
return partial(x, p);
|
||||
}
|
||||
|
||||
/** Abscissa of the measurement. */
|
||||
public final double x;
|
||||
|
||||
private static final long serialVersionUID = -2682582852369995960L;
|
||||
|
||||
}
|
||||
|
||||
/** Coefficients of the function */
|
||||
protected EstimatedParameter[] coefficients;
|
||||
|
||||
/** Measurements vector */
|
||||
protected List measurements;
|
||||
|
||||
/** Measurements array.
|
||||
* This array contains the same entries as measurements_, but in a
|
||||
* different structure.
|
||||
*/
|
||||
private FitMeasurement[] measurementsArray;
|
||||
|
||||
private int maxIterations;
|
||||
private double convergence;
|
||||
private double steadyStateThreshold;
|
||||
private double epsilon;
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.fitting;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.spaceroots.mantissa.functions.FunctionException;
|
||||
import org.spaceroots.mantissa.functions.ExhaustedSampleException;
|
||||
import org.spaceroots.mantissa.functions.vectorial.SampledFunctionIterator;
|
||||
import org.spaceroots.mantissa.functions.vectorial.VectorialValuedPair;
|
||||
|
||||
/** This class provides sampled values of the function t -> [f(t)^2, f'(t)^2].
|
||||
|
||||
* This class is a helper class used to compute a first guess of the
|
||||
* harmonic coefficients of a function <code>f (t) = a cos (omega t +
|
||||
* phi)</code>.
|
||||
|
||||
* @see FFPIterator
|
||||
* @see HarmonicCoefficientsGuesser
|
||||
|
||||
* @version $Id: F2FP2Iterator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
class F2FP2Iterator
|
||||
implements SampledFunctionIterator, Serializable {
|
||||
|
||||
public F2FP2Iterator(AbstractCurveFitter.FitMeasurement[] measurements) {
|
||||
ffpIterator = new FFPIterator(measurements);
|
||||
}
|
||||
|
||||
public int getDimension() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return ffpIterator.hasNext();
|
||||
}
|
||||
|
||||
public VectorialValuedPair nextSamplePoint()
|
||||
throws ExhaustedSampleException, FunctionException {
|
||||
|
||||
// get the raw values from the underlying FFPIterator
|
||||
VectorialValuedPair point = ffpIterator.nextSamplePoint();
|
||||
|
||||
// hack the values (to avoid building a new object)
|
||||
double[] y = point.getY();
|
||||
y[0] *= y[0];
|
||||
y[1] *= y[1];
|
||||
return point;
|
||||
|
||||
}
|
||||
|
||||
private FFPIterator ffpIterator;
|
||||
|
||||
private static final long serialVersionUID = -8113110433795298072L;
|
||||
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.fitting;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.spaceroots.mantissa.functions.FunctionException;
|
||||
import org.spaceroots.mantissa.functions.ExhaustedSampleException;
|
||||
import org.spaceroots.mantissa.functions.vectorial.SampledFunctionIterator;
|
||||
import org.spaceroots.mantissa.functions.vectorial.VectorialValuedPair;
|
||||
|
||||
/** This class provides sampled values of the function t -> [f(t), f'(t)].
|
||||
|
||||
* This class is a helper class used to compute a first guess of the
|
||||
* harmonic coefficients of a function <code>f (t) = a cos (omega t +
|
||||
* phi)</code>.
|
||||
|
||||
* @see F2FP2Iterator
|
||||
* @see HarmonicCoefficientsGuesser
|
||||
|
||||
* @version $Id: FFPIterator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
class FFPIterator
|
||||
implements SampledFunctionIterator, Serializable {
|
||||
|
||||
public FFPIterator(AbstractCurveFitter.FitMeasurement[] measurements) {
|
||||
this.measurements = measurements;
|
||||
|
||||
// initialize the points of the raw sample
|
||||
current = measurements[0];
|
||||
currentY = current.getMeasuredValue();
|
||||
next = measurements[1];
|
||||
nextY = next.getMeasuredValue();
|
||||
nextIndex = 2;
|
||||
|
||||
}
|
||||
|
||||
public int getDimension() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return nextIndex < measurements.length;
|
||||
}
|
||||
|
||||
public VectorialValuedPair nextSamplePoint()
|
||||
throws ExhaustedSampleException, FunctionException {
|
||||
if (nextIndex >= measurements.length) {
|
||||
throw new ExhaustedSampleException(measurements.length);
|
||||
}
|
||||
|
||||
// shift the points
|
||||
previous = current;
|
||||
previousY = currentY;
|
||||
current = next;
|
||||
currentY = nextY;
|
||||
next = measurements[nextIndex++];
|
||||
nextY = next.getMeasuredValue();
|
||||
|
||||
// return the two dimensions vector [f(x), f'(x)]
|
||||
double[] table = new double[2];
|
||||
table[0] = currentY;
|
||||
table[1] = (nextY - previousY) / (next.x - previous.x);
|
||||
return new VectorialValuedPair(current.x, table);
|
||||
|
||||
}
|
||||
|
||||
private AbstractCurveFitter.FitMeasurement[] measurements;
|
||||
private int nextIndex;
|
||||
|
||||
private AbstractCurveFitter.FitMeasurement previous;
|
||||
private double previousY;
|
||||
|
||||
private AbstractCurveFitter.FitMeasurement current;
|
||||
private double nextY;
|
||||
|
||||
private AbstractCurveFitter.FitMeasurement next;
|
||||
private double currentY;
|
||||
|
||||
private static final long serialVersionUID = -3187229691615380125L;
|
||||
|
||||
}
|
|
@ -0,0 +1,271 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.fitting;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.spaceroots.mantissa.functions.FunctionException;
|
||||
import org.spaceroots.mantissa.functions.ExhaustedSampleException;
|
||||
import org.spaceroots.mantissa.functions.vectorial.SampledFunctionIterator;
|
||||
import org.spaceroots.mantissa.functions.vectorial.VectorialValuedPair;
|
||||
|
||||
import org.spaceroots.mantissa.quadrature.vectorial.EnhancedSimpsonIntegratorSampler;
|
||||
|
||||
import org.spaceroots.mantissa.estimation.EstimationException;
|
||||
|
||||
/** This class guesses harmonic coefficients from a sample.
|
||||
|
||||
* <p>The algorithm used to guess the coefficients is as follows:</p>
|
||||
|
||||
* <p>We know f (t) at some sampling points ti and want to find a,
|
||||
* omega and phi such that f (t) = a cos (omega t + phi).
|
||||
* </p>
|
||||
*
|
||||
* <p>From the analytical expression, we can compute two primitives :
|
||||
* <pre>
|
||||
* If2 (t) = int (f^2) = a^2 * [t + S (t)] / 2
|
||||
* If'2 (t) = int (f'^2) = a^2 * omega^2 * [t - S (t)] / 2
|
||||
* where S (t) = sin (2 * (omega * t + phi)) / (2 * omega)
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
* <p>We can remove S between these expressions :
|
||||
* <pre>
|
||||
* If'2 (t) = a^2 * omega ^ 2 * t - omega ^ 2 * If2 (t)
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
* <p>The preceding expression shows that If'2 (t) is a linear
|
||||
* combination of both t and If2 (t): If'2 (t) = A * t + B * If2 (t)
|
||||
* </p>
|
||||
*
|
||||
* <p>From the primitive, we can deduce the same form for definite
|
||||
* integrals between t1 and ti for each ti :
|
||||
* <pre>
|
||||
* If2 (ti) - If2 (t1) = A * (ti - t1) + B * (If2 (ti) - If2 (t1))
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
* <p>We can find the coefficients A and B that best fit the sample
|
||||
* to this linear expression by computing the definite integrals for
|
||||
* each sample points.
|
||||
* </p>
|
||||
*
|
||||
* <p>For a bilinear expression z (xi, yi) = A * xi + B * yi, the
|
||||
* coefficients a and b that minimize a least square criterion
|
||||
* Sum ((zi - z (xi, yi))^2) are given by these expressions:</p>
|
||||
* <pre>
|
||||
*
|
||||
* Sum (yi^2) Sum (xi zi) - Sum (xi yi) Sum (yi zi)
|
||||
* A = ------------------------------------------------
|
||||
* Sum (xi^2) Sum (yi^2) - Sum (xi yi) Sum (xi yi)
|
||||
*
|
||||
* Sum (xi^2) Sum (yi zi) - Sum (xi yi) Sum (xi zi)
|
||||
* B = ------------------------------------------------
|
||||
* Sum (xi^2) Sum (yi^2) - Sum (xi yi) Sum (xi yi)
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>In fact, we can assume both a and omega are positive and
|
||||
* compute them directly, knowing that A = a^2 * omega^2 and that
|
||||
* B = - omega^2. The complete algorithm is therefore:</p>
|
||||
* <pre>
|
||||
*
|
||||
* for each ti from t1 to t(n-1), compute:
|
||||
* f (ti)
|
||||
* f' (ti) = (f (t(i+1)) - f(t(i-1))) / (t(i+1) - t(i-1))
|
||||
* xi = ti - t1
|
||||
* yi = int (f^2) from t1 to ti
|
||||
* zi = int (f'^2) from t1 to ti
|
||||
* update the sums Sum (xi^2), Sum (yi^2),
|
||||
* Sum (xi yi), Sum (xi zi)
|
||||
* and Sum (yi zi)
|
||||
* end for
|
||||
*
|
||||
* |-------------------------------------------------
|
||||
* \ | Sum (yi^2) Sum (xi zi) - Sum (xi yi) Sum (yi zi)
|
||||
* a = \ | ------------------------------------------------
|
||||
* \| Sum (xi yi) Sum (xi zi) - Sum (xi^2) Sum (yi zi)
|
||||
*
|
||||
*
|
||||
* |-------------------------------------------------
|
||||
* \ | Sum (xi yi) Sum (xi zi) - Sum (xi^2) Sum (yi zi)
|
||||
* omega = \ | ------------------------------------------------
|
||||
* \| Sum (xi^2) Sum (yi^2) - Sum (xi yi) Sum (xi yi)
|
||||
*
|
||||
* </pre>
|
||||
* </p>
|
||||
|
||||
* <p>Once we know omega, we can compute:
|
||||
* <pre>
|
||||
* fc = omega * f (t) * cos (omega * t) - f' (t) * sin (omega * t)
|
||||
* fs = omega * f (t) * sin (omega * t) + f' (t) * cos (omega * t)
|
||||
* </pre>
|
||||
* </p>
|
||||
|
||||
* <p>It appears that <code>fc = a * omega * cos (phi)</code> and
|
||||
* <code>fs = -a * omega * sin (phi)</code>, so we can use these
|
||||
* expressions to compute phi. The best estimate over the sample is
|
||||
* given by averaging these expressions.
|
||||
* </p>
|
||||
|
||||
* <p>Since integrals and means are involved in the preceding
|
||||
* estimations, these operations run in O(n) time, where n is the
|
||||
* number of measurements.</p>
|
||||
|
||||
* @version $Id: HarmonicCoefficientsGuesser.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class HarmonicCoefficientsGuesser
|
||||
implements Serializable{
|
||||
|
||||
public HarmonicCoefficientsGuesser(AbstractCurveFitter.FitMeasurement[] measurements) {
|
||||
this.measurements = measurements;
|
||||
a = Double.NaN;
|
||||
omega = Double.NaN;
|
||||
}
|
||||
|
||||
/** Estimate a first guess of the coefficients.
|
||||
|
||||
* @exception ExhaustedSampleException if the sample is exhausted.
|
||||
|
||||
* @exception FunctionException if the integrator throws one.
|
||||
|
||||
* @exception EstimationException if the sample is too short or if
|
||||
* the first guess cannot be computed (when the elements under the
|
||||
* square roots are negative).
|
||||
* */
|
||||
public void guess()
|
||||
throws ExhaustedSampleException, FunctionException, EstimationException {
|
||||
guessAOmega();
|
||||
guessPhi();
|
||||
}
|
||||
|
||||
/** Estimate a first guess of the a and omega coefficients.
|
||||
|
||||
* @exception ExhaustedSampleException if the sample is exhausted.
|
||||
|
||||
* @exception FunctionException if the integrator throws one.
|
||||
|
||||
* @exception EstimationException if the sample is too short or if
|
||||
* the first guess cannot be computed (when the elements under the
|
||||
* square roots are negative).
|
||||
|
||||
*/
|
||||
private void guessAOmega()
|
||||
throws ExhaustedSampleException, FunctionException, EstimationException {
|
||||
|
||||
// initialize the sums for the linear model between the two integrals
|
||||
double sx2 = 0.0;
|
||||
double sy2 = 0.0;
|
||||
double sxy = 0.0;
|
||||
double sxz = 0.0;
|
||||
double syz = 0.0;
|
||||
|
||||
// build the integrals sampler
|
||||
F2FP2Iterator iter = new F2FP2Iterator(measurements);
|
||||
SampledFunctionIterator sampler =
|
||||
new EnhancedSimpsonIntegratorSampler(iter);
|
||||
VectorialValuedPair p0 = sampler.nextSamplePoint();
|
||||
double p0X = p0.getX();
|
||||
double[] p0Y = p0.getY();
|
||||
|
||||
// get the points for the linear model
|
||||
while (sampler.hasNext()) {
|
||||
|
||||
VectorialValuedPair point = sampler.nextSamplePoint();
|
||||
double pX = point.getX();
|
||||
double[] pY = point.getY();
|
||||
|
||||
double dx = pX - p0X;
|
||||
double dy0 = pY[0] - p0Y[0];
|
||||
double dy1 = pY[1] - p0Y[1];
|
||||
|
||||
sx2 += dx * dx;
|
||||
sy2 += dy0 * dy0;
|
||||
sxy += dx * dy0;
|
||||
sxz += dx * dy1;
|
||||
syz += dy0 * dy1;
|
||||
|
||||
}
|
||||
|
||||
// compute the amplitude and pulsation coefficients
|
||||
double c1 = sy2 * sxz - sxy * syz;
|
||||
double c2 = sxy * sxz - sx2 * syz;
|
||||
double c3 = sx2 * sy2 - sxy * sxy;
|
||||
if ((c1 / c2 < 0.0) || (c2 / c3 < 0.0)) {
|
||||
throw new EstimationException("unable to guess a first estimate");
|
||||
}
|
||||
a = Math.sqrt(c1 / c2);
|
||||
omega = Math.sqrt(c2 / c3);
|
||||
|
||||
}
|
||||
|
||||
/** Estimate a first guess of the phi coefficient.
|
||||
|
||||
* @exception ExhaustedSampleException if the sample is exhausted.
|
||||
|
||||
* @exception FunctionException if the sampler throws one.
|
||||
|
||||
*/
|
||||
private void guessPhi()
|
||||
throws ExhaustedSampleException, FunctionException {
|
||||
|
||||
SampledFunctionIterator iter = new FFPIterator(measurements);
|
||||
|
||||
// initialize the means
|
||||
double fcMean = 0.0;
|
||||
double fsMean = 0.0;
|
||||
|
||||
while (iter.hasNext()) {
|
||||
VectorialValuedPair point = iter.nextSamplePoint();
|
||||
double omegaX = omega * point.getX();
|
||||
double[] pY = point.getY();
|
||||
double cosine = Math.cos(omegaX);
|
||||
double sine = Math.sin(omegaX);
|
||||
fcMean += omega * pY[0] * cosine - pY[1] * sine;
|
||||
fsMean += omega * pY[0] * sine + pY[1] * cosine;
|
||||
}
|
||||
|
||||
phi = Math.atan2(-fsMean, fcMean);
|
||||
|
||||
}
|
||||
|
||||
public double getOmega() {
|
||||
return omega;
|
||||
}
|
||||
|
||||
public double getA() {
|
||||
return a;
|
||||
}
|
||||
|
||||
public double getPhi() {
|
||||
return phi;
|
||||
}
|
||||
|
||||
private AbstractCurveFitter.FitMeasurement[] measurements;
|
||||
private double a;
|
||||
private double omega;
|
||||
private double phi;
|
||||
|
||||
private static final long serialVersionUID = 2400399048702758814L;
|
||||
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.fitting;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.spaceroots.mantissa.estimation.*;
|
||||
import org.spaceroots.mantissa.functions.ExhaustedSampleException;
|
||||
import org.spaceroots.mantissa.functions.FunctionException;
|
||||
|
||||
/** This class implements a curve fitting specialized for sinusoids.
|
||||
|
||||
* <p>Harmonic fitting is a very simple case of curve fitting. The
|
||||
* estimated coefficients are the amplitude a, the pulsation omega and
|
||||
* the phase phi: <code>f (t) = a cos (omega t + phi)</code>. They are
|
||||
* searched by a least square estimator initialized with a rough guess
|
||||
* based on integrals.</p>
|
||||
|
||||
* <p>This class <emph>is by no means optimized</emph>, neither versus
|
||||
* space nor versus time performance.</p>
|
||||
|
||||
* @version $Id: HarmonicFitter.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class HarmonicFitter
|
||||
extends AbstractCurveFitter
|
||||
implements EstimationProblem, Serializable {
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* @param maxIterations maximum number of iterations allowed
|
||||
* @param convergence criterion threshold below which we do not need
|
||||
* to improve the criterion anymore
|
||||
* @param steadyStateThreshold steady state detection threshold, the
|
||||
* problem has reached a steady state (read converged) if
|
||||
* <code>Math.abs (Jn - Jn-1) < Jn * convergence</code>, where
|
||||
* <code>Jn</code> and <code>Jn-1</code> are the current and
|
||||
* preceding criterion value (square sum of the weighted residuals
|
||||
* of considered measurements).
|
||||
* @param epsilon threshold under which the matrix of the linearized
|
||||
* problem is considered singular (see {@link
|
||||
* org.spaceroots.mantissa.linalg.SquareMatrix#solve(
|
||||
* org.spaceroots.mantissa.linalg.Matrix,double) SquareMatrix.solve}).
|
||||
*/
|
||||
public HarmonicFitter(int maxIterations, double convergence,
|
||||
double steadyStateThreshold, double epsilon) {
|
||||
super(3, maxIterations, convergence, steadyStateThreshold, epsilon);
|
||||
coefficients[0] = new EstimatedParameter("a", 2.0 * Math.PI);
|
||||
coefficients[1] = new EstimatedParameter("omega", 0.0);
|
||||
coefficients[2] = new EstimatedParameter("phi", 0.0);
|
||||
firstGuessNeeded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
|
||||
* <p>This constructor can be used when a first estimate of the
|
||||
* coefficients is already known.</p>
|
||||
|
||||
* @param coefficients first estimate of the coefficients.
|
||||
* A reference to this array is hold by the newly created
|
||||
* object. Its elements will be adjusted during the fitting process
|
||||
* and they will be set to the adjusted coefficients at the end.
|
||||
* @param maxIterations maximum number of iterations allowed
|
||||
* @param convergence criterion threshold below which we do not need
|
||||
* to improve the criterion anymore
|
||||
* @param steadyStateThreshold steady state detection threshold, the
|
||||
* problem has reached a steady state (read converged) if
|
||||
* <code>Math.abs (Jn - Jn-1) < Jn * convergence</code>, where
|
||||
* <code>Jn</code> and <code>Jn-1</code> are the current and
|
||||
* preceding criterion value (square sum of the weighted residuals
|
||||
* of considered measurements).
|
||||
* @param epsilon threshold under which the matrix of the linearized
|
||||
* problem is considered singular (see {@link
|
||||
* org.spaceroots.mantissa.linalg.SquareMatrix#solve(
|
||||
* org.spaceroots.mantissa.linalg.Matrix,double) SquareMatrix.solve}).
|
||||
|
||||
*/
|
||||
public HarmonicFitter(EstimatedParameter[] coefficients,
|
||||
int maxIterations, double convergence,
|
||||
double steadyStateThreshold, double epsilon) {
|
||||
super(coefficients,
|
||||
maxIterations, convergence,
|
||||
steadyStateThreshold, epsilon);
|
||||
firstGuessNeeded = false;
|
||||
}
|
||||
|
||||
public double[] fit()
|
||||
throws EstimationException {
|
||||
if (firstGuessNeeded) {
|
||||
if (measurements.size() < 4) {
|
||||
throw new EstimationException("sample must contain at least {0} points",
|
||||
new String[] {
|
||||
Integer.toString(4)
|
||||
});
|
||||
}
|
||||
|
||||
sortMeasurements();
|
||||
|
||||
try {
|
||||
HarmonicCoefficientsGuesser guesser =
|
||||
new HarmonicCoefficientsGuesser((FitMeasurement[]) getMeasurements());
|
||||
guesser.guess();
|
||||
|
||||
coefficients[0].setEstimate(guesser.getA());
|
||||
coefficients[1].setEstimate(guesser.getOmega());
|
||||
coefficients[2].setEstimate(guesser.getPhi());
|
||||
} catch(ExhaustedSampleException e) {
|
||||
throw new EstimationException(e);
|
||||
} catch(FunctionException e) {
|
||||
throw new EstimationException(e);
|
||||
}
|
||||
|
||||
firstGuessNeeded = false;
|
||||
|
||||
}
|
||||
|
||||
return super.fit();
|
||||
|
||||
}
|
||||
|
||||
/** Get the current amplitude coefficient estimate.
|
||||
* Get a, where <code>f (t) = a cos (omega t + phi)</code>
|
||||
* @return current amplitude coefficient estimate
|
||||
*/
|
||||
public double getAmplitude() {
|
||||
return coefficients[0].getEstimate();
|
||||
}
|
||||
|
||||
/** Get the current pulsation coefficient estimate.
|
||||
* Get omega, where <code>f (t) = a cos (omega t + phi)</code>
|
||||
* @return current pulsation coefficient estimate
|
||||
*/
|
||||
public double getPulsation() {
|
||||
return coefficients[1].getEstimate();
|
||||
}
|
||||
|
||||
/** Get the current phase coefficient estimate.
|
||||
* Get phi, where <code>f (t) = a cos (omega t + phi)</code>
|
||||
* @return current phase coefficient estimate
|
||||
*/
|
||||
public double getPhase() {
|
||||
return coefficients[2].getEstimate();
|
||||
}
|
||||
|
||||
/** Get the value of the function at x according to the current parameters value.
|
||||
* @param x abscissa at which the theoretical value is requested
|
||||
* @return theoretical value at x
|
||||
*/
|
||||
public double valueAt(double x) {
|
||||
double a = coefficients[0].getEstimate();
|
||||
double omega = coefficients[1].getEstimate();
|
||||
double phi = coefficients[2].getEstimate();
|
||||
return a * Math.cos(omega * x + phi);
|
||||
}
|
||||
|
||||
/** Get the derivative of the function at x with respect to parameter p.
|
||||
* @param x abscissa at which the partial derivative is requested
|
||||
* @param p parameter with respect to which the derivative is requested
|
||||
* @return partial derivative
|
||||
*/
|
||||
public double partial(double x, EstimatedParameter p) {
|
||||
double a = coefficients[0].getEstimate();
|
||||
double omega = coefficients[1].getEstimate();
|
||||
double phi = coefficients[2].getEstimate();
|
||||
if (p == coefficients[0]) {
|
||||
return Math.cos(omega * x + phi);
|
||||
} else if (p == coefficients[1]) {
|
||||
return -a * x * Math.sin(omega * x + phi);
|
||||
} else {
|
||||
return -a * Math.sin(omega * x + phi);
|
||||
}
|
||||
}
|
||||
|
||||
/** Indicator of the need to compute a first guess of the coefficients. */
|
||||
private boolean firstGuessNeeded;
|
||||
|
||||
private static final long serialVersionUID = -8722683066277473450L;
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.fitting;
|
||||
|
||||
import org.spaceroots.mantissa.estimation.EstimatedParameter;
|
||||
|
||||
/** This class represents a polynomial coefficient.
|
||||
|
||||
* <p>Each coefficient is uniquely defined by its degree.</p>
|
||||
|
||||
* @see PolynomialFitter
|
||||
|
||||
* @version $Id: PolynomialCoefficient.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
public class PolynomialCoefficient
|
||||
extends EstimatedParameter {
|
||||
|
||||
public PolynomialCoefficient(int degree) {
|
||||
super("a" + degree, 0.0);
|
||||
this.degree = degree;
|
||||
}
|
||||
|
||||
public final int degree;
|
||||
|
||||
private static final long serialVersionUID = 5775845068390259552L;
|
||||
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.fitting;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.spaceroots.mantissa.estimation.*;
|
||||
|
||||
/** This class implements a curve fitting specialized for polynomials.
|
||||
|
||||
* <p>Polynomial fitting is a very simple case of curve fitting. The
|
||||
* estimated coefficients are the polynom coefficients. They are
|
||||
* searched by a least square estimator.</p>
|
||||
|
||||
* <p>This class <emph>is by no means optimized</emph>, neither in
|
||||
* space nor in time performance.</p>
|
||||
|
||||
* @see PolynomialCoefficient
|
||||
|
||||
* @version $Id: PolynomialFitter.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class PolynomialFitter
|
||||
extends AbstractCurveFitter
|
||||
implements EstimationProblem, Serializable {
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
|
||||
* <p>The polynomial fitter built this way are complete polynoms,
|
||||
* ie. a n-degree polynom has n+1 coefficients. In order to build
|
||||
* fitter for sparse polynoms (for example <code>a x^20 - b
|
||||
* x^30</code>, on should first build the coefficients array and
|
||||
* provide it to {@link
|
||||
* #PolynomialFitter(PolynomialCoefficient[], int, double, double,
|
||||
* double)}.</p>
|
||||
* @param degree maximal degree of the polynom
|
||||
* @param maxIterations maximum number of iterations allowed
|
||||
* @param convergence criterion threshold below which we do not need
|
||||
* to improve the criterion anymore
|
||||
* @param steadyStateThreshold steady state detection threshold, the
|
||||
* problem has reached a steady state (read converged) if
|
||||
* <code>Math.abs (Jn - Jn-1) < Jn * convergence</code>, where
|
||||
* <code>Jn</code> and <code>Jn-1</code> are the current and
|
||||
* preceding criterion value (square sum of the weighted residuals
|
||||
* of considered measurements).
|
||||
* @param epsilon threshold under which the matrix of the linearized
|
||||
* problem is considered singular (see {@link
|
||||
* org.spaceroots.mantissa.linalg.SquareMatrix#solve(
|
||||
* org.spaceroots.mantissa.linalg.Matrix,double) SquareMatrix.solve}).
|
||||
|
||||
*/
|
||||
public PolynomialFitter(int degree,
|
||||
int maxIterations, double convergence,
|
||||
double steadyStateThreshold, double epsilon) {
|
||||
|
||||
super(degree + 1,
|
||||
maxIterations, steadyStateThreshold,
|
||||
convergence, epsilon);
|
||||
|
||||
for (int i = 0; i < coefficients.length; ++i) {
|
||||
coefficients[i] = new PolynomialCoefficient(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
|
||||
* <p>This constructor can be used either when a first estimate of
|
||||
* the coefficients is already known (which is of little interest
|
||||
* because the fit cost is the same whether a first guess is known or
|
||||
* not) or when one needs to handle sparse polynoms like <code>a
|
||||
* x^20 - b x^30</code>.</p>
|
||||
|
||||
* @param coefficients first estimate of the coefficients.
|
||||
* A reference to this array is hold by the newly created
|
||||
* object. Its elements will be adjusted during the fitting process
|
||||
* and they will be set to the adjusted coefficients at the end.
|
||||
* @param maxIterations maximum number of iterations allowed
|
||||
* @param convergence criterion threshold below which we do not need
|
||||
* to improve the criterion anymore
|
||||
* @param steadyStateThreshold steady state detection threshold, the
|
||||
* problem has reached a steady state (read converged) if
|
||||
* <code>Math.abs (Jn - Jn-1) < Jn * convergence</code>, where
|
||||
* <code>Jn</code> and <code>Jn-1</code> are the current and
|
||||
* preceding criterion value (square sum of the weighted residuals
|
||||
* of considered measurements).
|
||||
* @param epsilon threshold under which the matrix of the linearized
|
||||
* problem is considered singular (see {@link
|
||||
* org.spaceroots.mantissa.linalg.SquareMatrix#solve(
|
||||
* org.spaceroots.mantissa.linalg.Matrix,double) SquareMatrix.solve}).
|
||||
|
||||
*/
|
||||
public PolynomialFitter(PolynomialCoefficient[] coefficients,
|
||||
int maxIterations, double convergence,
|
||||
double steadyStateThreshold, double epsilon) {
|
||||
super(coefficients,
|
||||
maxIterations, steadyStateThreshold,
|
||||
convergence, epsilon);
|
||||
}
|
||||
|
||||
/** Get the value of the function at x according to the current parameters value.
|
||||
* @param x abscissa at which the theoretical value is requested
|
||||
* @return theoretical value at x
|
||||
*/
|
||||
public double valueAt(double x) {
|
||||
double y = coefficients[coefficients.length - 1].getEstimate();
|
||||
for (int i = coefficients.length - 2; i >= 0; --i) {
|
||||
y = y * x + coefficients[i].getEstimate();
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
/** Get the derivative of the function at x with respect to parameter p.
|
||||
* @param x abscissa at which the partial derivative is requested
|
||||
* @param p parameter with respect to which the derivative is requested
|
||||
* @return partial derivative
|
||||
*/
|
||||
public double partial(double x, EstimatedParameter p) {
|
||||
return Math.pow(x, ((PolynomialCoefficient) p).degree);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -226724596015163603L;
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,26 @@
|
|||
<html>
|
||||
<body>
|
||||
This package provides classes to perform curve fitting.
|
||||
|
||||
<p>Curve fitting is a special case of an {@link
|
||||
org.spaceroots.mantissa.estimation.EstimationProblem estimation problem}
|
||||
were the parameters are the coefficients of a function <code>f</code>
|
||||
whose graph <code>y=f(x)</code> should pass through sample points, and
|
||||
were the measurements are the ordinates of the curve
|
||||
<code>yi=f(xi)</code>.</p>
|
||||
|
||||
<p>The organisation of this package is explained in the class diagram
|
||||
below. The {@link org.spaceroots.mantissa.fitting.AbstractCurveFitter
|
||||
AbstractCurveFitter} class is the base class for all curve fitting
|
||||
classes, it handles all common features like sample points
|
||||
handling. Each specific curve fitting class should sub-class this
|
||||
abstract class and implement the {@link
|
||||
org.spaceroots.mantissa.fitting.AbstractCurveFitter#valueAt valueAt} and
|
||||
{@link org.spaceroots.mantissa.fitting.AbstractCurveFitter#partial
|
||||
partial} methods.</p>
|
||||
|
||||
<img src="doc-files/org_spaceroots_mantissa_fitting_classes.png" />
|
||||
|
||||
@author L. Maisonobe
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,42 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.functions;
|
||||
|
||||
import org.spaceroots.mantissa.MantissaException;
|
||||
|
||||
/** This class represents exceptions thrown by sample iterators.
|
||||
|
||||
* @version $Id: ExhaustedSampleException.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class ExhaustedSampleException
|
||||
extends MantissaException {
|
||||
|
||||
/** Simple constructor.
|
||||
* @param size size of the sample
|
||||
*/
|
||||
public ExhaustedSampleException(int size) {
|
||||
super("sample contains only {0} elements",
|
||||
new String[] { Integer.toString(size) });
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -1490493298938282440L;
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.functions;
|
||||
|
||||
import org.spaceroots.mantissa.MantissaException;
|
||||
|
||||
/** This class represents exceptions thrown by scalar functions.
|
||||
|
||||
* @version $Id: FunctionException.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class FunctionException
|
||||
extends MantissaException {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an exception by translating and formating a message
|
||||
* @param specifier format specifier (to be translated)
|
||||
* @param parts to insert in the format (no translation)
|
||||
*/
|
||||
public FunctionException(String specifier, String[] parts) {
|
||||
super(specifier, parts);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an exception by translating the specified message
|
||||
* @param message message to translate
|
||||
*/
|
||||
public FunctionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an exception from a cause
|
||||
* @param cause cause of this exception
|
||||
*/
|
||||
public FunctionException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1455885104381976115L;
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.functions.scalar;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.spaceroots.mantissa.functions.FunctionException;
|
||||
import org.spaceroots.mantissa.functions.ExhaustedSampleException;
|
||||
|
||||
/** This class is a simple wrapper allowing to iterate over a
|
||||
* SampledFunction.
|
||||
|
||||
* <p>The basic implementation of the iteration interface does not
|
||||
* perform any transformation on the sample, it only handles a loop
|
||||
* over the underlying sampled function.</p>
|
||||
|
||||
* @see SampledFunction
|
||||
|
||||
* @version $Id: BasicSampledFunctionIterator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
public class BasicSampledFunctionIterator
|
||||
implements SampledFunctionIterator, Serializable {
|
||||
|
||||
/** Underlying sampled function. */
|
||||
private final SampledFunction function;
|
||||
|
||||
/** Next sample element. */
|
||||
private int next;
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an instance from a SampledFunction
|
||||
* @param function smapled function over which we want to iterate
|
||||
*/
|
||||
public BasicSampledFunctionIterator(SampledFunction function) {
|
||||
this.function = function;
|
||||
next = 0;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return next < function.size();
|
||||
}
|
||||
|
||||
public ScalarValuedPair nextSamplePoint()
|
||||
throws ExhaustedSampleException, FunctionException {
|
||||
if (next >= function.size()) {
|
||||
throw new ExhaustedSampleException(function.size());
|
||||
}
|
||||
|
||||
int current = next++;
|
||||
return function.samplePointAt(current);
|
||||
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -9106690005598356403L;
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.functions.scalar;
|
||||
|
||||
import org.spaceroots.mantissa.functions.FunctionException;
|
||||
|
||||
/** This interface represents scalar functions of one real variable.
|
||||
|
||||
* <p>This interface should be implemented by all scalar functions
|
||||
* that can be evaluated at any point. This does not imply that an
|
||||
* explicit definition is available, a function given by an implicit
|
||||
* function that should be numerically solved for each point for
|
||||
* example is considered a computable function.</p>
|
||||
|
||||
* <p>The {@link ComputableFunctionSampler} class can be used to
|
||||
* transform classes implementing this interface into classes
|
||||
* implementing the {@link SampledFunction} interface.</p>
|
||||
|
||||
* <p>Several numerical algorithms (Gauss-Legendre integrators for
|
||||
* example) need to choose themselves the evaluation points, so they
|
||||
* can handle only objects that implement this interface.</p>
|
||||
|
||||
* @see org.spaceroots.mantissa.quadrature.scalar.ComputableFunctionIntegrator
|
||||
* @see SampledFunction
|
||||
|
||||
* @version $Id: ComputableFunction.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
public interface ComputableFunction {
|
||||
|
||||
/** Get the value of the function at the specified abscissa.
|
||||
* @param x current abscissa
|
||||
* @return function value
|
||||
* @exception FunctionException if something goes wrong
|
||||
*/
|
||||
public double valueAt(double x)
|
||||
throws FunctionException;
|
||||
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.functions.scalar;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.spaceroots.mantissa.functions.FunctionException;
|
||||
|
||||
/** This class is a wrapper allowing to sample a
|
||||
* {@link ComputableFunction}.
|
||||
|
||||
* <p>The sample produced is a regular sample. It can be specified by
|
||||
* several means :
|
||||
* <ul>
|
||||
* <li> from an initial point a step and a number of points</li>
|
||||
* <li> from a range and a number of points</li>
|
||||
* <li> from a range and a step between points.</li>
|
||||
* </ul>
|
||||
* In the latter case, the step can optionaly be adjusted in order to
|
||||
* have the last point exactly at the upper bound of the range.</p>
|
||||
|
||||
* <p>The sample points are computed on demand, they are not
|
||||
* stored. This allow to use this method for very large sample with
|
||||
* little memory overhead. The drawback is that if the same sample
|
||||
* points are going to be requested several times, they will be
|
||||
* recomputed each time. In this case, the user should consider
|
||||
* storing the points by some other means.</p>
|
||||
|
||||
* @see ComputableFunction
|
||||
|
||||
* @version $Id: ComputableFunctionSampler.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
public class ComputableFunctionSampler
|
||||
implements SampledFunction, Serializable {
|
||||
|
||||
/** Underlying computable function. */
|
||||
private ComputableFunction function;
|
||||
|
||||
/** Beginning abscissa. */
|
||||
private double begin;
|
||||
|
||||
/** Step between points. */
|
||||
private double step;
|
||||
|
||||
/** Total number of points. */
|
||||
private int n;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
|
||||
* Build a sample from an {@link ComputableFunction}. Beware of the
|
||||
* classical off-by-one problem ! If you want to have a sample like
|
||||
* this : 0.0, 0.1, 0.2 ..., 1.0, then you should specify step = 0.1
|
||||
* and n = 11 (not n = 10).
|
||||
|
||||
* @param begin beginning of the range (will be the abscissa of the
|
||||
* first point)
|
||||
* @param step step between points
|
||||
* @param n number of points
|
||||
|
||||
*/
|
||||
public ComputableFunctionSampler(ComputableFunction function,
|
||||
double begin, double step, int n) {
|
||||
this.function = function;
|
||||
this.begin = begin;
|
||||
this.step = step;
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Build a sample from an {@link ComputableFunction}.
|
||||
|
||||
* @param range abscissa range (from <code>range [0]</code> to
|
||||
* <code>range [1]</code>)
|
||||
* @param n number of points
|
||||
*/
|
||||
public ComputableFunctionSampler(ComputableFunction function,
|
||||
double[] range, int n) {
|
||||
this.function = function;
|
||||
begin = range[0];
|
||||
step = (range[1] - range[0]) / (n - 1);
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Build a sample from an {@link ComputableFunction}.
|
||||
|
||||
* @param range abscissa range (from <code>range [0]</code> to
|
||||
* <code>range [1]</code>)
|
||||
* @param step step between points
|
||||
* @param adjustStep if true, the step is reduced in order to have
|
||||
* the last point of the sample exactly at <code>range [1]</code>,
|
||||
* if false the last point will be between <code>range [1] -
|
||||
* step</code> and <code>range [1]</code> */
|
||||
public ComputableFunctionSampler(ComputableFunction function,
|
||||
double[] range, double step,
|
||||
boolean adjustStep) {
|
||||
this.function = function;
|
||||
begin = range [0];
|
||||
if (adjustStep) {
|
||||
n = (int) Math.ceil((range[1] - range[0]) / step);
|
||||
this.step = (range[1] - range[0]) / (n - 1);
|
||||
} else {
|
||||
n = (int) Math.floor((range[1] - range[0]) / step);
|
||||
this.step = step;
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return n;
|
||||
}
|
||||
|
||||
public ScalarValuedPair samplePointAt(int index)
|
||||
throws ArrayIndexOutOfBoundsException, FunctionException {
|
||||
|
||||
if (index < 0 || index >= n) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
double x = begin + index * step;
|
||||
return new ScalarValuedPair(x, function.valueAt(x));
|
||||
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -5127043442851795719L;
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.functions.scalar;
|
||||
|
||||
import org.spaceroots.mantissa.functions.FunctionException;
|
||||
|
||||
/** This interface represent sampled scalar functions.
|
||||
|
||||
* <p>A function sample is an ordered set of points of the form (x, y)
|
||||
* where x is the abscissa of the point and y is the function value at
|
||||
* x. It is typically a function that has been computed by external
|
||||
* means or the result of measurements.</p>
|
||||
|
||||
* <p>The {@link ComputableFunctionSampler} class can be used to
|
||||
* transform classes implementing the {@link ComputableFunction}
|
||||
* interface into classes implementing this interface.</p>
|
||||
|
||||
* <p>Sampled functions cannot be directly handled by integrators
|
||||
* implementing the {@link
|
||||
* org.spaceroots.mantissa.quadrature.scalar.SampledFunctionIntegrator
|
||||
* SampledFunctionIntegrator}. These integrators need a {@link
|
||||
* SampledFunctionIterator} object to iterate over the
|
||||
* sample.</p>
|
||||
|
||||
* @see SampledFunctionIterator
|
||||
* @see ComputableFunctionSampler
|
||||
* @see ComputableFunction
|
||||
|
||||
* @version $Id: SampledFunction.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
public interface SampledFunction {
|
||||
|
||||
/** Get the number of points in the sample.
|
||||
* @return number of points in the sample
|
||||
*/
|
||||
public int size();
|
||||
|
||||
/** Get the abscissa and value of the sample at the specified index.
|
||||
* @param index index in the sample, should be between 0 and
|
||||
* {@link #size} - 1
|
||||
* @return abscissa and value of the sample at the specified index
|
||||
* @exception ArrayIndexOutOfBoundsException if the index is wrong
|
||||
* @exception FunctionException if an eventual underlying function
|
||||
* throws one
|
||||
*/
|
||||
public ScalarValuedPair samplePointAt(int index)
|
||||
throws ArrayIndexOutOfBoundsException, FunctionException;
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.functions.scalar;
|
||||
|
||||
import org.spaceroots.mantissa.functions.FunctionException;
|
||||
import org.spaceroots.mantissa.functions.ExhaustedSampleException;
|
||||
|
||||
/** This interface provides iteration services over scalar functions
|
||||
* samples.
|
||||
|
||||
* @see SampledFunction
|
||||
|
||||
* @version $Id: SampledFunctionIterator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
public interface SampledFunctionIterator {
|
||||
|
||||
/** Check if the iterator can provide another point.
|
||||
* @return true if the iterator can provide another point.
|
||||
*/
|
||||
public boolean hasNext();
|
||||
|
||||
/** Get the next point of a sampled function.
|
||||
* @return the next point of the sampled function
|
||||
* @exception ExhaustedSampleException if the sample has been exhausted
|
||||
* @exception FunctionException if the underlying function throws one
|
||||
*/
|
||||
public ScalarValuedPair nextSamplePoint()
|
||||
throws ExhaustedSampleException, FunctionException;
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.functions.scalar;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** This class represents an (x, f(x)) pair for scalar functions.
|
||||
|
||||
* <p>A scalar function is a function of one scalar parameter x whose
|
||||
* value is a scalar. This class is used has a simple placeholder to
|
||||
* contain both an abscissa and the value of the function at this
|
||||
* abscissa.</p>
|
||||
|
||||
* @see SampledFunction
|
||||
* @see org.spaceroots.mantissa.functions.vectorial.VectorialValuedPair
|
||||
|
||||
* @version $Id: ScalarValuedPair.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
public class ScalarValuedPair
|
||||
implements Serializable {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an instance from its coordinates
|
||||
* @param x abscissa
|
||||
* @param y ordinate (value of the function)
|
||||
*/
|
||||
public ScalarValuedPair(double x, double y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/** Copy-constructor.
|
||||
* @param p point to copy
|
||||
*/
|
||||
public ScalarValuedPair(ScalarValuedPair p) {
|
||||
x = p.x;
|
||||
y = p.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for the abscissa.
|
||||
* @return value of the abscissa
|
||||
*/
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for the ordinate.
|
||||
* @return value of the ordinate
|
||||
*/
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the abscissa.
|
||||
* @param x new value for the abscissa
|
||||
*/
|
||||
public void setX(double x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the ordinate.
|
||||
* @param y new value for the ordinate
|
||||
*/
|
||||
public void setY(double y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/** Abscissa of the point. */
|
||||
private double x;
|
||||
|
||||
/** Scalar ordinate of the point, y = f (x). */
|
||||
private double y;
|
||||
|
||||
private static final long serialVersionUID = 1884346552569300794L;
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.functions.vectorial;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.spaceroots.mantissa.functions.FunctionException;
|
||||
import org.spaceroots.mantissa.functions.ExhaustedSampleException;
|
||||
|
||||
/** This class is a wrapper allowing to iterate over a
|
||||
* SampledFunction.
|
||||
|
||||
* <p>The basic implementation of the iteration interface does not
|
||||
* perform any transformation on the sample, it only handles a loop
|
||||
* over the underlying sampled function.</p>
|
||||
|
||||
* @see SampledFunction
|
||||
|
||||
* @version $Id: BasicSampledFunctionIterator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
public class BasicSampledFunctionIterator
|
||||
implements SampledFunctionIterator, Serializable {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an instance from a SampledFunction
|
||||
* @param function smapled function over which we want to iterate
|
||||
*/
|
||||
public BasicSampledFunctionIterator(SampledFunction function) {
|
||||
this.function = function;
|
||||
next = 0;
|
||||
}
|
||||
|
||||
public int getDimension() {
|
||||
return function.getDimension();
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return next < function.size();
|
||||
}
|
||||
|
||||
public VectorialValuedPair nextSamplePoint()
|
||||
throws ExhaustedSampleException, FunctionException {
|
||||
|
||||
if (next >= function.size()) {
|
||||
throw new ExhaustedSampleException(function.size());
|
||||
}
|
||||
|
||||
int current = next++;
|
||||
return function.samplePointAt(current);
|
||||
|
||||
}
|
||||
|
||||
/** Underlying sampled function. */
|
||||
private final SampledFunction function;
|
||||
|
||||
/** Next sample element. */
|
||||
private int next;
|
||||
|
||||
private static final long serialVersionUID = -4386278658288500627L;
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.functions.vectorial;
|
||||
|
||||
import org.spaceroots.mantissa.functions.FunctionException;
|
||||
|
||||
/** This interface represents vectorial functions of one real variable.
|
||||
|
||||
* <p>This interface should be implemented by all vectorial functions
|
||||
* that can be evaluated at any point. This does not imply that an
|
||||
* explicit definition is available, a function given by an implicit
|
||||
* function that should be numerically solved for each point for
|
||||
* example is considered a computable function.</p>
|
||||
|
||||
* <p>The {@link ComputableFunctionSampler} class can be used to
|
||||
* transform classes implementing this interface into classes
|
||||
* implementing the {@link SampledFunction} interface.</p>
|
||||
|
||||
* <p>Several numerical algorithms (Gauss-Legendre integrators for
|
||||
* example) need to choose themselves the evaluation points, so they
|
||||
* can handle only objects that implement this interface.</p>
|
||||
|
||||
* @see org.spaceroots.mantissa.quadrature.vectorial.ComputableFunctionIntegrator
|
||||
* @see SampledFunction
|
||||
|
||||
* @version $Id: ComputableFunction.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
public interface ComputableFunction {
|
||||
/** Get the dimension of the vectorial values of the function.
|
||||
* @return dimension
|
||||
*/
|
||||
public int getDimension();
|
||||
|
||||
/** Get the value of the function at the specified abscissa.
|
||||
* @param x current abscissa
|
||||
* @return function value
|
||||
* @exception FunctionException if something goes wrong
|
||||
*/
|
||||
public double[] valueAt(double x)
|
||||
throws FunctionException;
|
||||
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.functions.vectorial;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.spaceroots.mantissa.functions.FunctionException;
|
||||
|
||||
/** This class is a wrapper allowing to sample a
|
||||
* {@link ComputableFunction}.
|
||||
|
||||
* <p>The sample produced is a regular sample. It can be specified by
|
||||
* several means :
|
||||
* <ul>
|
||||
* <li> from an initial point a step and a number of points</li>
|
||||
* <li> from a range and a number of points</li>
|
||||
* <li> from a range and a step between points.</li>
|
||||
* </ul>
|
||||
* In the latter case, the step can optionaly be adjusted in order to
|
||||
* have the last point exactly at the upper bound of the range.</p>
|
||||
|
||||
* <p>The sample points are computed on demand, they are not
|
||||
* stored. This allow to use this method for very large sample with
|
||||
* little memory overhead. The drawback is that if the same sample
|
||||
* points are going to be requested several times, they will be
|
||||
* recomputed each time. In this case, the user should consider
|
||||
* storing the points by some other means.</p>
|
||||
|
||||
* @see ComputableFunction
|
||||
|
||||
* @version $Id: ComputableFunctionSampler.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
public class ComputableFunctionSampler
|
||||
implements SampledFunction, Serializable {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
|
||||
* Build a sample from an {@link ComputableFunction}. Beware of the
|
||||
* classical off-by-one problem ! If you want to have a sample like
|
||||
* this : 0.0, 0.1, 0.2 ..., 1.0, then you should specify step = 0.1
|
||||
* and n = 11 (not n = 10).
|
||||
|
||||
* @param begin beginning of the range (will be the abscissa of the
|
||||
* first point)
|
||||
* @param step step between points
|
||||
* @param n number of points
|
||||
|
||||
*/
|
||||
public ComputableFunctionSampler(ComputableFunction function,
|
||||
double begin, double step, int n) {
|
||||
this.function = function;
|
||||
this.begin = begin;
|
||||
this.step = step;
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Build a sample from an {@link ComputableFunction}.
|
||||
|
||||
* @param range abscissa range (from <code>range [0]</code> to
|
||||
* <code>range [1]</code>)
|
||||
* @param n number of points
|
||||
*/
|
||||
public ComputableFunctionSampler(ComputableFunction function,
|
||||
double[] range, int n) {
|
||||
this.function = function;
|
||||
begin = range[0];
|
||||
step = (range[1] - range[0]) / (n - 1);
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Build a sample from an {@link ComputableFunction}.
|
||||
|
||||
* @param range abscissa range (from <code>range [0]</code> to
|
||||
* <code>range [1]</code>)
|
||||
* @param step step between points
|
||||
* @param adjustStep if true, the step is reduced in order to have
|
||||
* the last point of the sample exactly at <code>range [1]</code>,
|
||||
* if false the last point will be between <code>range [1] -
|
||||
* step</code> and <code>range [1]</code> */
|
||||
public ComputableFunctionSampler(ComputableFunction function,
|
||||
double[] range, double step,
|
||||
boolean adjustStep) {
|
||||
this.function = function;
|
||||
begin = range[0];
|
||||
if (adjustStep) {
|
||||
n = (int) Math.ceil((range[1] - range[0]) / step);
|
||||
this.step = (range[1] - range[0]) / (n - 1);
|
||||
} else {
|
||||
n = (int) Math.floor((range[1] - range[0]) / step);
|
||||
this.step = step;
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return n;
|
||||
}
|
||||
|
||||
public int getDimension() {
|
||||
return function.getDimension();
|
||||
}
|
||||
|
||||
public VectorialValuedPair samplePointAt(int index)
|
||||
throws ArrayIndexOutOfBoundsException, FunctionException {
|
||||
|
||||
if (index < 0 || index >= n) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
double x = begin + index * step;
|
||||
return new VectorialValuedPair (x, function.valueAt(x));
|
||||
|
||||
}
|
||||
|
||||
/** Underlying computable function. */
|
||||
private ComputableFunction function;
|
||||
|
||||
/** Beginning abscissa. */
|
||||
private double begin;
|
||||
|
||||
/** Step between points. */
|
||||
private double step;
|
||||
|
||||
/** Total number of points. */
|
||||
private int n;
|
||||
|
||||
private static final long serialVersionUID = 1368582688313212821L;
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.functions.vectorial;
|
||||
|
||||
import org.spaceroots.mantissa.functions.FunctionException;
|
||||
|
||||
/** This interface represent sampled vectorial functions.
|
||||
|
||||
* <p>A function sample is an ordered set of points of the form (x, y)
|
||||
* where x is the abscissa of the point and y is the function value at
|
||||
* x. It is typically a function that has been computed by external
|
||||
* means or the result of measurements.</p>
|
||||
|
||||
* <p>The {@link ComputableFunctionSampler} class can be used to
|
||||
* transform classes implementing the {@link ComputableFunction}
|
||||
* interface into classes implementing this interface.</p>
|
||||
|
||||
* <p>Sampled functions cannot be directly handled by integrators
|
||||
* implementing the {@link
|
||||
* org.spaceroots.mantissa.quadrature.vectorial.SampledFunctionIntegrator
|
||||
* SampledFunctionIntegrator}. These integrators need a {@link
|
||||
* SampledFunctionIterator} object to iterate over the
|
||||
* sample.</p>
|
||||
|
||||
* @see SampledFunctionIterator
|
||||
* @see ComputableFunctionSampler
|
||||
* @see ComputableFunction
|
||||
|
||||
* @version $Id: SampledFunction.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
public interface SampledFunction {
|
||||
|
||||
/** Get the number of points in the sample.
|
||||
* @return number of points in the sample
|
||||
*/
|
||||
public int size();
|
||||
|
||||
/** Get the dimension of the vectorial values of the function.
|
||||
* @return dimension
|
||||
*/
|
||||
public int getDimension();
|
||||
|
||||
/** Get the abscissa and value of the sample at the specified index.
|
||||
* @param index index in the sample, should be between 0 and
|
||||
* {@link #size} - 1
|
||||
* @return abscissa and value of the sample at the specified index
|
||||
* @exception ArrayIndexOutOfBoundsException if the index is wrong
|
||||
* @exception FunctionException if an eventual underlying function
|
||||
* throws one
|
||||
*/
|
||||
public VectorialValuedPair samplePointAt(int index)
|
||||
throws ArrayIndexOutOfBoundsException, FunctionException;
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.functions.vectorial;
|
||||
|
||||
import org.spaceroots.mantissa.functions.FunctionException;
|
||||
import org.spaceroots.mantissa.functions.ExhaustedSampleException;
|
||||
|
||||
/** This interface provides iteration services over vectorial functions
|
||||
* samples.
|
||||
|
||||
* @see SampledFunction
|
||||
|
||||
* @version $Id: SampledFunctionIterator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
public interface SampledFunctionIterator {
|
||||
|
||||
/** Get the dimension of the vectorial values of the function.
|
||||
* @return dimension
|
||||
*/
|
||||
public int getDimension();
|
||||
|
||||
/** Check if the iterator can provide another point.
|
||||
* @return true if the iterator can provide another point.
|
||||
*/
|
||||
public boolean hasNext();
|
||||
|
||||
/** Get the next point of a sampled function.
|
||||
* @return the next point of the sampled function
|
||||
* @exception ExhaustedSampleException if the sample has been exhausted
|
||||
* @exception FunctionException if the underlying function throws one
|
||||
*/
|
||||
public VectorialValuedPair nextSamplePoint()
|
||||
throws ExhaustedSampleException, FunctionException;
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.functions.vectorial;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** This class represents an (x, f(x)) pair for vectorial functions.
|
||||
|
||||
* <p>A vectorial function is a function of one vectorial parameter x whose
|
||||
* value is a vector. This class is used has a simple placeholder to
|
||||
* contain both an abscissa and the value of the function at this
|
||||
* abscissa.</p>
|
||||
|
||||
* @see SampledFunction
|
||||
* @see org.spaceroots.mantissa.functions.vectorial.VectorialValuedPair
|
||||
|
||||
* @version $Id: VectorialValuedPair.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
public class VectorialValuedPair
|
||||
implements Serializable {
|
||||
|
||||
/**
|
||||
* Simple constructor.
|
||||
* Build an instance from its coordinates
|
||||
* @param x abscissa
|
||||
* @param y ordinate (value of the function)
|
||||
*/
|
||||
public VectorialValuedPair(double x, double[] y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy-constructor.
|
||||
* @param p point to copy
|
||||
*/
|
||||
public VectorialValuedPair(VectorialValuedPair p) {
|
||||
x = p.x;
|
||||
y = p.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for the abscissa.
|
||||
* @return value of the abscissa
|
||||
*/
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for the ordinate.
|
||||
* @return value of the ordinate
|
||||
*/
|
||||
public double[] getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the abscissa.
|
||||
* @param x new value for the abscissa
|
||||
*/
|
||||
public void setX(double x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the ordinate.
|
||||
* @param y new value for the ordinate
|
||||
*/
|
||||
public void setY(double[] y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/** Abscissa of the point. */
|
||||
private double x;
|
||||
|
||||
/** Vectorial ordinate of the point, y = f (x). */
|
||||
private double[] y;
|
||||
|
||||
private static final long serialVersionUID = -1336411215846160578L;
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.geometry;
|
||||
|
||||
import org.spaceroots.mantissa.MantissaException;
|
||||
|
||||
/** This class represents exceptions thrown while extractiong Cardan
|
||||
* or Euler angles from a rotation.
|
||||
|
||||
* @version $Id: CardanEulerSingularityException.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class CardanEulerSingularityException
|
||||
extends MantissaException {
|
||||
|
||||
/** Simple constructor.
|
||||
* build an exception with a default message.
|
||||
* @param isCardan if true, the rotation is related to Cardan angles,
|
||||
* if false it is related to EulerAngles
|
||||
*/
|
||||
public CardanEulerSingularityException(boolean isCardan) {
|
||||
super(isCardan ? "Cardan angles singularity" : "Euler angles singularity");
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -1360952845582206770L;
|
||||
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.geometry;
|
||||
|
||||
/**
|
||||
* This class implements immutable vectors in a three-dimensional space.
|
||||
|
||||
* @version $Id: ImmutableVector3D.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class ImmutableVector3D
|
||||
extends Vector3D {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a vector from its coordinates
|
||||
* @param x abscissa
|
||||
* @param y ordinate
|
||||
* @param z height
|
||||
*/
|
||||
public ImmutableVector3D(double x, double y, double z) {
|
||||
super(x, y, z);
|
||||
computeNorm();
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a vector from its azimuthal coordinates
|
||||
* @param alpha azimuth around Z
|
||||
* (0 is +X, PI/2 is +Y, PI is -X and 3PI/2 is -Y)
|
||||
* @param delta elevation above (XY) plane, from -PI to +PI
|
||||
*/
|
||||
public ImmutableVector3D(double alpha, double delta) {
|
||||
super(alpha, delta);
|
||||
computeNorm();
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* Build a copy of a vector
|
||||
* @param v vector to copy
|
||||
*/
|
||||
public ImmutableVector3D(Vector3D v) {
|
||||
super(v);
|
||||
computeNorm();
|
||||
}
|
||||
|
||||
/** Multiplicative constructor
|
||||
* Build a vector from another one and a scale factor.
|
||||
* The vector built will be a * u
|
||||
* @param a scale factor
|
||||
* @param u base (unscaled) vector
|
||||
*/
|
||||
public ImmutableVector3D(double a, Vector3D u) {
|
||||
super(a, u);
|
||||
computeNorm();
|
||||
}
|
||||
|
||||
/** Linear constructor
|
||||
* Build a vector from two other ones and corresponding scale factors.
|
||||
* The vector built will be a * u + b * v
|
||||
* @param a first scale factor
|
||||
* @param u first base (unscaled) vector
|
||||
* @param b second scale factor
|
||||
* @param v second base (unscaled) vector
|
||||
*/
|
||||
public ImmutableVector3D(double a, Vector3D u, double b, Vector3D v) {
|
||||
super(a, u, b, v);
|
||||
computeNorm();
|
||||
}
|
||||
|
||||
/** Set the abscissa of the vector.
|
||||
* This method should not be called for immutable vectors, it always
|
||||
* throws an <code>UnsupportedOperationException</code> exception
|
||||
* @param x new abscissa for the vector
|
||||
* @exception UnsupportedOperationException thrown in every case
|
||||
*/
|
||||
public void setX(double x) {
|
||||
throw new UnsupportedOperationException("vector is immutable");
|
||||
}
|
||||
|
||||
/** Set the ordinate of the vector.
|
||||
* This method should not be called for immutable vectors, it always
|
||||
* throws an <code>UnsupportedOperationException</code> exception
|
||||
* @param y new ordinate for the vector
|
||||
* @exception UnsupportedOperationException thrown in every case
|
||||
*/
|
||||
public void setY(double y) {
|
||||
throw new UnsupportedOperationException("vector is immutable");
|
||||
}
|
||||
|
||||
/** Set the height of the vector.
|
||||
* This method should not be called for immutable vectors, it always
|
||||
* throws an <code>UnsupportedOperationException</code> exception
|
||||
* @param z new height for the vector
|
||||
* @exception UnsupportedOperationException thrown in every case
|
||||
*/
|
||||
public void setZ(double z) {
|
||||
throw new UnsupportedOperationException("vector is immutable");
|
||||
}
|
||||
|
||||
/** Set all coordinates of the vector.
|
||||
* This method should not be called for immutable vectors, it always
|
||||
* throws an <code>UnsupportedOperationException</code> exception
|
||||
* @param x new abscissa for the vector
|
||||
* @param y new ordinate for the vector
|
||||
* @param z new height for the vector
|
||||
* @exception UnsupportedOperationException thrown in every case
|
||||
*/
|
||||
public void setCoordinates(double x, double y, double z) {
|
||||
throw new UnsupportedOperationException("vector is immutable");
|
||||
}
|
||||
|
||||
/** Compute the norm once and for all. */
|
||||
private void computeNorm() {
|
||||
norm = Math.sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
/** Get the norm for the vector.
|
||||
* @return euclidian norm for the vector
|
||||
*/
|
||||
public double getNorm() {
|
||||
return norm;
|
||||
}
|
||||
|
||||
/** Add a vector to the instance.
|
||||
* This method should not be called for immutable vectors, it always
|
||||
* throws an <code>UnsupportedOperationException</code> exception
|
||||
* @param v vector to add
|
||||
* @exception UnsupportedOperationException thrown in every case
|
||||
*/
|
||||
public void addToSelf(Vector3D v) {
|
||||
throw new UnsupportedOperationException("vector is immutable");
|
||||
}
|
||||
|
||||
/** Subtract a vector from the instance.
|
||||
* This method should not be called for immutable vectors, it always
|
||||
* throws an <code>UnsupportedOperationException</code> exception
|
||||
* @param v vector to subtract
|
||||
* @exception UnsupportedOperationException thrown in every case
|
||||
*/
|
||||
public void subtractFromSelf(Vector3D v) {
|
||||
throw new UnsupportedOperationException("vector is immutable");
|
||||
}
|
||||
|
||||
/** Normalize the instance.
|
||||
* This method should not be called for immutable vectors, it always
|
||||
* throws an <code>UnsupportedOperationException</code> exception
|
||||
* @exception UnsupportedOperationException thrown in every case
|
||||
*/
|
||||
public void normalizeSelf() {
|
||||
throw new UnsupportedOperationException("vector is immutable");
|
||||
}
|
||||
|
||||
/** Revert the instance.
|
||||
* This method should not be called for immutable vectors, it always
|
||||
* throws an <code>UnsupportedOperationException</code> exception
|
||||
* @exception UnsupportedOperationException thrown in every case
|
||||
*/
|
||||
public void negateSelf() {
|
||||
throw new UnsupportedOperationException("vector is immutable");
|
||||
}
|
||||
|
||||
/** Multiply the instance by a scalar
|
||||
* This method should not be called for immutable vectors, it always
|
||||
* throws an <code>UnsupportedOperationException</code> exception
|
||||
* @param a scalar by which the instance should be multiplied
|
||||
* @exception UnsupportedOperationException thrown in every case
|
||||
*/
|
||||
public void multiplySelf(double a) {
|
||||
throw new UnsupportedOperationException("vector is immutable");
|
||||
}
|
||||
|
||||
/** Reinitialize internal state from the specified array slice data.
|
||||
* This method should not be called for immutable vectors, it always
|
||||
* throws an <code>UnsupportedOperationException</code> exception
|
||||
* @param start start index in the array
|
||||
* @param array array holding the data to extract
|
||||
* @exception UnsupportedOperationException thrown in every case
|
||||
*/
|
||||
public void mapStateFromArray(int start, double[] array) {
|
||||
throw new UnsupportedOperationException("vector is immutable");
|
||||
}
|
||||
|
||||
/** Norm of the vector. */
|
||||
private double norm;
|
||||
|
||||
private static final long serialVersionUID = 5377895850033895270L;
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.geometry;
|
||||
|
||||
import org.spaceroots.mantissa.MantissaException;
|
||||
|
||||
/** This class represents exceptions thrown while building rotations
|
||||
* from matrices.
|
||||
|
||||
* @version $Id: NotARotationMatrixException.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class NotARotationMatrixException
|
||||
extends MantissaException {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an exception by translating and formating a message
|
||||
* @param specifier format specifier (to be translated)
|
||||
* @param parts to insert in the format (no translation)
|
||||
*/
|
||||
public NotARotationMatrixException(String specifier, String[] parts) {
|
||||
super(specifier, parts);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 5647178478658937642L;
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,126 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.geometry;
|
||||
|
||||
/**
|
||||
* This class is a utility representing a rotation order specification
|
||||
* for Cardan or Euler angles specification.
|
||||
|
||||
* This class cannot be instanciated by the user. He can only use one
|
||||
* of the twelve predefined supported orders as an argument to either
|
||||
* the {@link Rotation#Rotation(RotationOrder,double,double,double)}
|
||||
* constructor or the {@link Rotation#getAngles} method.
|
||||
|
||||
* @version $Id: RotationOrder.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
public final class RotationOrder {
|
||||
|
||||
/** Private constructor.
|
||||
* This is a utility class that cannot be instantiated by the user,
|
||||
* so its only constructor is private.
|
||||
* @param name name of the rotation order
|
||||
*/
|
||||
private RotationOrder(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/** Get a string representation of the instance.
|
||||
* @return a string representation of the instance (in fact, its name)
|
||||
*/
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/** Set of Cardan angles.
|
||||
* this ordered set of rotations is around X, then around Y, then
|
||||
* around Z
|
||||
*/
|
||||
public static final RotationOrder XYZ = new RotationOrder("XYZ");
|
||||
|
||||
/** Set of Cardan angles.
|
||||
* this ordered set of rotations is around X, then around Z, then
|
||||
* around Y
|
||||
*/
|
||||
public static final RotationOrder XZY = new RotationOrder("XZY");
|
||||
|
||||
/** Set of Cardan angles.
|
||||
* this ordered set of rotations is around Y, then around X, then
|
||||
* around Z
|
||||
*/
|
||||
public static final RotationOrder YXZ = new RotationOrder("YXZ");
|
||||
|
||||
/** Set of Cardan angles.
|
||||
* this ordered set of rotations is around Y, then around Z, then
|
||||
* around X
|
||||
*/
|
||||
public static final RotationOrder YZX = new RotationOrder("YZX");
|
||||
|
||||
/** Set of Cardan angles.
|
||||
* this ordered set of rotations is around Z, then around X, then
|
||||
* around Y
|
||||
*/
|
||||
public static final RotationOrder ZXY = new RotationOrder("ZXY");
|
||||
|
||||
/** Set of Cardan angles.
|
||||
* this ordered set of rotations is around Z, then around Y, then
|
||||
* around X
|
||||
*/
|
||||
public static final RotationOrder ZYX = new RotationOrder("ZYX");
|
||||
|
||||
/** Set of Euler angles.
|
||||
* this ordered set of rotations is around X, then around Y, then
|
||||
* around X
|
||||
*/
|
||||
public static final RotationOrder XYX = new RotationOrder("XYX");
|
||||
|
||||
/** Set of Euler angles.
|
||||
* this ordered set of rotations is around X, then around Z, then
|
||||
* around X
|
||||
*/
|
||||
public static final RotationOrder XZX = new RotationOrder("XZX");
|
||||
|
||||
/** Set of Euler angles.
|
||||
* this ordered set of rotations is around Y, then around X, then
|
||||
* around Y
|
||||
*/
|
||||
public static final RotationOrder YXY = new RotationOrder("YXY");
|
||||
|
||||
/** Set of Euler angles.
|
||||
* this ordered set of rotations is around Y, then around Z, then
|
||||
* around Y
|
||||
*/
|
||||
public static final RotationOrder YZY = new RotationOrder("YZY");
|
||||
|
||||
/** Set of Euler angles.
|
||||
* this ordered set of rotations is around Z, then around X, then
|
||||
* around Z
|
||||
*/
|
||||
public static final RotationOrder ZXZ = new RotationOrder("ZXZ");
|
||||
|
||||
/** Set of Euler angles.
|
||||
* this ordered set of rotations is around Z, then around Y, then
|
||||
* around Z
|
||||
*/
|
||||
public static final RotationOrder ZYZ = new RotationOrder("ZYZ");
|
||||
|
||||
/** Name of the rotations order. */
|
||||
private final String name;
|
||||
|
||||
}
|
|
@ -0,0 +1,491 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.geometry;
|
||||
|
||||
import java.io.Serializable;
|
||||
import org.spaceroots.mantissa.utilities.ArraySliceMappable;
|
||||
|
||||
|
||||
/** This class implements vectors in a three-dimensional space.
|
||||
* @version $Id: Vector3D.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
*/
|
||||
|
||||
public class Vector3D
|
||||
implements ArraySliceMappable, Serializable {
|
||||
|
||||
/** First canonical vector (coordinates : 1, 0, 0).
|
||||
* This is really an {@link ImmutableVector3D ImmutableVector3D},
|
||||
* hence it can't be changed in any way.
|
||||
*/
|
||||
public static final Vector3D plusI = new ImmutableVector3D(1, 0, 0);
|
||||
|
||||
/** Opposite of the first canonical vector (coordinates : -1, 0, 0).
|
||||
* This is really an {@link ImmutableVector3D ImmutableVector3D},
|
||||
* hence it can't be changed in any way.
|
||||
*/
|
||||
public static final Vector3D minusI = new ImmutableVector3D(-1, 0, 0);
|
||||
|
||||
/** Second canonical vector (coordinates : 0, 1, 0).
|
||||
* This is really an {@link ImmutableVector3D ImmutableVector3D},
|
||||
* hence it can't be changed in any way.
|
||||
*/
|
||||
public static final Vector3D plusJ = new ImmutableVector3D(0, 1, 0);
|
||||
|
||||
/** Opposite of the second canonical vector (coordinates : 0, -1, 0).
|
||||
* This is really an {@link ImmutableVector3D ImmutableVector3D},
|
||||
* hence it can't be changed in any way.
|
||||
*/
|
||||
public static final Vector3D minusJ = new ImmutableVector3D(0, -1, 0);
|
||||
|
||||
/** Third canonical vector (coordinates : 0, 0, 1).
|
||||
* This is really an {@link ImmutableVector3D ImmutableVector3D},
|
||||
* hence it can't be changed in any way.
|
||||
*/
|
||||
public static final Vector3D plusK = new ImmutableVector3D(0, 0, 1);
|
||||
|
||||
/** Opposite of the third canonical vector (coordinates : 0, 0, -1).
|
||||
* This is really an {@link ImmutableVector3D ImmutableVector3D},
|
||||
* hence it can't be changed in any way.
|
||||
*/
|
||||
public static final Vector3D minusK = new ImmutableVector3D(0, 0, -1);
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a null vector.
|
||||
*/
|
||||
public Vector3D() {
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a vector from its coordinates
|
||||
* @param x abscissa
|
||||
* @param y ordinate
|
||||
* @param z height
|
||||
* @see #getX()
|
||||
* @see #getY()
|
||||
* @see #getZ()
|
||||
*/
|
||||
public Vector3D(double x, double y, double z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a vector from its azimuthal coordinates
|
||||
* @param alpha azimuth (α) around Z
|
||||
* (0 is +X, π/2 is +Y, π is -X and 3π/2 is -Y)
|
||||
* @param delta elevation (δ) above (XY) plane, from -π/2 to +π/2
|
||||
* @see #getAlpha()
|
||||
* @see #getDelta()
|
||||
*/
|
||||
public Vector3D(double alpha, double delta) {
|
||||
double cosDelta = Math.cos(delta);
|
||||
this.x = Math.cos(alpha) * cosDelta;
|
||||
this.y = Math.sin(alpha) * cosDelta;
|
||||
this.z = Math.sin(delta);
|
||||
}
|
||||
|
||||
/** Multiplicative constructor
|
||||
* Build a vector from another one and a scale factor.
|
||||
* The vector built will be a * u
|
||||
* @param a scale factor
|
||||
* @param u base (unscaled) vector
|
||||
*/
|
||||
public Vector3D(double a, Vector3D u) {
|
||||
this.x = a * u.x;
|
||||
this.y = a * u.y;
|
||||
this.z = a * u.z;
|
||||
}
|
||||
|
||||
/** Linear constructor
|
||||
* Build a vector from two other ones and corresponding scale factors.
|
||||
* The vector built will be a * u + b * v
|
||||
* @param a first scale factor
|
||||
* @param u first base (unscaled) vector
|
||||
* @param b second scale factor
|
||||
* @param v second base (unscaled) vector
|
||||
*/
|
||||
public Vector3D(double a, Vector3D u, double b, Vector3D v) {
|
||||
this.x = a * u.x + b * v.x;
|
||||
this.y = a * u.y + b * v.y;
|
||||
this.z = a * u.z + b * v.z;
|
||||
}
|
||||
|
||||
/** Linear constructor
|
||||
* Build a vector from three other ones and corresponding scale factors.
|
||||
* The vector built will be a * u + b * v + c * w
|
||||
* @param a first scale factor
|
||||
* @param u first base (unscaled) vector
|
||||
* @param b second scale factor
|
||||
* @param v second base (unscaled) vector
|
||||
* @param c third scale factor
|
||||
* @param w third base (unscaled) vector
|
||||
*/
|
||||
public Vector3D(double a, Vector3D u,
|
||||
double b, Vector3D v,
|
||||
double c, Vector3D w) {
|
||||
this.x = a * u.x + b * v.x + c * w.x;
|
||||
this.y = a * u.y + b * v.y + c * w.y;
|
||||
this.z = a * u.z + b * v.z + c * w.z;
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* Build a copy of a vector
|
||||
* @param v vector to copy
|
||||
*/
|
||||
public Vector3D(Vector3D v) {
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
}
|
||||
|
||||
/** Reset the instance.
|
||||
* @param v vector to copy data from
|
||||
*/
|
||||
public void reset(Vector3D v) {
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
}
|
||||
|
||||
/** Get the abscissa of the vector.
|
||||
* @return abscissa of the vector
|
||||
* @see #Vector3D(double, double, double)
|
||||
* @see #setX(double)
|
||||
*/
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/** Set the abscissa of the vector.
|
||||
* @param x new abscissa for the vector
|
||||
* @see #getX()
|
||||
* @see #setCoordinates(double, double, double)
|
||||
*/
|
||||
public void setX(double x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
/** Get the ordinate of the vector.
|
||||
* @return ordinate of the vector
|
||||
* @see #Vector3D(double, double, double)
|
||||
* @see #setY(double)
|
||||
*/
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/** Set the ordinate of the vector.
|
||||
* @param y new ordinate for the vector
|
||||
* @see #getY()
|
||||
* @see #setCoordinates(double, double, double)
|
||||
*/
|
||||
public void setY(double y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/** Get the height of the vector.
|
||||
* @return height of the vector
|
||||
* @see #Vector3D(double, double, double)
|
||||
* @see #setZ(double)
|
||||
*/
|
||||
public double getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
/** Set the height of the vector.
|
||||
* @param z new height for the vector
|
||||
* @see #getZ()
|
||||
* @see #setCoordinates(double, double, double)
|
||||
*/
|
||||
public void setZ(double z) {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/** Set all coordinates of the vector.
|
||||
* @param x new abscissa for the vector
|
||||
* @param y new ordinate for the vector
|
||||
* @param z new height for the vector
|
||||
* @see #Vector3D(double, double, double)
|
||||
*/
|
||||
public void setCoordinates(double x, double y, double z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/** Get the norm for the vector.
|
||||
* @return euclidian norm for the vector
|
||||
*/
|
||||
public double getNorm() {
|
||||
return Math.sqrt (x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
/** Get the azimuth of the vector.
|
||||
* @return azimuth (α) of the vector, between -π and +π
|
||||
* @see #Vector3D(double, double)
|
||||
*/
|
||||
public double getAlpha() {
|
||||
return Math.atan2(y, x);
|
||||
}
|
||||
|
||||
/** Get the elevation of the vector.
|
||||
* @return elevation (δ) of the vector, between -π/2 and +π/2
|
||||
* @see #Vector3D(double, double)
|
||||
*/
|
||||
public double getDelta() {
|
||||
return Math.asin(z / getNorm());
|
||||
}
|
||||
|
||||
/** Add a vector to the instance.
|
||||
* Add a vector to the instance. The instance is changed.
|
||||
* @param v vector to add
|
||||
*/
|
||||
public void addToSelf(Vector3D v) {
|
||||
x += v.x;
|
||||
y += v.y;
|
||||
z += v.z;
|
||||
}
|
||||
|
||||
/** Add a scaled vector to the instance.
|
||||
* Add a scaled vector to the instance. The instance is changed.
|
||||
* @param factor scale factor to apply to v before adding it
|
||||
* @param v vector to add
|
||||
*/
|
||||
public void addToSelf(double factor, Vector3D v) {
|
||||
x += factor * v.x;
|
||||
y += factor * v.y;
|
||||
z += factor * v.z;
|
||||
}
|
||||
|
||||
/** Add two vectors.
|
||||
* Add two vectors and return the sum as a new vector
|
||||
* @param v1 first vector
|
||||
* @param v2 second vector
|
||||
* @return a new vector equal to v1 + v2
|
||||
*/
|
||||
public static Vector3D add(Vector3D v1, Vector3D v2) {
|
||||
return new Vector3D(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
|
||||
}
|
||||
|
||||
/** Subtract a vector from the instance.
|
||||
* Subtract a vector from the instance. The instance is changed.
|
||||
* @param v vector to subtract
|
||||
*/
|
||||
public void subtractFromSelf(Vector3D v) {
|
||||
x -= v.x;
|
||||
y -= v.y;
|
||||
z -= v.z;
|
||||
}
|
||||
|
||||
/** Subtract two vectors.
|
||||
* Subtract two vectors and return the difference as a new vector
|
||||
* @param v1 first vector
|
||||
* @param v2 second vector
|
||||
* @return a new vector equal to v1 - v2
|
||||
*/
|
||||
public static Vector3D subtract(Vector3D v1, Vector3D v2) {
|
||||
return new Vector3D(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
|
||||
}
|
||||
|
||||
/** Normalize the instance.
|
||||
* Divide the instance by its norm in order to have a unit
|
||||
* vector. The instance is changed.
|
||||
* @exception ArithmeticException if the norm is null
|
||||
*/
|
||||
public void normalizeSelf() {
|
||||
double s = getNorm();
|
||||
if (s == 0) {
|
||||
throw new ArithmeticException("null norm");
|
||||
}
|
||||
double invNorm = 1 / s;
|
||||
x *= invNorm;
|
||||
y *= invNorm;
|
||||
z *= invNorm;
|
||||
}
|
||||
|
||||
/** Get a vector orthogonal to the instance.
|
||||
* <p>There are an infinite number of normalized vectors orthogonal
|
||||
* to the instance. This method picks up one of them almost
|
||||
* arbitrarily. It is useful when one needs to compute a reference
|
||||
* frame with one of the axes in a predefined direction. The
|
||||
* following example shows how to build a frame having the k axis
|
||||
* aligned with the known vector u :
|
||||
* <pre><code>
|
||||
* Vector3D k = u;
|
||||
* k.normalizeSelf();
|
||||
* Vector3D i = k.orthogonal();
|
||||
* Vector3D j = Vector3D.crossProduct(k, i);
|
||||
* </code></pre></p>
|
||||
* @return a new normalized vector orthogonal to the instance
|
||||
* @exception ArithmeticException if the norm of the instance is null
|
||||
*/
|
||||
public Vector3D orthogonal() {
|
||||
|
||||
double threshold = 0.6 * getNorm();
|
||||
if (threshold == 0) {
|
||||
throw new ArithmeticException("null norm");
|
||||
}
|
||||
|
||||
if ((x >= -threshold) && (x <= threshold)) {
|
||||
double inverse = 1 / Math.sqrt(y * y + z * z);
|
||||
return new Vector3D(0, inverse * z, -inverse * y);
|
||||
} else if ((y >= -threshold) && (y <= threshold)) {
|
||||
double inverse = 1 / Math.sqrt(x * x + z * z);
|
||||
return new Vector3D(-inverse * z, 0, inverse * x);
|
||||
} else {
|
||||
double inverse = 1 / Math.sqrt(x * x + y * y);
|
||||
return new Vector3D(inverse * y, -inverse * x, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Compute the angular separation between two vectors.
|
||||
* <p>This method computes the angular separation between two
|
||||
* vectors using the dot product for well separated vectors and the
|
||||
* cross product for almost aligned vectors. This allow to have a
|
||||
* good accuracy in all cases, even for vectors very close to each
|
||||
* other.</p>
|
||||
* @param v1 first vector
|
||||
* @param v2 second vector
|
||||
* @exception ArithmeticException if either vector has a null norm
|
||||
*/
|
||||
public static double angle(Vector3D v1, Vector3D v2) {
|
||||
|
||||
double normProduct = v1.getNorm() * v2.getNorm();
|
||||
if (normProduct == 0) {
|
||||
throw new ArithmeticException("null norm");
|
||||
}
|
||||
|
||||
double dot = dotProduct(v1, v2);
|
||||
double threshold = normProduct * 0.9999;
|
||||
if ((dot < -threshold) || (dot > threshold)) {
|
||||
// the vectors are almost aligned, compute using the sine
|
||||
Vector3D v3 = crossProduct(v1, v2);
|
||||
if (dot >= 0) {
|
||||
return Math.asin(v3.getNorm() / normProduct);
|
||||
}
|
||||
return Math.PI - Math.asin(v3.getNorm() / normProduct);
|
||||
}
|
||||
|
||||
// the vectors are sufficiently separated to use the cosine
|
||||
return Math.acos(dot / normProduct);
|
||||
|
||||
}
|
||||
|
||||
/** Revert the instance.
|
||||
* Replace the instance u by -u
|
||||
*/
|
||||
public void negateSelf() {
|
||||
x = -x;
|
||||
y = -y;
|
||||
z = -z;
|
||||
}
|
||||
|
||||
/** Get the opposite of a vector.
|
||||
* @param u vector to revert
|
||||
* @return a new vector which is -u
|
||||
*/
|
||||
public static Vector3D negate(Vector3D u) {
|
||||
return new Vector3D(-u.x, -u.y, -u.z);
|
||||
}
|
||||
|
||||
/** Multiply the instance by a scalar
|
||||
* Multiply the instance by a scalar. The instance is changed.
|
||||
* @param a scalar by which the instance should be multiplied
|
||||
*/
|
||||
public void multiplySelf(double a) {
|
||||
x *= a;
|
||||
y *= a;
|
||||
z *= a;
|
||||
}
|
||||
|
||||
/** Multiply a vector by a scalar
|
||||
* Multiply a vectors by a scalar and return the product as a new vector
|
||||
* @param a scalar
|
||||
* @param v vector
|
||||
* @return a new vector equal to a * v
|
||||
*/
|
||||
public static Vector3D multiply(double a, Vector3D v) {
|
||||
return new Vector3D(a * v.x, a * v.y, a * v.z);
|
||||
}
|
||||
|
||||
/** Compute the dot-product of two vectors.
|
||||
* @param v1 first vector
|
||||
* @param v2 second vector
|
||||
* @return the dot product v1.v2
|
||||
*/
|
||||
public static double dotProduct(Vector3D v1, Vector3D v2) {
|
||||
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
|
||||
}
|
||||
|
||||
/** Set the instance to the result of the cross-product of two vectors.
|
||||
* @param v1 first vector (can be the instance)
|
||||
* @param v2 second vector (can be the instance)
|
||||
*/
|
||||
public void setToCrossProduct(Vector3D v1, Vector3D v2) {
|
||||
double newX = v1.y * v2.z - v1.z * v2.y;
|
||||
double newY = v1.z * v2.x - v1.x * v2.z;
|
||||
z = v1.x * v2.y - v1.y * v2.x;
|
||||
x = newX;
|
||||
y = newY;
|
||||
}
|
||||
|
||||
/** Compute the cross-product of two vectors.
|
||||
* @param v1 first vector
|
||||
* @param v2 second vector
|
||||
* @return the cross product v1 ^ v2 as a new Vector
|
||||
*/
|
||||
public static Vector3D crossProduct(Vector3D v1, Vector3D v2) {
|
||||
return new Vector3D(v1.y * v2.z - v1.z * v2.y,
|
||||
v1.z * v2.x - v1.x * v2.z,
|
||||
v1.x * v2.y - v1.y * v2.x);
|
||||
}
|
||||
|
||||
public int getStateDimension() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
public void mapStateFromArray(int start, double[] array) {
|
||||
x = array[start];
|
||||
y = array[start + 1];
|
||||
z = array[start + 2];
|
||||
}
|
||||
|
||||
public void mapStateToArray(int start, double[] array) {
|
||||
array[start] = x;
|
||||
array[start + 1] = y;
|
||||
array[start + 2] = z;
|
||||
}
|
||||
|
||||
/** Abscissa. */
|
||||
protected double x;
|
||||
|
||||
/** Ordinate. */
|
||||
protected double y;
|
||||
|
||||
/** Height. */
|
||||
protected double z;
|
||||
|
||||
private static final long serialVersionUID = 4115635019045864211L;
|
||||
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.linalg;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** This class implements diagonal matrices of linear algebra.
|
||||
|
||||
* @version $Id: DiagonalMatrix.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class DiagonalMatrix
|
||||
extends SquareMatrix
|
||||
implements Serializable, Cloneable {
|
||||
|
||||
/** Simple constructor.
|
||||
* This constructor builds a diagonal matrix of specified order, all
|
||||
* elements on the diagonal being ones (so this is an identity matrix).
|
||||
* @param order order of the matrix
|
||||
*/
|
||||
public DiagonalMatrix(int order) {
|
||||
this(order, 1.0);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* This constructor builds a diagonal matrix of specified order and
|
||||
* set all diagonal elements to the same value.
|
||||
* @param order order of the matrix
|
||||
* @param value value for the diagonal elements
|
||||
*/
|
||||
public DiagonalMatrix(int order, double value) {
|
||||
super(order);
|
||||
for (int index = 0; index < order * order; index += order + 1) {
|
||||
data[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a matrix with specified elements.
|
||||
* @param order order of the matrix
|
||||
* @param data table of the matrix elements (stored row after row)
|
||||
*/
|
||||
public DiagonalMatrix(int order, double[] data) {
|
||||
super(order, data);
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* @param d diagonal matrix to copy
|
||||
*/
|
||||
public DiagonalMatrix(DiagonalMatrix d) {
|
||||
super(d);
|
||||
}
|
||||
|
||||
public Matrix duplicate() {
|
||||
return new DiagonalMatrix(this);
|
||||
}
|
||||
|
||||
public void setElement(int i, int j, double value) {
|
||||
if (i != j) {
|
||||
throw new ArrayIndexOutOfBoundsException("cannot set elements"
|
||||
+ " out of diagonal in a"
|
||||
+ " diagonal matrix");
|
||||
}
|
||||
super.setElement(i, j, value);
|
||||
}
|
||||
|
||||
public double getDeterminant(double epsilon) {
|
||||
double determinant = data[0];
|
||||
for (int index = columns + 1; index < columns * columns; index += columns + 1) {
|
||||
determinant *= data[index];
|
||||
}
|
||||
return determinant;
|
||||
}
|
||||
|
||||
public SquareMatrix getInverse(double epsilon)
|
||||
throws SingularMatrixException {
|
||||
|
||||
DiagonalMatrix inv = new DiagonalMatrix (columns);
|
||||
|
||||
for (int index = 0; index < columns * columns; index += columns + 1) {
|
||||
if (Math.abs(data[index]) < epsilon) {
|
||||
throw new SingularMatrixException();
|
||||
}
|
||||
inv.data[index] = 1.0 / data[index];
|
||||
}
|
||||
|
||||
return inv;
|
||||
|
||||
}
|
||||
|
||||
public Matrix solve(Matrix b, double epsilon)
|
||||
throws SingularMatrixException {
|
||||
|
||||
Matrix result = b.duplicate();
|
||||
|
||||
for (int i = 0; i < columns; ++i) {
|
||||
double diag = data[i * (columns + 1)];
|
||||
if (Math.abs(diag) < epsilon) {
|
||||
throw new SingularMatrixException();
|
||||
}
|
||||
double inv = 1.0 / diag;
|
||||
|
||||
NonNullRange range = result.getRangeForRow(i);
|
||||
for (int index = i * b.columns + range.begin;
|
||||
index < i * b.columns + range.end;
|
||||
++index) {
|
||||
result.data[index] = inv * b.data[index];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
public NonNullRange getRangeForRow(int i) {
|
||||
return new NonNullRange(i, i + 1);
|
||||
}
|
||||
|
||||
public NonNullRange getRangeForColumn(int j) {
|
||||
return new NonNullRange(j, j + 1);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -2965166085913895323L;
|
||||
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.linalg;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** This class represents matrices of the most general type.
|
||||
|
||||
* <p>This class is the basic implementation of matrices to use when
|
||||
* nothing special is known about the structure of the matrix.</p>
|
||||
|
||||
* @version $Id: GeneralMatrix.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class GeneralMatrix
|
||||
extends Matrix
|
||||
implements Serializable {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a matrix with null elements.
|
||||
* @param rows number of rows of the matrix
|
||||
* @param columns number of columns of the matrix
|
||||
*/
|
||||
public GeneralMatrix(int rows, int columns) {
|
||||
super(rows, columns);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a matrix with specified elements.
|
||||
* @param rows number of rows of the matrix
|
||||
* @param columns number of columns of the matrix
|
||||
* @param data table of the matrix elements (stored row after row)
|
||||
*/
|
||||
public GeneralMatrix(int rows, int columns, double[] data) {
|
||||
super(rows, columns, data);
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* @param m matrix to copy
|
||||
*/
|
||||
public GeneralMatrix(Matrix m) {
|
||||
super(m);
|
||||
}
|
||||
|
||||
public Matrix duplicate() {
|
||||
return new GeneralMatrix(this);
|
||||
}
|
||||
|
||||
/** Add a matrix to the instance.
|
||||
* This method adds a matrix to the instance. It does modify the instance.
|
||||
* @param m matrix to add
|
||||
* @exception IllegalArgumentException if there is a dimension mismatch
|
||||
*/
|
||||
public void selfAdd(Matrix m) {
|
||||
|
||||
// validity check
|
||||
if ((rows != m.rows) || (columns != m.columns)) {
|
||||
throw new IllegalArgumentException("cannot add a "
|
||||
+ m.rows + 'x' + m.columns
|
||||
+ " matrix to a "
|
||||
+ rows + 'x' + columns
|
||||
+ " matrix");
|
||||
}
|
||||
|
||||
// addition loop
|
||||
for (int index = 0; index < rows * columns; ++index) {
|
||||
data[index] += m.data[index];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Substract a matrix from the instance.
|
||||
* This method substracts a matrix from the instance. It does modify the instance.
|
||||
* @param m matrix to substract
|
||||
* @exception IllegalArgumentException if there is a dimension mismatch
|
||||
*/
|
||||
public void selfSub(Matrix m) {
|
||||
|
||||
// validity check
|
||||
if ((rows != m.rows) || (columns != m.columns)) {
|
||||
throw new IllegalArgumentException("cannot substract a "
|
||||
+ m.rows + 'x' + m.columns
|
||||
+ " matrix from a "
|
||||
+ rows + 'x' + columns
|
||||
+ " matrix");
|
||||
}
|
||||
|
||||
// substraction loop
|
||||
for (int index = 0; index < rows * columns; ++index) {
|
||||
data[index] -= m.data[index];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected NonNullRange getRangeForRow(int i) {
|
||||
return new NonNullRange(0, columns);
|
||||
}
|
||||
|
||||
protected NonNullRange getRangeForColumn(int j) {
|
||||
return new NonNullRange(0, rows);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 4350328622456299819L;
|
||||
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.linalg;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** This class implements general square matrices of linear algebra.
|
||||
|
||||
* @version $Id: GeneralSquareMatrix.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class GeneralSquareMatrix
|
||||
extends SquareMatrix
|
||||
implements Serializable, Cloneable {
|
||||
|
||||
/** Simple constructor.
|
||||
* This constructor builds a square matrix of specified order, all
|
||||
* elements beeing zeros.
|
||||
* @param order order of the matrix
|
||||
*/
|
||||
public GeneralSquareMatrix(int order) {
|
||||
super(order);
|
||||
permutations = null;
|
||||
evenPermutations = true;
|
||||
lower = null;
|
||||
upper = null;
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a matrix with specified elements.
|
||||
* @param order order of the matrix
|
||||
* @param data table of the matrix elements (stored row after row)
|
||||
*/
|
||||
public GeneralSquareMatrix(int order, double[] data) {
|
||||
super(order, data);
|
||||
permutations = null;
|
||||
evenPermutations = true;
|
||||
lower = null;
|
||||
upper = null;
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* @param s square matrix to copy
|
||||
*/
|
||||
public GeneralSquareMatrix(GeneralSquareMatrix s) {
|
||||
super(s);
|
||||
|
||||
if (s.permutations != null) {
|
||||
permutations = (int[]) s.permutations.clone();
|
||||
evenPermutations = s.evenPermutations;
|
||||
lower = new LowerTriangularMatrix(s.lower);
|
||||
upper = new UpperTriangularMatrix(s.upper);
|
||||
} else {
|
||||
permutations = null;
|
||||
evenPermutations = true;
|
||||
lower = null;
|
||||
upper = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Matrix duplicate() {
|
||||
return new GeneralSquareMatrix(this);
|
||||
}
|
||||
|
||||
public void setElement(int i, int j, double value) {
|
||||
super.setElement(i, j, value);
|
||||
permutations = null;
|
||||
evenPermutations = true;
|
||||
lower = null;
|
||||
upper = null;
|
||||
}
|
||||
|
||||
/** Add a matrix to the instance.
|
||||
* This method adds a matrix to the instance. It does modify the instance.
|
||||
* @param s square matrix to add
|
||||
* @exception IllegalArgumentException if there is a dimension mismatch
|
||||
*/
|
||||
public void selfAdd(SquareMatrix s) {
|
||||
|
||||
// validity check
|
||||
if ((rows != s.rows) || (columns != s.columns)) {
|
||||
throw new IllegalArgumentException("cannot add a "
|
||||
+ s.rows + 'x' + s.columns
|
||||
+ " matrix to a "
|
||||
+ rows + 'x' + columns
|
||||
+ " matrix");
|
||||
}
|
||||
|
||||
// addition loop
|
||||
for (int index = 0; index < rows * columns; ++index) {
|
||||
data[index] += s.data[index];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Substract a matrix from the instance.
|
||||
* This method substracts a matrix from the instance. It does modify the instance.
|
||||
* @param s square matrix to substract
|
||||
* @exception IllegalArgumentException if there is a dimension mismatch
|
||||
*/
|
||||
public void selfSub(SquareMatrix s) {
|
||||
|
||||
// validity check
|
||||
if ((rows != s.rows) || (columns != s.columns)) {
|
||||
throw new IllegalArgumentException("cannot substract a "
|
||||
+ s.rows + 'x' + s.columns
|
||||
+ " matrix from a "
|
||||
+ rows + 'x' + columns
|
||||
+ " matrix");
|
||||
}
|
||||
|
||||
// substraction loop
|
||||
for (int index = 0; index < rows * columns; ++index) {
|
||||
data[index] -= s.data[index];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public double getDeterminant(double epsilon) {
|
||||
try {
|
||||
if (permutations == null)
|
||||
computeLUFactorization(epsilon);
|
||||
double d = upper.getDeterminant(epsilon);
|
||||
return evenPermutations ? d : -d;
|
||||
} catch (SingularMatrixException e) {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
public Matrix solve(Matrix b, double epsilon)
|
||||
throws SingularMatrixException {
|
||||
// validity check
|
||||
if (b.getRows() != rows) {
|
||||
throw new IllegalArgumentException("dimension mismatch");
|
||||
}
|
||||
|
||||
if (permutations == null) {
|
||||
computeLUFactorization(epsilon);
|
||||
}
|
||||
|
||||
// apply the permutations to the second member
|
||||
double[] permData = new double[b.data.length];
|
||||
int bCols = b.getColumns();
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
NonNullRange range = b.getRangeForRow(permutations[i]);
|
||||
for (int j = range.begin; j < range.end; ++j) {
|
||||
permData[i * bCols + j] = b.data[permutations[i] * bCols + j];
|
||||
}
|
||||
}
|
||||
Matrix permB = MatrixFactory.buildMatrix(b.getRows(), bCols, permData);
|
||||
|
||||
// solve the permuted system
|
||||
return upper.solve(lower.solve(permB, epsilon), epsilon);
|
||||
|
||||
}
|
||||
|
||||
protected NonNullRange getRangeForRow(int i) {
|
||||
return new NonNullRange(0, columns);
|
||||
}
|
||||
|
||||
protected NonNullRange getRangeForColumn(int j) {
|
||||
return new NonNullRange(0, rows);
|
||||
}
|
||||
|
||||
private void computeLUFactorization(double epsilon)
|
||||
throws SingularMatrixException {
|
||||
// build a working copy of the matrix data
|
||||
double[] work = new double[rows * columns];
|
||||
for (int index = 0; index < work.length; ++index) {
|
||||
work[index] = data[index];
|
||||
}
|
||||
|
||||
// initialize the permutations table to identity
|
||||
permutations = new int[rows];
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
permutations[i] = i;
|
||||
}
|
||||
evenPermutations = true;
|
||||
|
||||
for (int k = 0; k < rows; ++k) {
|
||||
|
||||
// find the maximal element in the column
|
||||
double maxElt = Math.abs(work[permutations[k] * columns + k]);
|
||||
int jMax = k;
|
||||
for (int i = k + 1; i < rows; ++i) {
|
||||
double curElt = Math.abs(work[permutations[i] * columns + k]);
|
||||
if (curElt > maxElt) {
|
||||
maxElt = curElt;
|
||||
jMax = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxElt < epsilon) {
|
||||
throw new SingularMatrixException();
|
||||
}
|
||||
|
||||
if (k != jMax) {
|
||||
// do the permutation to have a large enough diagonal element
|
||||
int tmp = permutations[k];
|
||||
permutations[k] = permutations[jMax];
|
||||
permutations[jMax] = tmp;
|
||||
evenPermutations = ! evenPermutations;
|
||||
}
|
||||
|
||||
double inv = 1.0 / work[permutations[k] * columns + k];
|
||||
|
||||
// compute the contribution of the row to the triangular matrices
|
||||
for (int i = k + 1; i < rows; ++i) {
|
||||
double factor = inv * work[permutations[i] * columns + k];
|
||||
|
||||
// lower triangular matrix
|
||||
work[permutations[i] * columns + k] = factor;
|
||||
|
||||
// upper triangular matrix
|
||||
int index1 = permutations[i] * columns + k;
|
||||
int index2 = permutations[k] * columns + k;
|
||||
for (int j = k + 1; j < columns; ++j) {
|
||||
work[++index1] -= factor * work[++index2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build the matrices
|
||||
double[] lowerData = new double[rows * columns];
|
||||
double[] upperData = new double[rows * columns];
|
||||
|
||||
int index = 0;
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
int workIndex = permutations[i] * columns;
|
||||
int j = 0;
|
||||
|
||||
// lower part
|
||||
while (j++ < i) {
|
||||
lowerData[index] = work[workIndex++];
|
||||
upperData[index++] = 0.0;
|
||||
}
|
||||
|
||||
// diagonal
|
||||
lowerData[index] = 1.0;
|
||||
upperData[index++] = work[workIndex++];
|
||||
|
||||
// upper part
|
||||
while (j++ < columns) {
|
||||
lowerData[index] = 0.0;
|
||||
upperData[index++] = work[workIndex++];
|
||||
}
|
||||
}
|
||||
|
||||
// release the memory as soon as possible
|
||||
work = null;
|
||||
|
||||
lower = new LowerTriangularMatrix(rows, lowerData);
|
||||
upper = new UpperTriangularMatrix(rows, upperData);
|
||||
|
||||
}
|
||||
|
||||
private int[] permutations;
|
||||
private boolean evenPermutations;
|
||||
private LowerTriangularMatrix lower;
|
||||
private UpperTriangularMatrix upper;
|
||||
|
||||
private static final long serialVersionUID = -506293526695298279L;
|
||||
|
||||
}
|
|
@ -0,0 +1,219 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.linalg;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** This class implements lower triangular matrices of linear algebra.
|
||||
|
||||
* @version $Id: LowerTriangularMatrix.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class LowerTriangularMatrix
|
||||
extends SquareMatrix
|
||||
implements Serializable, Cloneable {
|
||||
|
||||
/** Simple constructor.
|
||||
* This constructor builds a lower triangular matrix of specified order, all
|
||||
* elements being zeros.
|
||||
* @param order order of the matrix
|
||||
*/
|
||||
public LowerTriangularMatrix(int order) {
|
||||
super(order);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a matrix with specified elements.
|
||||
* @param order order of the matrix
|
||||
* @param data table of the matrix elements (stored row after row)
|
||||
*/
|
||||
public LowerTriangularMatrix(int order, double[] data) {
|
||||
super(order, data);
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* @param l lower triangular matrix to copy
|
||||
*/
|
||||
public LowerTriangularMatrix(LowerTriangularMatrix l) {
|
||||
super(l);
|
||||
}
|
||||
|
||||
public Matrix duplicate() {
|
||||
return new LowerTriangularMatrix(this);
|
||||
}
|
||||
|
||||
public void setElement(int i, int j, double value) {
|
||||
if (i < j) {
|
||||
throw new ArrayIndexOutOfBoundsException("cannot set elements"
|
||||
+ " above diagonal of a"
|
||||
+ " lower triangular matrix");
|
||||
}
|
||||
super.setElement(i, j, value);
|
||||
}
|
||||
|
||||
/** Add a matrix to the instance.
|
||||
* This method adds a matrix to the instance. It does modify the instance.
|
||||
* @param l lower triangular matrix to add
|
||||
* @exception IllegalArgumentException if there is a dimension mismatch
|
||||
*/
|
||||
public void selfAdd(LowerTriangularMatrix l) {
|
||||
|
||||
// validity check
|
||||
if ((rows != l.rows) || (columns != l.columns)) {
|
||||
throw new IllegalArgumentException("cannot add a "
|
||||
+ l.rows + 'x' + l.columns
|
||||
+ " matrix to a "
|
||||
+ rows + 'x' + columns
|
||||
+ " matrix");
|
||||
}
|
||||
|
||||
// addition loop
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
for (int index = i * columns; index < i * (columns + 1) + 1; ++index) {
|
||||
data[index] += l.data[index];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Substract a matrix from the instance.
|
||||
* This method substract a matrix from the instance. It does modify the instance.
|
||||
* @param l lower triangular matrix to substract
|
||||
* @exception IllegalArgumentException if there is a dimension mismatch
|
||||
*/
|
||||
public void selfSub(LowerTriangularMatrix l) {
|
||||
|
||||
// validity check
|
||||
if ((rows != l.rows) || (columns != l.columns)) {
|
||||
throw new IllegalArgumentException("cannot substract a "
|
||||
+ l.rows + 'x' + l.columns
|
||||
+ " matrix from a "
|
||||
+ rows + 'x' + columns
|
||||
+ " matrix");
|
||||
}
|
||||
|
||||
// substraction loop
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
for (int index = i * columns; index < i * (columns + 1) + 1; ++index) {
|
||||
data[index] -= l.data[index];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public double getDeterminant(double epsilon) {
|
||||
double determinant = data[0];
|
||||
for (int index = columns + 1; index < columns * columns; index += columns + 1) {
|
||||
determinant *= data[index];
|
||||
}
|
||||
return determinant;
|
||||
}
|
||||
|
||||
public Matrix solve(Matrix b, double epsilon)
|
||||
throws SingularMatrixException {
|
||||
// validity check
|
||||
if (b.getRows () != rows) {
|
||||
throw new IllegalArgumentException("dimension mismatch");
|
||||
}
|
||||
|
||||
// prepare the data storage
|
||||
int bRows = b.getRows();
|
||||
int bCols = b.getColumns();
|
||||
|
||||
double[] resultData = new double[bRows * bCols];
|
||||
int resultIndex = 0;
|
||||
int lowerElements = 0;
|
||||
int upperElements = 0;
|
||||
int minJ = columns;
|
||||
int maxJ = 0;
|
||||
|
||||
// solve the linear system
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
double diag = data[i * (columns + 1)];
|
||||
if (Math.abs(diag) < epsilon) {
|
||||
throw new SingularMatrixException();
|
||||
}
|
||||
double inv = 1.0 / diag;
|
||||
|
||||
NonNullRange range = b.getRangeForRow(i);
|
||||
minJ = Math.min(minJ, range.begin);
|
||||
maxJ = Math.max(maxJ, range.end);
|
||||
|
||||
int j = 0;
|
||||
while (j < minJ) {
|
||||
resultData[resultIndex] = 0.0;
|
||||
++resultIndex;
|
||||
++j;
|
||||
}
|
||||
|
||||
// compute the possibly non null elements
|
||||
int bIndex = i * bCols + minJ;
|
||||
while (j < maxJ) {
|
||||
|
||||
// compute the current element
|
||||
int index1 = i * columns;
|
||||
int index2 = j;
|
||||
double value = b.data[bIndex];
|
||||
while (index1 < i * (columns + 1)) {
|
||||
value -= data[index1] * resultData[index2];
|
||||
++index1;
|
||||
index2 += bCols;
|
||||
}
|
||||
value *= inv;
|
||||
resultData[resultIndex] = value;
|
||||
|
||||
// count the affected upper and lower elements
|
||||
// (in order to deduce the shape of the resulting matrix)
|
||||
if (j < i) {
|
||||
++lowerElements;
|
||||
} else if (i < j) {
|
||||
++upperElements;
|
||||
}
|
||||
|
||||
++bIndex;
|
||||
++resultIndex;
|
||||
++j;
|
||||
|
||||
}
|
||||
|
||||
while (j < bCols) {
|
||||
resultData[resultIndex] = 0.0;
|
||||
++resultIndex;
|
||||
++j;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return MatrixFactory.buildMatrix(bRows, bCols, resultData,
|
||||
lowerElements, upperElements);
|
||||
|
||||
}
|
||||
|
||||
public NonNullRange getRangeForRow(int i) {
|
||||
return new NonNullRange(0, i + 1);
|
||||
}
|
||||
|
||||
public NonNullRange getRangeForColumn(int j) {
|
||||
return new NonNullRange(j, rows);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 3592505328858227281L;
|
||||
|
||||
}
|
|
@ -0,0 +1,484 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.linalg;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** This class factor all services common to matrices.
|
||||
|
||||
* <p>This class is the base class of all matrix implementations, it
|
||||
* is also the base class of the {@link SquareMatrix} class which adds
|
||||
* methods specific to square matrices.</p>
|
||||
|
||||
* <p>This class both handles the storage of matrix elements and
|
||||
* implements the classical operations on matrices (addition,
|
||||
* substraction, multiplication, transposition). It relies on two
|
||||
* protected methods ({@link #getRangeForRow} and {@link
|
||||
* #getRangeForColumn}) to get tight loop bounds for matrices with
|
||||
* known structures full of zeros. These methods should be
|
||||
* implemented by derived classes to provide information about their
|
||||
* specific shape to the general algorithms implemented by this
|
||||
* abstract class.</p>
|
||||
|
||||
* @version $Id: Matrix.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public abstract class Matrix
|
||||
implements Serializable {
|
||||
/** Simple constructor.
|
||||
* Build a matrix with null elements.
|
||||
* @param rows number of rows of the matrix
|
||||
* @param columns number of columns of the matrix
|
||||
*/
|
||||
protected Matrix(int rows, int columns) {
|
||||
// sanity check
|
||||
if (rows <= 0 || columns <= 0) {
|
||||
throw new IllegalArgumentException("cannot build a matrix"
|
||||
+ " with negative or null dimension");
|
||||
}
|
||||
|
||||
this.rows = rows;
|
||||
this.columns = columns;
|
||||
data = new double[rows * columns];
|
||||
for (int i = 0; i < data.length; ++i) {
|
||||
data[i] = 0.0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a matrix with specified elements.
|
||||
* @param rows number of rows of the matrix
|
||||
* @param columns number of columns of the matrix
|
||||
* @param data table of the matrix elements (stored row after row)
|
||||
*/
|
||||
public Matrix(int rows, int columns, double[] data) {
|
||||
// sanity check
|
||||
if (rows <= 0 || columns <= 0) {
|
||||
throw new IllegalArgumentException("cannot build a matrix"
|
||||
+ " with negative or null dimension");
|
||||
}
|
||||
|
||||
this.rows = rows;
|
||||
this.columns = columns;
|
||||
this.data = data;
|
||||
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* @param m matrix to copy
|
||||
*/
|
||||
protected Matrix(Matrix m) {
|
||||
rows = m.rows;
|
||||
columns = m.columns;
|
||||
data = new double[rows * columns];
|
||||
System.arraycopy(m.data, 0, data, 0, m.data.length);
|
||||
}
|
||||
|
||||
/** Polymorphic copy operator.
|
||||
* This method build a new object of the same type of the
|
||||
* instance. It is somewhat similar to the {@link Object#clone}
|
||||
* method, except that it has public access, it doesn't throw any
|
||||
* specific exception and it returns a Matrix.
|
||||
*@see Object#clone
|
||||
*/
|
||||
public abstract Matrix duplicate();
|
||||
|
||||
/** Get the number of rows of the matrix.
|
||||
* @return number of rows
|
||||
* @see #getColumns
|
||||
*/
|
||||
public int getRows() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
/** Get the number of columns of the matrix.
|
||||
* @return number of columns
|
||||
* @see #getRows
|
||||
*/
|
||||
public int getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
/** Get a matrix element.
|
||||
* @param i row index, from 0 to rows - 1
|
||||
* @param j column index, from 0 to cols - 1
|
||||
* @return value of the element
|
||||
* @exception ArrayIndexOutOfBoundsException if the indices are wrong
|
||||
* @see #setElement
|
||||
*/
|
||||
public double getElement(int i, int j) {
|
||||
if (i < 0 || i >= rows || j < 0 || j >= columns) {
|
||||
throw new IllegalArgumentException("cannot get element ("
|
||||
+ i + ", " + j + ") from a "
|
||||
+ rows + 'x' + columns
|
||||
+ " matrix");
|
||||
}
|
||||
return data[i * columns + j];
|
||||
}
|
||||
|
||||
/** Set a matrix element.
|
||||
* @param i row index, from 0 to rows - 1
|
||||
* @param j column index, from 0 to cols - 1
|
||||
* @param value value of the element
|
||||
* @exception ArrayIndexOutOfBoundsException if the indices are wrong
|
||||
* @see #getElement
|
||||
*/
|
||||
public void setElement(int i, int j, double value) {
|
||||
if (i < 0 || i >= rows || j < 0 || j >= columns) {
|
||||
throw new IllegalArgumentException("cannot set element ("
|
||||
+ i + ", " + j + ") in a "
|
||||
+ rows + 'x' + columns
|
||||
+ " matrix");
|
||||
}
|
||||
data[i * columns + j] = value;
|
||||
}
|
||||
|
||||
/** Add a matrix to the instance.
|
||||
* This method adds a matrix to the instance. It returns a new
|
||||
* matrix and does not modify the instance.
|
||||
* @param m matrix to add
|
||||
* @return a new matrix containing the result
|
||||
* @exception IllegalArgumentException if there is a dimension mismatch
|
||||
*/
|
||||
public Matrix add(Matrix m) {
|
||||
|
||||
// validity check
|
||||
if ((rows != m.rows) || (columns != m.columns)) {
|
||||
throw new IllegalArgumentException("cannot add a "
|
||||
+ m.rows + 'x' + m.columns
|
||||
+ " matrix to a "
|
||||
+ rows + 'x' + columns
|
||||
+ " matrix");
|
||||
}
|
||||
|
||||
double[] resultData = new double[rows * columns];
|
||||
int resultIndex = 0;
|
||||
int lowerElements = 0;
|
||||
int upperElements = 0;
|
||||
|
||||
// external loop through the rows
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
// compute the indices of the internal loop
|
||||
NonNullRange r = NonNullRange.reunion(getRangeForRow(i),
|
||||
m.getRangeForRow(i));
|
||||
|
||||
// assign the zeros before the non null range
|
||||
int j = 0;
|
||||
while (j < r.begin) {
|
||||
resultData[resultIndex] = 0.0;
|
||||
++resultIndex;
|
||||
++j;
|
||||
}
|
||||
|
||||
// compute the possibly non null elements
|
||||
while (j < r.end) {
|
||||
|
||||
// compute the current element
|
||||
resultData[resultIndex] = data[resultIndex] + m.data[resultIndex];
|
||||
|
||||
// count the affected upper and lower elements
|
||||
// (in order to deduce the shape of the resulting matrix)
|
||||
if (j < i) {
|
||||
++lowerElements;
|
||||
} else if (i < j) {
|
||||
++upperElements;
|
||||
}
|
||||
|
||||
++resultIndex;
|
||||
++j;
|
||||
|
||||
}
|
||||
|
||||
// assign the zeros after the non null range
|
||||
while (j < columns) {
|
||||
resultData[resultIndex++] = 0.0;
|
||||
++resultIndex;
|
||||
++j;
|
||||
}
|
||||
}
|
||||
|
||||
return MatrixFactory.buildMatrix(rows, columns, resultData,
|
||||
lowerElements, upperElements);
|
||||
|
||||
}
|
||||
|
||||
/** Substract a matrix from the instance.
|
||||
* This method substracts a matrix from the instance. It returns a new
|
||||
* matrix and does not modify the instance.
|
||||
* @param m matrix to substract
|
||||
* @return a new matrix containing the result
|
||||
* @exception IllegalArgumentException if there is a dimension mismatch
|
||||
*/
|
||||
public Matrix sub(Matrix m) {
|
||||
|
||||
// validity check
|
||||
if ((rows != m.rows) || (columns != m.columns)) {
|
||||
throw new IllegalArgumentException("cannot substract a "
|
||||
+ m.rows + 'x' + m.columns
|
||||
+ " matrix from a "
|
||||
+ rows + 'x' + columns
|
||||
+ " matrix");
|
||||
}
|
||||
|
||||
double[] resultData = new double[rows * columns];
|
||||
int resultIndex = 0;
|
||||
int lowerElements = 0;
|
||||
int upperElements = 0;
|
||||
|
||||
// external loop through the rows
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
// compute the indices of the internal loop
|
||||
NonNullRange r = NonNullRange.reunion(getRangeForRow(i),
|
||||
m.getRangeForRow(i));
|
||||
|
||||
// assign the zeros before the non null range
|
||||
int j = 0;
|
||||
while (j < r.begin) {
|
||||
resultData[resultIndex] = 0.0;
|
||||
++resultIndex;
|
||||
++j;
|
||||
}
|
||||
|
||||
// compute the possibly non null elements
|
||||
while (j < r.end) {
|
||||
|
||||
// compute the current element
|
||||
resultData[resultIndex] = data[resultIndex] - m.data[resultIndex];
|
||||
|
||||
// count the affected upper and lower elements
|
||||
// (in order to deduce the shape of the resulting matrix)
|
||||
if (j < i) {
|
||||
++lowerElements;
|
||||
} else if (i < j) {
|
||||
++upperElements;
|
||||
}
|
||||
|
||||
++resultIndex;
|
||||
++j;
|
||||
|
||||
}
|
||||
|
||||
// assign the zeros after the non null range
|
||||
while (j < columns) {
|
||||
resultData[resultIndex++] = 0.0;
|
||||
++resultIndex;
|
||||
++j;
|
||||
}
|
||||
}
|
||||
|
||||
return MatrixFactory.buildMatrix(rows, columns, resultData,
|
||||
lowerElements, upperElements);
|
||||
|
||||
}
|
||||
|
||||
/** Multiply the instance by a matrix.
|
||||
* This method multiplies the instance by a matrix. It returns a new
|
||||
* matrix and does not modify the instance.
|
||||
* @param m matrix by which to multiply
|
||||
* @return a new matrix containing the result
|
||||
* @exception IllegalArgumentException if there is a dimension mismatch
|
||||
*/
|
||||
public Matrix mul(Matrix m) {
|
||||
|
||||
// validity check
|
||||
if (columns != m.rows) {
|
||||
throw new IllegalArgumentException("cannot multiply a "
|
||||
+ rows + 'x' + columns
|
||||
+ " matrix by a "
|
||||
+ m.rows + 'x' + m.columns
|
||||
+ " matrix");
|
||||
}
|
||||
|
||||
double[] resultData = new double[rows * m.columns];
|
||||
int resultIndex = 0;
|
||||
int lowerElements = 0;
|
||||
int upperElements = 0;
|
||||
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
for (int j = 0; j < m.columns; ++j) {
|
||||
double value = 0.0;
|
||||
|
||||
// compute the tighter possible indices of the internal loop
|
||||
NonNullRange r = NonNullRange.intersection(getRangeForRow(i),
|
||||
m.getRangeForColumn(j));
|
||||
|
||||
if (r.begin < r.end) {
|
||||
int k = r.begin;
|
||||
int idx = i * columns + k;
|
||||
int midx = k * m.columns + j;
|
||||
while (k++ < r.end) {
|
||||
value += data[idx++] * m.data[midx];
|
||||
midx += m.columns;
|
||||
}
|
||||
|
||||
// count the affected upper and lower elements
|
||||
// (in order to deduce the shape of the resulting matrix)
|
||||
if (j < i) {
|
||||
++lowerElements;
|
||||
} else if (i < j) {
|
||||
++upperElements;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// store the element value
|
||||
resultData[resultIndex++] = value;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return MatrixFactory.buildMatrix(rows, m.columns, resultData,
|
||||
lowerElements, upperElements);
|
||||
|
||||
}
|
||||
|
||||
/** Multiply the instance by a scalar.
|
||||
* This method multiplies the instance by a scalar. It returns a new
|
||||
* matrix and does not modify the instance.
|
||||
* @param a scalar by which to multiply
|
||||
* @return a new matrix containing the result
|
||||
* @see #selfMul(double)
|
||||
*/
|
||||
public Matrix mul(double a) {
|
||||
Matrix copy = duplicate();
|
||||
copy.selfMul(a);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/** Multiply the instance by a scalar.
|
||||
* This method multiplies the instance by a scalar.
|
||||
* It does modify the instance.
|
||||
* @param a scalar by which to multiply
|
||||
* @see #mul(double)
|
||||
*/
|
||||
public void selfMul(double a) {
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
NonNullRange r = getRangeForRow(i);
|
||||
for (int j = r.begin, index = i * columns + r.begin; j < r.end; ++j) {
|
||||
data[index++] *= a;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Compute the transpose of the instance.
|
||||
* This method transposes the instance. It returns a new
|
||||
* matrix and does not modify the instance.
|
||||
* @return a new matrix containing the result
|
||||
*/
|
||||
public Matrix getTranspose() {
|
||||
|
||||
double[] resultData = new double[columns * rows];
|
||||
int resultIndex = 0;
|
||||
int upperElements = 0;
|
||||
int lowerElements = 0;
|
||||
|
||||
for (int i = 0; i < columns; ++i) {
|
||||
// compute the indices of the internal loop
|
||||
NonNullRange range = getRangeForColumn(i);
|
||||
|
||||
int j = 0;
|
||||
int index = i;
|
||||
|
||||
// assign the zeros before the non null range
|
||||
while (j < range.begin) {
|
||||
resultData[resultIndex++] = 0.0;
|
||||
index += columns;
|
||||
++j;
|
||||
}
|
||||
|
||||
// compute the possibly non null elements
|
||||
while (j < range.end) {
|
||||
resultData[resultIndex] = data[index];
|
||||
|
||||
// count the affected upper and lower elements
|
||||
// (in order to deduce the shape of the resulting matrix)
|
||||
if (j < i) {
|
||||
++lowerElements;
|
||||
} else if (i < j) {
|
||||
++upperElements;
|
||||
}
|
||||
|
||||
index += columns;
|
||||
++resultIndex;
|
||||
++j;
|
||||
|
||||
}
|
||||
|
||||
// assign the zeros after the non null range
|
||||
while (j < rows) {
|
||||
resultData[resultIndex] = 0.0;
|
||||
++resultIndex;
|
||||
++j;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return MatrixFactory.buildMatrix(columns, rows, resultData,
|
||||
lowerElements, upperElements);
|
||||
|
||||
}
|
||||
|
||||
/** Set a range to the non null part covered by a row.
|
||||
* @param i index of the row
|
||||
* @return range of non nul elements in the specified row
|
||||
* @see #getRangeForColumn
|
||||
*/
|
||||
protected abstract NonNullRange getRangeForRow(int i);
|
||||
|
||||
/** Set a range to the non null part covered by a column.
|
||||
* @param j index of the column
|
||||
* @return range of non nul elements in the specified column
|
||||
* @see #getRangeForRow
|
||||
*/
|
||||
protected abstract NonNullRange getRangeForColumn(int j);
|
||||
|
||||
public String toString() {
|
||||
String separator = System.getProperty("line.separator");
|
||||
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int index = 0; index < rows * columns; ++index) {
|
||||
if (index > 0) {
|
||||
if (index % columns == 0) {
|
||||
buf.append(separator);
|
||||
} else {
|
||||
buf.append(' ');
|
||||
}
|
||||
}
|
||||
buf.append(Double.toString(data[index]));
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
|
||||
}
|
||||
|
||||
/** number of rows of the matrix. */
|
||||
protected final int rows;
|
||||
|
||||
/** number of columns of the matrix. */
|
||||
protected final int columns;
|
||||
|
||||
/** array of the matrix elements.
|
||||
* the elements are stored in a one dimensional array, row after row
|
||||
*/
|
||||
protected final double[] data;
|
||||
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.linalg;
|
||||
|
||||
/** This class is a factory for the linear algebra package.
|
||||
|
||||
* <p>This class is devoted to building the right type of matrix
|
||||
* according to the structure of the non null elements.</p>
|
||||
|
||||
* <p>This is a utility class, no instance of this class should be
|
||||
* built, so the constructor is explicitly made private.</p>
|
||||
|
||||
* @version $Id: MatrixFactory.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class MatrixFactory {
|
||||
/** Simple constructor.
|
||||
* Since the class is a utility class with only static methods, the
|
||||
* constructor is made private to prevent creating instances of this
|
||||
* class.
|
||||
*/
|
||||
private MatrixFactory() {
|
||||
}
|
||||
|
||||
/** Build a matrix of the right subtype.
|
||||
* Build the right subtype of matrix according to the structure of
|
||||
* the non null elements of the instance. Note that the information
|
||||
* provided does not allow to build instances of the {@link
|
||||
* SymetricalMatrix} class. When the data corresponding to a
|
||||
* symetrical matrix is given, this method can only build an
|
||||
* instance of the {@link GeneralSquareMatrix} class.
|
||||
* @param rows number of row of the matrix
|
||||
* @param columns number of columns of the matrix
|
||||
* @param data table of the matrix elements (stored row after row)
|
||||
* @param lowerElements number of non null elements in the lower triangle
|
||||
* @param upperElements number of non null elements in the upper triangle
|
||||
* @return a matrix containing the instance
|
||||
*/
|
||||
public static Matrix buildMatrix(int rows, int columns, double[] data,
|
||||
int lowerElements, int upperElements) {
|
||||
if (rows == columns) {
|
||||
if (lowerElements == 0 && upperElements == 0) {
|
||||
return new DiagonalMatrix(rows, data);
|
||||
} else if (lowerElements == 0) {
|
||||
return new UpperTriangularMatrix(rows, data);
|
||||
} else if (upperElements == 0) {
|
||||
return new LowerTriangularMatrix(rows, data);
|
||||
} else {
|
||||
return new GeneralSquareMatrix(rows, data);
|
||||
}
|
||||
}
|
||||
return new GeneralMatrix(rows, columns, data);
|
||||
}
|
||||
|
||||
/** Build a matrix of the right subtype.
|
||||
* Build the right subtype of matrix according to the dimensions.
|
||||
* @param rows number of row of the matrix
|
||||
* @param columns number of columns of the matrix
|
||||
* @param data table of the matrix elements (stored row after row)
|
||||
* @return a matrix containing the instance
|
||||
*/
|
||||
public static Matrix buildMatrix(int rows, int columns, double[] data) {
|
||||
if (rows == columns) {
|
||||
return new GeneralSquareMatrix(rows, data);
|
||||
}
|
||||
return new GeneralMatrix(rows, columns, data);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.linalg;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** This class represents range of non null elements for rows or
|
||||
* columns of matrices.
|
||||
|
||||
* <p>This class is used to reduce the computation loops by avoiding
|
||||
* using elements that are known to be zeros. For full matrices, the
|
||||
* range simply spans from 0 to the order of the matrix. For lower and
|
||||
* upper triangular matrices, its width will depend on the index of
|
||||
* the row or column considered. For diagonal matrices, the range is
|
||||
* reduced to one index.</p>
|
||||
|
||||
* <p>The indices provided by the class correspond to the elements
|
||||
* that are non-null only according to the <emph>structure</emph> of
|
||||
* the matrix. The real value of the element is not
|
||||
* considered. Consider for example the following lower triangular
|
||||
* matrix :</p>
|
||||
|
||||
* <pre>
|
||||
* 1 0 0 0
|
||||
* 2 8 0 0
|
||||
* 0 5 3 0
|
||||
* 3 2 4 4
|
||||
* </pre>
|
||||
|
||||
* <p>The third rows begins with zero, but this is not a consequence
|
||||
* of the lower triangular structure, it is only a
|
||||
* coincidence. Therefore, the range (in row/columns count)
|
||||
* corresponding to third row will span from 0 to 2, not from 1 to 2.</p>
|
||||
|
||||
* @version $Id: NonNullRange.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
class NonNullRange
|
||||
implements Serializable, Cloneable {
|
||||
|
||||
/** Index in row/column count of the first non-null element. */
|
||||
public final int begin;
|
||||
|
||||
/** Index in row/column count after the last non-null element. */
|
||||
public final int end;
|
||||
|
||||
/** Simple constructor.
|
||||
* @param begin index in row/column count of the first non-null element
|
||||
* @param end index in row/column count after the last non-null element
|
||||
*/
|
||||
public NonNullRange(int begin, int end)
|
||||
{
|
||||
this.begin = begin;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* @param range range to copy.
|
||||
*/
|
||||
public NonNullRange(NonNullRange range) {
|
||||
begin = range.begin;
|
||||
end = range.end;
|
||||
}
|
||||
|
||||
/** Build the intersection of two ranges.
|
||||
* @param first first range to consider
|
||||
* @param second second range to consider
|
||||
*/
|
||||
public static NonNullRange intersection(NonNullRange first,
|
||||
NonNullRange second) {
|
||||
return new NonNullRange(Math.max(first.begin, second.begin),
|
||||
Math.min(first.end, second.end));
|
||||
}
|
||||
|
||||
/** Build the reunion of two ranges.
|
||||
* @param first first range to consider
|
||||
* @param second second range to consider
|
||||
*/
|
||||
public static NonNullRange reunion(NonNullRange first,
|
||||
NonNullRange second) {
|
||||
return new NonNullRange(Math.min(first.begin, second.begin),
|
||||
Math.max(first.end, second.end));
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 8175301560126132666L;
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.linalg;
|
||||
|
||||
import org.spaceroots.mantissa.MantissaException;
|
||||
|
||||
/** This class represent exceptions thrown by some matrix operations.
|
||||
|
||||
* @version $Id: SingularMatrixException.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class SingularMatrixException
|
||||
extends MantissaException {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an exception with a default message
|
||||
*/
|
||||
public SingularMatrixException() {
|
||||
super("singular matrix");
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 7531357987468317564L;
|
||||
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.linalg;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** This class factor all services common to square matrices of linear algebra.
|
||||
|
||||
* <p>This class is the base class of all square matrix
|
||||
* implementations. It extends the {@link Matrix} class with methods
|
||||
* specific to square matrices.</p>
|
||||
|
||||
* @version $Id: SquareMatrix.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public abstract class SquareMatrix
|
||||
extends Matrix
|
||||
implements Serializable, Cloneable {
|
||||
/** Simple constructor.
|
||||
* Build a matrix with null elements.
|
||||
* @param order order of the matrix
|
||||
*/
|
||||
protected SquareMatrix(int order) {
|
||||
super(order, order);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a matrix with specified elements.
|
||||
* @param order order of the matrix
|
||||
* @param data table of the matrix elements (stored row after row)
|
||||
*/
|
||||
protected SquareMatrix(int order, double[] data) {
|
||||
super(order, order, data);
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* @param m matrix to copy
|
||||
*/
|
||||
protected SquareMatrix(SquareMatrix m) {
|
||||
super(m);
|
||||
}
|
||||
|
||||
/** Get the determinant of the matrix.
|
||||
* @param epsilon threshold on matrix elements below which the
|
||||
* matrix is considered singular (this is used by the derived
|
||||
* classes that use a factorization to compute the determinant)
|
||||
* @return the determinant of the matrix
|
||||
*/
|
||||
public abstract double getDeterminant(double epsilon);
|
||||
|
||||
/** Invert the instance.
|
||||
* @param epsilon threshold on matrix elements below which the
|
||||
* matrix is considered singular
|
||||
* @return the inverse matrix of the instance
|
||||
* @exception SingularMatrixException if the matrix is singular
|
||||
*/
|
||||
public SquareMatrix getInverse(double epsilon)
|
||||
throws SingularMatrixException {
|
||||
return solve(new DiagonalMatrix (columns), epsilon);
|
||||
}
|
||||
|
||||
|
||||
/** Solve the <tt>A.X = B</tt> equation.
|
||||
* @param b second term of the equation
|
||||
* @param epsilon threshold on matrix elements below which the
|
||||
* matrix is considered singular
|
||||
* @return a matrix X such that <tt>A.X = B</tt>, where A is the instance
|
||||
* @exception SingularMatrixException if the matrix is singular
|
||||
*/
|
||||
public abstract Matrix solve(Matrix b, double epsilon)
|
||||
throws SingularMatrixException;
|
||||
|
||||
/** Solve the <tt>A.X = B</tt> equation.
|
||||
* @param b second term of the equation
|
||||
* @param epsilon threshold on matrix elements below which the
|
||||
* matrix is considered singular
|
||||
* @return a matrix X such that <tt>A.X = B</tt>, where A is the instance
|
||||
* @exception SingularMatrixException if the matrix is singular
|
||||
*/
|
||||
public SquareMatrix solve(SquareMatrix b, double epsilon)
|
||||
throws SingularMatrixException {
|
||||
return (SquareMatrix) solve((Matrix) b, epsilon);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.linalg;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** This class implements symetrical matrices of linear algebra.
|
||||
|
||||
* @version $Id: SymetricalMatrix.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class SymetricalMatrix
|
||||
extends GeneralSquareMatrix
|
||||
implements Serializable, Cloneable {
|
||||
|
||||
/** Simple constructor.
|
||||
* This constructor builds a symetrical matrix of specified order, all
|
||||
* elements beeing zeros.
|
||||
* @param order order of the matrix
|
||||
*/
|
||||
public SymetricalMatrix(int order) {
|
||||
super(order);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a matrix with specified elements.
|
||||
* @param order order of the matrix
|
||||
* @param data table of the matrix elements (stored row after row)
|
||||
*/
|
||||
public SymetricalMatrix(int order, double[] data) {
|
||||
super(order, data);
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* @param s square matrix to copy
|
||||
*/
|
||||
public SymetricalMatrix(SymetricalMatrix s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
/** Build the symetrical matrix resulting from the product w.A.At.
|
||||
* @param w multiplicative factor (weight)
|
||||
* @param a base vector used to compute the symetrical contribution
|
||||
*/
|
||||
public SymetricalMatrix(double w, double[] a) {
|
||||
super(a.length, new double[a.length * a.length]);
|
||||
|
||||
for (int i = 0; i < a.length; ++i) {
|
||||
int indexU = i * (columns + 1);
|
||||
int indexL = indexU;
|
||||
|
||||
double factor = w * a[i];
|
||||
data[indexU] = factor * a[i];
|
||||
|
||||
for (int j = i + 1; j < columns; ++j) {
|
||||
++indexU;
|
||||
indexL += columns;
|
||||
data[indexU] = factor * a[j];
|
||||
data[indexL] = data[indexU];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Matrix duplicate() {
|
||||
return new SymetricalMatrix(this);
|
||||
}
|
||||
|
||||
/** Set a matrix element.
|
||||
* On symetrical matrices, setting separately elements outside of
|
||||
* the diagonal is forbidden, so this method throws an
|
||||
* ArrayIndexOutOfBoundsException in this case. The {@link
|
||||
* #setElementAndSymetricalElement} can be used to set both elements
|
||||
* simultaneously.
|
||||
* @param i row index, from 0 to rows - 1
|
||||
* @param j column index, from 0 to cols - 1
|
||||
* @param value value of the element
|
||||
* @exception ArrayIndexOutOfBoundsException if the indices are wrong
|
||||
* @see #setElementAndSymetricalElement
|
||||
* @see Matrix#getElement
|
||||
*/
|
||||
public void setElement(int i, int j, double value) {
|
||||
if (i != j) {
|
||||
throw new ArrayIndexOutOfBoundsException("cannot separately set"
|
||||
+ " elements out of diagonal"
|
||||
+ " in a symetrical matrix");
|
||||
}
|
||||
super.setElement(i, j, value);
|
||||
}
|
||||
|
||||
/** Set both a matrix element and its symetrical element.
|
||||
* @param i row index of first element (column index of second
|
||||
* element), from 0 to order - 1
|
||||
* @param j column index of first element (row index of second
|
||||
* element), from 0 to order - 1
|
||||
* @param value value of the elements
|
||||
* @exception ArrayIndexOutOfBoundsException if the indices are wrong
|
||||
* @see #setElement
|
||||
* @see Matrix#getElement
|
||||
*/
|
||||
public void setElementAndSymetricalElement(int i, int j, double value) {
|
||||
super.setElement(i, j, value);
|
||||
if (i != j) {
|
||||
super.setElement(j, i, value);
|
||||
}
|
||||
}
|
||||
|
||||
/** Add a matrix to the instance.
|
||||
* This method adds a matrix to the instance. It does modify the instance.
|
||||
* @param s symetrical matrix to add
|
||||
* @exception IllegalArgumentException if there is a dimension mismatch
|
||||
*/
|
||||
public void selfAdd(SymetricalMatrix s) {
|
||||
|
||||
// validity check
|
||||
if ((rows != s.rows) || (columns != s.columns)) {
|
||||
throw new IllegalArgumentException("cannot add a "
|
||||
+ s.rows + 'x' + s.columns
|
||||
+ " matrix to a "
|
||||
+ rows + 'x' + columns
|
||||
+ " matrix");
|
||||
}
|
||||
|
||||
// addition loop
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
int indexU = i * (columns + 1);
|
||||
int indexL = indexU;
|
||||
|
||||
data[indexU] += s.data[indexU];
|
||||
|
||||
for (int j = i + 1; j < columns; ++j) {
|
||||
++indexU;
|
||||
indexL += columns;
|
||||
data[indexU] += s.data[indexU];
|
||||
data[indexL] = data[indexU];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Substract a matrix from the instance.
|
||||
* This method substracts a matrix from the instance. It does modify the instance.
|
||||
* @param s symetrical matrix to substract
|
||||
* @exception IllegalArgumentException if there is a dimension mismatch
|
||||
*/
|
||||
public void selfSub(SymetricalMatrix s) {
|
||||
|
||||
// validity check
|
||||
if ((rows != s.rows) || (columns != s.columns)) {
|
||||
throw new IllegalArgumentException("cannot substract a "
|
||||
+ s.rows + 'x' + s.columns
|
||||
+ " matrix from a "
|
||||
+ rows + 'x' + columns
|
||||
+ " matrix");
|
||||
}
|
||||
|
||||
// substraction loop
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
int indexU = i * (columns + 1);
|
||||
int indexL = indexU;
|
||||
|
||||
data[indexU] -= s.data[indexU];
|
||||
|
||||
for (int j = i + 1; j < columns; ++j) {
|
||||
++indexU;
|
||||
indexL += columns;
|
||||
data[indexU] -= s.data[indexU];
|
||||
data[indexL] = data[indexU];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Add the symetrical matrix resulting from the product w.A.At to the instance.
|
||||
* This method can be used to build progressively the matrices of
|
||||
* least square problems. The instance is modified.
|
||||
* @param w multiplicative factor (weight)
|
||||
* @param a base vector used to compute the symetrical contribution
|
||||
* @exception IllegalArgumentException if there is a dimension mismatch
|
||||
*/
|
||||
public void selfAddWAAt(double w, double[] a) {
|
||||
if (rows != a.length) {
|
||||
throw new IllegalArgumentException("cannot add a "
|
||||
+ a.length + 'x' + a.length
|
||||
+ " matrix to a "
|
||||
+ rows + 'x' + columns
|
||||
+ " matrix");
|
||||
}
|
||||
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
int indexU = i * (columns + 1);
|
||||
int indexL = indexU;
|
||||
|
||||
double factor = w * a[i];
|
||||
data[indexU] += factor * a[i];
|
||||
|
||||
for (int j = i + 1; j < columns; ++j) {
|
||||
++indexU;
|
||||
indexL += columns;
|
||||
data[indexU] += factor * a[j];
|
||||
data[indexL] = data[indexU];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -2083829252075519221L;
|
||||
|
||||
}
|
|
@ -0,0 +1,219 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.linalg;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** This class implements upper triangular matrices of linear algebra.
|
||||
|
||||
* @version $Id: UpperTriangularMatrix.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class UpperTriangularMatrix
|
||||
extends SquareMatrix
|
||||
implements Serializable, Cloneable {
|
||||
|
||||
/** Simple constructor.
|
||||
* This constructor builds a upper triangular matrix of specified order, all
|
||||
* elements being zeros.
|
||||
* @param order order of the matrix
|
||||
*/
|
||||
public UpperTriangularMatrix(int order) {
|
||||
super(order);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a matrix with specified elements.
|
||||
* @param order order of the matrix
|
||||
* @param data table of the matrix elements (stored row after row)
|
||||
*/
|
||||
public UpperTriangularMatrix(int order, double[] data) {
|
||||
super(order, data);
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* @param u upper triangular matrix to copy
|
||||
*/
|
||||
public UpperTriangularMatrix(UpperTriangularMatrix u) {
|
||||
super(u);
|
||||
}
|
||||
|
||||
public Matrix duplicate() {
|
||||
return new UpperTriangularMatrix(this);
|
||||
}
|
||||
|
||||
public void setElement(int i, int j, double value) {
|
||||
if (i > j) {
|
||||
throw new ArrayIndexOutOfBoundsException("cannot set elements"
|
||||
+ " below diagonal of a"
|
||||
+ " upper triangular matrix");
|
||||
}
|
||||
super.setElement(i, j, value);
|
||||
}
|
||||
|
||||
/** Add a matrix to the instance.
|
||||
* This method adds a matrix to the instance. It does modify the instance.
|
||||
* @param u upper triangular matrix to add
|
||||
* @exception IllegalArgumentException if there is a dimension mismatch
|
||||
*/
|
||||
public void selfAdd(UpperTriangularMatrix u) {
|
||||
|
||||
// validity check
|
||||
if ((rows != u.rows) || (columns != u.columns)) {
|
||||
throw new IllegalArgumentException("cannot add a "
|
||||
+ u.rows + 'x' + u.columns
|
||||
+ " matrix to a "
|
||||
+ rows + 'x' + columns
|
||||
+ " matrix");
|
||||
}
|
||||
|
||||
// addition loop
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
for (int index = i * (columns + 1); index < (i + 1) * columns; ++index) {
|
||||
data[index] += u.data[index];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Substract a matrix from the instance.
|
||||
* This method substract a matrix from the instance. It does modify the instance.
|
||||
* @param u upper triangular matrix to substract
|
||||
* @exception IllegalArgumentException if there is a dimension mismatch
|
||||
*/
|
||||
public void selfSub(UpperTriangularMatrix u) {
|
||||
|
||||
// validity check
|
||||
if ((rows != u.rows) || (columns != u.columns)) {
|
||||
throw new IllegalArgumentException("cannot substract a "
|
||||
+ u.rows + 'x' + u.columns
|
||||
+ " matrix from a "
|
||||
+ rows + 'x' + columns
|
||||
+ " matrix");
|
||||
}
|
||||
|
||||
// substraction loop
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
for (int index = i * (columns + 1); index < (i + 1) * columns; ++index) {
|
||||
data[index] -= u.data[index];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public double getDeterminant(double epsilon) {
|
||||
double determinant = data[0];
|
||||
for (int index = columns + 1; index < columns * columns; index += columns + 1) {
|
||||
determinant *= data[index];
|
||||
}
|
||||
return determinant;
|
||||
}
|
||||
|
||||
public Matrix solve(Matrix b, double epsilon)
|
||||
throws SingularMatrixException {
|
||||
// validity check
|
||||
if (b.getRows() != rows) {
|
||||
throw new IllegalArgumentException("dimension mismatch");
|
||||
}
|
||||
|
||||
// prepare the data storage
|
||||
int bRows = b.getRows();
|
||||
int bCols = b.getColumns();
|
||||
|
||||
double[] resultData = new double[bRows * bCols];
|
||||
int resultIndex = bRows * bCols - 1;
|
||||
int lowerElements = 0;
|
||||
int upperElements = 0;
|
||||
int minJ = columns;
|
||||
int maxJ = 0;
|
||||
|
||||
// solve the linear system
|
||||
for (int i = rows - 1; i >= 0; --i) {
|
||||
double diag = data[i * (columns + 1)];
|
||||
if (Math.abs(diag) < epsilon) {
|
||||
throw new SingularMatrixException();
|
||||
}
|
||||
double inv = 1.0 / diag;
|
||||
|
||||
NonNullRange range = b.getRangeForRow(i);
|
||||
minJ = Math.min(minJ, range.begin);
|
||||
maxJ = Math.max(maxJ, range.end);
|
||||
|
||||
int j = bCols - 1;
|
||||
while (j >= maxJ) {
|
||||
resultData[resultIndex] = 0.0;
|
||||
--resultIndex;
|
||||
--j;
|
||||
}
|
||||
|
||||
// compute the possibly non null elements
|
||||
int bIndex = i * bCols + maxJ - 1;
|
||||
while (j >= minJ) {
|
||||
|
||||
// compute the current element
|
||||
int index1 = (i + 1) * columns - 1;
|
||||
int index2 = (bRows - 1) * bCols + j;
|
||||
double value = b.data[bIndex];
|
||||
while (index1 >= i * (columns + 1)) {
|
||||
value -= data[index1] * resultData[index2];
|
||||
--index1;
|
||||
index2 -= bCols;
|
||||
}
|
||||
value *= inv;
|
||||
resultData[resultIndex] = value;
|
||||
|
||||
// count the affected upper and lower elements
|
||||
// (in order to deduce the shape of the resulting matrix)
|
||||
if (j < i) {
|
||||
++lowerElements;
|
||||
} else if (i < j) {
|
||||
++upperElements;
|
||||
}
|
||||
|
||||
--bIndex;
|
||||
--resultIndex;
|
||||
--j;
|
||||
|
||||
}
|
||||
|
||||
while (j >= 0) {
|
||||
resultData[resultIndex] = 0.0;
|
||||
--resultIndex;
|
||||
--j;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return MatrixFactory.buildMatrix(bRows, bCols, resultData,
|
||||
lowerElements, upperElements);
|
||||
|
||||
}
|
||||
|
||||
public NonNullRange getRangeForRow(int i) {
|
||||
return new NonNullRange (i, columns);
|
||||
}
|
||||
|
||||
public NonNullRange getRangeForColumn(int j) {
|
||||
return new NonNullRange (0, j + 1);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -197266611942032237L;
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version = "1.0" encoding = "ISO-8859-1" ?>
|
||||
<!DOCTYPE argo SYSTEM "argo.dtd" >
|
||||
<argo>
|
||||
<documentation>
|
||||
<authorname></authorname>
|
||||
<version></version>
|
||||
<description>
|
||||
|
||||
</description>
|
||||
</documentation>
|
||||
|
||||
<searchpath href="PROJECT_DIR" />
|
||||
<member
|
||||
type="pgml"
|
||||
name="linalg_classdiagram1.pgml"
|
||||
/>
|
||||
<member
|
||||
type="xmi"
|
||||
name="linalg.xmi"
|
||||
/>
|
||||
<historyfile name="" />
|
||||
<stats>
|
||||
<stat name="clicksInToDoPane"
|
||||
value="0" />
|
||||
<stat name="dblClicksInToDoPane"
|
||||
value="0" />
|
||||
<stat name="longestToDoList"
|
||||
value="48" />
|
||||
<stat name="longestAdd"
|
||||
value="0" />
|
||||
<stat name="longestHot"
|
||||
value="0" />
|
||||
<stat name="numCriticsFired"
|
||||
value="17738" />
|
||||
<stat name="numNotValid"
|
||||
value="4" />
|
||||
<stat name="numCriticsApplied"
|
||||
value="0" />
|
||||
<stat name="toDoPerspectivesChanged"
|
||||
value="1" />
|
||||
<stat name="navPerspectivesChanged"
|
||||
value="5" />
|
||||
<stat name="clicksInNavPane"
|
||||
value="3" />
|
||||
<stat name="numFinds"
|
||||
value="1" />
|
||||
<stat name="numJumpToRelated"
|
||||
value="0" />
|
||||
<stat name="numDecisionModel"
|
||||
value="0" />
|
||||
<stat name="numGoalsModel"
|
||||
value="0" />
|
||||
<stat name="numCriticBrowser"
|
||||
value="0" />
|
||||
<stat name="numNavConfig"
|
||||
value="0" />
|
||||
<stat name="numHushes"
|
||||
value="0" />
|
||||
<stat name="numChecks"
|
||||
value="0" />
|
||||
<stat name="Num_Button_Clicks"
|
||||
value="0" />
|
||||
<stat name="Drags_To_New"
|
||||
value="0" />
|
||||
<stat name="Drags_To_Existing"
|
||||
value="0" />
|
||||
</stats>
|
||||
</argo>
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -0,0 +1,21 @@
|
|||
<html>
|
||||
<body>
|
||||
This package provides classes to perform linear algebra computation.
|
||||
|
||||
<p>It is by no means a complete linear algebra system, it is
|
||||
sufficient to solve least squares problems and linear equations
|
||||
systems, but it lacks lots of functionalities and matrices types (for
|
||||
example sparse matrices are not supported).</p>
|
||||
|
||||
<p>The class diagram for the public classes of this package is
|
||||
displayed below. The user will mainly use directly the implementation
|
||||
classes rather than the abstract {@link
|
||||
org.spaceroots.mantissa.linalg.Matrix} class. The shape of the matrices
|
||||
used is often known in the algorithms so there is little need to hide
|
||||
this shape behind the general class.</p>
|
||||
|
||||
<img src="doc-files/org_spaceroots_mantissa_linalg_classes.png" />
|
||||
|
||||
@author L. Maisonobe
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,433 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
/** This abstract class represents an interpolator over the last step
|
||||
* during an ODE integration.
|
||||
*
|
||||
* <p>The various ODE integrators provide objects extending this class
|
||||
* to the step handlers. The handlers can use these objects to
|
||||
* retrieve the state vector at intermediate times between the
|
||||
* previous and the current grid points (dense output).</p>
|
||||
*
|
||||
* @see FirstOrderIntegrator
|
||||
* @see SecondOrderIntegrator
|
||||
* @see StepHandler
|
||||
*
|
||||
* @version $Id: AbstractStepInterpolator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
*
|
||||
*/
|
||||
|
||||
public abstract class AbstractStepInterpolator
|
||||
implements StepInterpolator, Cloneable {
|
||||
|
||||
/** previous time */
|
||||
protected double previousTime;
|
||||
|
||||
/** current time */
|
||||
protected double currentTime;
|
||||
|
||||
/** current time step */
|
||||
protected double h;
|
||||
|
||||
/** current state */
|
||||
protected double[] currentState;
|
||||
|
||||
/** interpolated time */
|
||||
protected double interpolatedTime;
|
||||
|
||||
/** interpolated state */
|
||||
protected double[] interpolatedState;
|
||||
|
||||
/** indicate if the step has been finalized or not. */
|
||||
private boolean finalized;
|
||||
|
||||
/** integration direction. */
|
||||
private boolean forward;
|
||||
|
||||
/** Simple constructor.
|
||||
* This constructor builds an instance that is not usable yet, the
|
||||
* {@link #reinitialize} method should be called before using the
|
||||
* instance in order to initialize the internal arrays. This
|
||||
* constructor is used only in order to delay the initialization in
|
||||
* some cases. As an example, the {@link
|
||||
* RungeKuttaFehlbergIntegrator} uses the prototyping design pattern
|
||||
* to create the step interpolators by cloning an uninitialized
|
||||
* model and latter initializing the copy.
|
||||
*/
|
||||
protected AbstractStepInterpolator() {
|
||||
previousTime = Double.NaN;
|
||||
currentTime = Double.NaN;
|
||||
h = Double.NaN;
|
||||
interpolatedTime = Double.NaN;
|
||||
currentState = null;
|
||||
interpolatedState = null;
|
||||
finalized = false;
|
||||
this.forward = true;
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* @param y reference to the integrator array holding the state at
|
||||
* the end of the step
|
||||
* @param forward integration direction indicator
|
||||
*/
|
||||
protected AbstractStepInterpolator(double[] y, boolean forward) {
|
||||
|
||||
previousTime = Double.NaN;
|
||||
currentTime = Double.NaN;
|
||||
h = Double.NaN;
|
||||
interpolatedTime = Double.NaN;
|
||||
|
||||
currentState = y;
|
||||
interpolatedState = new double[y.length];
|
||||
|
||||
finalized = false;
|
||||
this.forward = forward;
|
||||
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
|
||||
* <p>The copied interpolator should have been finalized before the
|
||||
* copy, otherwise the copy will not be able to perform correctly
|
||||
* any derivative computation and will throw a {@link
|
||||
* NullPointerException} later. Since we don't want this constructor
|
||||
* to throw the exceptions finalization may involve and since we
|
||||
* don't want this method to modify the state of the copied
|
||||
* interpolator, finalization is <strong>not</strong> done
|
||||
* automatically, it remains under user control.</p>
|
||||
|
||||
* <p>The copy is a deep copy: its arrays are separated from the
|
||||
* original arrays of the instance.</p>
|
||||
|
||||
* @param interpolator interpolator to copy from.
|
||||
|
||||
*/
|
||||
protected AbstractStepInterpolator(AbstractStepInterpolator interpolator) {
|
||||
|
||||
previousTime = interpolator.previousTime;
|
||||
currentTime = interpolator.currentTime;
|
||||
h = interpolator.h;
|
||||
interpolatedTime = interpolator.interpolatedTime;
|
||||
|
||||
if (interpolator.currentState != null) {
|
||||
int dimension = interpolator.currentState.length;
|
||||
|
||||
currentState = new double[dimension];
|
||||
System.arraycopy(interpolator.currentState, 0, currentState, 0,
|
||||
dimension);
|
||||
|
||||
interpolatedState = new double[dimension];
|
||||
System.arraycopy(interpolator.interpolatedState, 0, interpolatedState, 0,
|
||||
dimension);
|
||||
} else {
|
||||
currentState = null;
|
||||
interpolatedState = null;
|
||||
}
|
||||
|
||||
finalized = interpolator.finalized;
|
||||
forward = interpolator.forward;
|
||||
|
||||
}
|
||||
|
||||
/** Reinitialize the instance
|
||||
* @param y reference to the integrator array holding the state at
|
||||
* the end of the step
|
||||
* @param forward integration direction indicator
|
||||
*/
|
||||
protected void reinitialize(double[] y, boolean forward) {
|
||||
|
||||
previousTime = Double.NaN;
|
||||
currentTime = Double.NaN;
|
||||
h = Double.NaN;
|
||||
interpolatedTime = Double.NaN;
|
||||
|
||||
currentState = y;
|
||||
interpolatedState = new double[y.length];
|
||||
|
||||
finalized = false;
|
||||
this.forward = forward;
|
||||
|
||||
}
|
||||
|
||||
/** Copy the instance.
|
||||
|
||||
* <p>The copied interpolator should have been finalized before the
|
||||
* copy, otherwise the copy will not be able to perform correctly any
|
||||
* interpolation and will throw a {@link NullPointerException}
|
||||
* later. Since we don't want this constructor to throw the
|
||||
* exceptions finalization may involve and since we don't want this
|
||||
* method to modify the state of the copied interpolator,
|
||||
* finalization is <strong>not</strong> done automatically, it
|
||||
* remains under user control.</p>
|
||||
|
||||
* <p>The copy is a deep copy: its arrays are separated from the
|
||||
* original arrays of the instance.</p>
|
||||
|
||||
* <p>This method has been redeclared as public instead of protected.</p>
|
||||
|
||||
* @return a copy of the instance.
|
||||
|
||||
*/
|
||||
public abstract Object clone();
|
||||
|
||||
/** Shift one step forward.
|
||||
* Copy the current time into the previous time, hence preparing the
|
||||
* interpolator for future calls to {@link #storeTime storeTime}
|
||||
*/
|
||||
public void shift() {
|
||||
previousTime = currentTime;
|
||||
}
|
||||
|
||||
/** Store the current step time.
|
||||
* @param t current time
|
||||
*/
|
||||
public void storeTime(double t) {
|
||||
|
||||
currentTime = t;
|
||||
h = currentTime - previousTime;
|
||||
interpolatedTime = t;
|
||||
System.arraycopy(currentState, 0, interpolatedState, 0,
|
||||
currentState.length);
|
||||
|
||||
// the step is not finalized anymore
|
||||
finalized = false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the previous grid point time.
|
||||
* @return previous grid point time
|
||||
*/
|
||||
public double getPreviousTime() {
|
||||
return previousTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current grid point time.
|
||||
* @return current grid point time
|
||||
*/
|
||||
public double getCurrentTime() {
|
||||
return currentTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time of the interpolated point.
|
||||
* If {@link #setInterpolatedTime} has not been called, it returns
|
||||
* the current grid point time.
|
||||
* @return interpolation point time
|
||||
*/
|
||||
public double getInterpolatedTime() {
|
||||
return interpolatedTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time of the interpolated point.
|
||||
* <p>Setting the time outside of the current step is now allowed
|
||||
* (it was not allowed up to version 5.4 of Mantissa), but should be
|
||||
* used with care since the accuracy of the interpolator will
|
||||
* probably be very poor far from this step. This allowance has been
|
||||
* added to simplify implementation of search algorithms near the
|
||||
* step endpoints.</p>
|
||||
* @param time time of the interpolated point
|
||||
* @throws DerivativeException if this call induces an automatic
|
||||
* step finalization that throws one
|
||||
*/
|
||||
public void setInterpolatedTime(double time)
|
||||
throws DerivativeException {
|
||||
interpolatedTime = time;
|
||||
double oneMinusThetaH = currentTime - interpolatedTime;
|
||||
computeInterpolatedState((h - oneMinusThetaH) / h, oneMinusThetaH);
|
||||
}
|
||||
|
||||
/** Check if the natural integration direction is forward.
|
||||
* <p>This method provides the integration direction as specified by the
|
||||
* integrator itself, it avoid some nasty problems in degenerated
|
||||
* cases like null steps due to cancellation at step initialization,
|
||||
* step control or switching function triggering.</p>
|
||||
* @return true if the integration variable (time) increases during
|
||||
* integration
|
||||
*/
|
||||
public boolean isForward() {
|
||||
return forward;
|
||||
}
|
||||
|
||||
/** Compute the state at the interpolated time.
|
||||
* This is the main processing method that should be implemented by
|
||||
* the derived classes to perform the interpolation.
|
||||
* @param theta normalized interpolation abscissa within the step
|
||||
* (theta is zero at the previous time step and one at the current time step)
|
||||
* @param oneMinusThetaH time gap between the interpolated time and
|
||||
* the current time
|
||||
* @throws DerivativeException this exception is propagated to the caller if the
|
||||
* underlying user function triggers one
|
||||
*/
|
||||
protected abstract void computeInterpolatedState(double theta,
|
||||
double oneMinusThetaH)
|
||||
throws DerivativeException;
|
||||
|
||||
/**
|
||||
* Get the state vector of the interpolated point.
|
||||
* @return state vector at time {@link #getInterpolatedTime}
|
||||
*/
|
||||
public double[] getInterpolatedState() {
|
||||
return interpolatedState;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finalize the step.
|
||||
|
||||
* <p>Some Runge-Kutta-Fehlberg integrators need fewer functions
|
||||
* evaluations than their counterpart step interpolators. These
|
||||
* interpolators should perform the last evaluations they need by
|
||||
* themselves only if they need them. This method triggers these
|
||||
* extra evaluations. It can be called directly by the user step
|
||||
* handler and it is called automatically if {@link
|
||||
* #setInterpolatedTime} is called.</p>
|
||||
|
||||
* <p>Once this method has been called, <strong>no</strong> other
|
||||
* evaluation will be performed on this step. If there is a need to
|
||||
* have some side effects between the step handler and the
|
||||
* differential equations (for example update some data in the
|
||||
* equations once the step has been done), it is advised to call
|
||||
* this method explicitly from the step handler before these side
|
||||
* effects are set up. If the step handler induces no side effect,
|
||||
* then this method can safely be ignored, it will be called
|
||||
* transparently as needed.</p>
|
||||
|
||||
* <p><strong>Warning</strong>: since the step interpolator provided
|
||||
* to the step handler as a parameter of the {@link
|
||||
* StepHandler#handleStep handleStep} is valid only for the duration
|
||||
* of the {@link StepHandler#handleStep handleStep} call, one cannot
|
||||
* simply store a reference and reuse it later. One should first
|
||||
* finalize the instance, then copy this finalized instance into a
|
||||
* new object that can be kept.</p>
|
||||
|
||||
* <p>This method calls the protected {@link #doFinalize doFinalize}
|
||||
* method if it has never been called during this step and set a
|
||||
* flag indicating that it has been called once. It is the {@link
|
||||
* #doFinalize doFinalize} method which should perform the
|
||||
* evaluations. This wrapping prevents from calling {@link
|
||||
* #doFinalize doFinalize} several times and hence evaluating the
|
||||
* differential equations too often. Therefore, subclasses are not
|
||||
* allowed not reimplement it, they should rather reimplement {@link
|
||||
* #doFinalize doFinalize}.</p>
|
||||
|
||||
* @throws DerivativeException this exception is propagated to the
|
||||
* caller if the underlying user function triggers one
|
||||
|
||||
*/
|
||||
public final void finalizeStep()
|
||||
throws DerivativeException {
|
||||
if (! finalized) {
|
||||
doFinalize();
|
||||
finalized = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Really finalize the step.
|
||||
* The default implementation of this method does nothing.
|
||||
* @throws DerivativeException this exception is propagated to the
|
||||
* caller if the underlying user function triggers one
|
||||
*/
|
||||
protected void doFinalize()
|
||||
throws DerivativeException {
|
||||
}
|
||||
|
||||
public abstract void writeExternal(ObjectOutput out)
|
||||
throws IOException;
|
||||
|
||||
public abstract void readExternal(ObjectInput in)
|
||||
throws IOException;
|
||||
|
||||
/** Save the base state of the instance.
|
||||
* This method performs step finalization if it has not been done
|
||||
* before.
|
||||
* @param out stream where to save the state
|
||||
* @exception IOException in case of write error
|
||||
*/
|
||||
protected void writeBaseExternal(ObjectOutput out)
|
||||
throws IOException {
|
||||
|
||||
out.writeInt(currentState.length);
|
||||
out.writeDouble(previousTime);
|
||||
out.writeDouble(currentTime);
|
||||
out.writeDouble(h);
|
||||
out.writeBoolean(forward);
|
||||
|
||||
for (int i = 0; i < currentState.length; ++i) {
|
||||
out.writeDouble(currentState[i]);
|
||||
}
|
||||
|
||||
out.writeDouble(interpolatedTime);
|
||||
|
||||
// we do not store the interpolated state,
|
||||
// it will be recomputed as needed after reading
|
||||
|
||||
// finalize the step (and don't bother saving the now true flag)
|
||||
try {
|
||||
finalizeStep();
|
||||
} catch (DerivativeException e) {
|
||||
IOException ioe = new IOException();
|
||||
ioe.initCause(e);
|
||||
throw ioe;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Read the base state of the instance.
|
||||
* This method does <strong>neither</strong> set the interpolated
|
||||
* time nor state. It is up to the derived class to reset it
|
||||
* properly calling the {@link #setInterpolatedTime} method later,
|
||||
* once all rest of the object state has been set up properly.
|
||||
* @param in stream where to read the state from
|
||||
* @return interpolated time be set later by the caller
|
||||
* @exception IOException in case of read error
|
||||
*/
|
||||
protected double readBaseExternal(ObjectInput in)
|
||||
throws IOException {
|
||||
|
||||
int dimension = in.readInt();
|
||||
previousTime = in.readDouble();
|
||||
currentTime = in.readDouble();
|
||||
h = in.readDouble();
|
||||
forward = in.readBoolean();
|
||||
|
||||
currentState = new double[dimension];
|
||||
for (int i = 0; i < currentState.length; ++i) {
|
||||
currentState[i] = in.readDouble();
|
||||
}
|
||||
|
||||
// we do NOT handle the interpolated time and state here
|
||||
interpolatedTime = Double.NaN;
|
||||
interpolatedState = new double[dimension];
|
||||
|
||||
finalized = true;
|
||||
|
||||
return in.readDouble();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,317 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This abstract class holds the common part of all adaptive
|
||||
* stepsize integrators for Ordinary Differential Equations.
|
||||
|
||||
* <p>These algorithms perform integration with stepsize control, which
|
||||
* means the user does not specify the integration step but rather a
|
||||
* tolerance on error. The error threshold is computed as
|
||||
* <pre>
|
||||
* threshold_i = absTol_i + relTol_i * max (abs (ym), abs (ym+1))
|
||||
* </pre>
|
||||
* where absTol_i is the absolute tolerance for component i of the
|
||||
* state vector and relTol_i is the relative tolerance for the same
|
||||
* component. The user can also use only two scalar values absTol and
|
||||
* relTol which will be used for all components.</p>
|
||||
|
||||
* <p>If the estimated error for ym+1 is such that
|
||||
* <pre>
|
||||
* sqrt((sum (errEst_i / threshold_i)^2 ) / n) < 1
|
||||
* </pre>
|
||||
|
||||
* (where n is the state vector dimension) then the step is accepted,
|
||||
* otherwise the step is rejected and a new attempt is made with a new
|
||||
* stepsize.</p>
|
||||
|
||||
* @version $Id: AdaptiveStepsizeIntegrator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public abstract class AdaptiveStepsizeIntegrator
|
||||
implements FirstOrderIntegrator {
|
||||
|
||||
/** Build an integrator with the given stepsize bounds.
|
||||
* The default step handler does nothing.
|
||||
* @param minStep minimal step (must be positive even for backward
|
||||
* integration), the last step can be smaller than this
|
||||
* @param maxStep maximal step (must be positive even for backward
|
||||
* integration)
|
||||
* @param scalAbsoluteTolerance allowed absolute error
|
||||
* @param scalRelativeTolerance allowed relative error
|
||||
*/
|
||||
public AdaptiveStepsizeIntegrator(double minStep, double maxStep,
|
||||
double scalAbsoluteTolerance,
|
||||
double scalRelativeTolerance) {
|
||||
|
||||
this.minStep = minStep;
|
||||
this.maxStep = maxStep;
|
||||
this.initialStep = -1.0;
|
||||
|
||||
this.scalAbsoluteTolerance = scalAbsoluteTolerance;
|
||||
this.scalRelativeTolerance = scalRelativeTolerance;
|
||||
this.vecAbsoluteTolerance = null;
|
||||
this.vecRelativeTolerance = null;
|
||||
|
||||
// set the default step handler
|
||||
handler = DummyStepHandler.getInstance();
|
||||
|
||||
switchesHandler = new SwitchingFunctionsHandler();
|
||||
|
||||
}
|
||||
|
||||
/** Build an integrator with the given stepsize bounds.
|
||||
* The default step handler does nothing.
|
||||
* @param minStep minimal step (must be positive even for backward
|
||||
* integration), the last step can be smaller than this
|
||||
* @param maxStep maximal step (must be positive even for backward
|
||||
* integration)
|
||||
* @param vecAbsoluteTolerance allowed absolute error
|
||||
* @param vecRelativeTolerance allowed relative error
|
||||
*/
|
||||
public AdaptiveStepsizeIntegrator(double minStep, double maxStep,
|
||||
double[] vecAbsoluteTolerance,
|
||||
double[] vecRelativeTolerance) {
|
||||
|
||||
this.minStep = minStep;
|
||||
this.maxStep = maxStep;
|
||||
this.initialStep = -1.0;
|
||||
|
||||
this.scalAbsoluteTolerance = 0;
|
||||
this.scalRelativeTolerance = 0;
|
||||
this.vecAbsoluteTolerance = vecAbsoluteTolerance;
|
||||
this.vecRelativeTolerance = vecRelativeTolerance;
|
||||
|
||||
// set the default step handler
|
||||
handler = DummyStepHandler.getInstance();
|
||||
|
||||
switchesHandler = new SwitchingFunctionsHandler();
|
||||
|
||||
}
|
||||
|
||||
/** Set the initial step size.
|
||||
* <p>This method allows the user to specify an initial positive
|
||||
* step size instead of letting the integrator guess it by
|
||||
* itself. If this method is not called before integration is
|
||||
* started, the initial step size will be estimated by the
|
||||
* integrator.</p>
|
||||
* @param initialStepSize initial step size to use (must be positive even
|
||||
* for backward integration ; providing a negative value or a value
|
||||
* outside of the min/max step interval will lead the integrator to
|
||||
* ignore the value and compute the initial step size by itself)
|
||||
*/
|
||||
public void setInitialStepSize(double initialStepSize) {
|
||||
if ((initialStepSize < minStep) || (initialStepSize > maxStep)) {
|
||||
initialStep = -1.0;
|
||||
} else {
|
||||
initialStep = initialStepSize;
|
||||
}
|
||||
}
|
||||
|
||||
/** Set the step handler for this integrator.
|
||||
* The handler will be called by the integrator for each accepted
|
||||
* step.
|
||||
* @param handler handler for the accepted steps
|
||||
*/
|
||||
public void setStepHandler (StepHandler handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
/** Get the step handler for this integrator.
|
||||
* @return the step handler for this integrator
|
||||
*/
|
||||
public StepHandler getStepHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
/** Add a switching function to the integrator.
|
||||
* @param function switching function
|
||||
* @param maxCheckInterval maximal time interval between switching
|
||||
* function checks (this interval prevents missing sign changes in
|
||||
* case the integration steps becomes very large)
|
||||
* @param convergence convergence threshold in the event time search
|
||||
*/
|
||||
public void addSwitchingFunction(SwitchingFunction function,
|
||||
double maxCheckInterval,
|
||||
double convergence) {
|
||||
switchesHandler.add(function, maxCheckInterval, convergence);
|
||||
}
|
||||
|
||||
/** Initialize the integration step.
|
||||
* @param equations differential equations set
|
||||
* @param forward forward integration indicator
|
||||
* @param order order of the method
|
||||
* @param scale scaling vector for the state vector
|
||||
* @param t0 start time
|
||||
* @param y0 state vector at t0
|
||||
* @param yDot0 first time derivative of y0
|
||||
* @param y1 work array for a state vector
|
||||
* @param yDot1 work array for the first time derivative of y1
|
||||
* @return first integration step
|
||||
* @exception DerivativeException this exception is propagated to
|
||||
* the caller if the underlying user function triggers one
|
||||
*/
|
||||
public double initializeStep(FirstOrderDifferentialEquations equations,
|
||||
boolean forward, int order, double[] scale,
|
||||
double t0, double[] y0, double[] yDot0,
|
||||
double[] y1, double[] yDot1)
|
||||
throws DerivativeException {
|
||||
|
||||
if (initialStep > 0) {
|
||||
// use the user provided value
|
||||
return forward ? initialStep : -initialStep;
|
||||
}
|
||||
|
||||
// very rough first guess : h = 0.01 * ||y/scale|| / ||y'/scale||
|
||||
// this guess will be used to perform an Euler step
|
||||
double ratio;
|
||||
double yOnScale2 = 0;
|
||||
double yDotOnScale2 = 0;
|
||||
for (int j = 0; j < y0.length; ++j) {
|
||||
ratio = y0[j] / scale[j];
|
||||
yOnScale2 += ratio * ratio;
|
||||
ratio = yDot0[j] / scale[j];
|
||||
yDotOnScale2 += ratio * ratio;
|
||||
}
|
||||
|
||||
double h = ((yOnScale2 < 1.0e-10) || (yDotOnScale2 < 1.0e-10))
|
||||
? 1.0e-6 : (0.01 * Math.sqrt(yOnScale2 / yDotOnScale2));
|
||||
if (! forward) {
|
||||
h = -h;
|
||||
}
|
||||
|
||||
// perform an Euler step using the preceding rough guess
|
||||
for (int j = 0; j < y0.length; ++j) {
|
||||
y1[j] = y0[j] + h * yDot0[j];
|
||||
}
|
||||
equations.computeDerivatives(t0 + h, y1, yDot1);
|
||||
|
||||
// estimate the second derivative of the solution
|
||||
double yDDotOnScale = 0;
|
||||
for (int j = 0; j < y0.length; ++j) {
|
||||
ratio = (yDot1[j] - yDot0[j]) / scale[j];
|
||||
yDDotOnScale += ratio * ratio;
|
||||
}
|
||||
yDDotOnScale = Math.sqrt(yDDotOnScale) / h;
|
||||
|
||||
// step size is computed such that
|
||||
// h^order * max (||y'/tol||, ||y''/tol||) = 0.01
|
||||
double maxInv2 = Math.max(Math.sqrt(yDotOnScale2), yDDotOnScale);
|
||||
double h1 = (maxInv2 < 1.0e-15)
|
||||
? Math.max(1.0e-6, 0.001 * Math.abs(h))
|
||||
: Math.pow(0.01 / maxInv2, 1.0 / order);
|
||||
h = Math.min(100.0 * Math.abs(h), h1);
|
||||
h = Math.max(h, 1.0e-12 * Math.abs(t0)); // avoids cancellation when computing t1 - t0
|
||||
if (h < getMinStep()) {
|
||||
h = getMinStep();
|
||||
}
|
||||
if (h > getMaxStep()) {
|
||||
h = getMaxStep();
|
||||
}
|
||||
if (! forward) {
|
||||
h = -h;
|
||||
}
|
||||
|
||||
return h;
|
||||
|
||||
}
|
||||
|
||||
/** Filter the integration step.
|
||||
* @param h signed step
|
||||
* @param acceptSmall if true, steps smaller than the minimal value
|
||||
* are silently increased up to this value, if false such small
|
||||
* steps generate an exception
|
||||
* @return a bounded integration step (h if no bound is reach, or a bounded value)
|
||||
* @exception IntegratorException if the step is too small and acceptSmall is false
|
||||
*/
|
||||
protected double filterStep(double h, boolean acceptSmall)
|
||||
throws IntegratorException {
|
||||
|
||||
if (Math.abs(h) < minStep) {
|
||||
if (acceptSmall) {
|
||||
h = (h < 0) ? -minStep : minStep;
|
||||
} else {
|
||||
throw new IntegratorException("minimal step size ({0}) reached,"
|
||||
+ " integration needs {1}",
|
||||
new String[] {
|
||||
Double.toString(minStep),
|
||||
Double.toString(Math.abs(h))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (h > maxStep) {
|
||||
h = maxStep;
|
||||
} else if (h < -maxStep) {
|
||||
h = -maxStep;
|
||||
}
|
||||
|
||||
return h;
|
||||
|
||||
}
|
||||
|
||||
public abstract void integrate (FirstOrderDifferentialEquations equations,
|
||||
double t0, double[] y0,
|
||||
double t, double[] y)
|
||||
throws DerivativeException, IntegratorException;
|
||||
|
||||
/** Get the minimal step.
|
||||
* @return minimal step
|
||||
*/
|
||||
public double getMinStep() {
|
||||
return minStep;
|
||||
}
|
||||
|
||||
/** Get the maximal step.
|
||||
* @return maximal step
|
||||
*/
|
||||
public double getMaxStep() {
|
||||
return maxStep;
|
||||
}
|
||||
|
||||
/** Minimal step. */
|
||||
private double minStep;
|
||||
|
||||
/** Maximal step. */
|
||||
private double maxStep;
|
||||
|
||||
/** User supplied initial step. */
|
||||
private double initialStep;
|
||||
|
||||
/** Allowed absolute scalar error. */
|
||||
protected double scalAbsoluteTolerance;
|
||||
|
||||
/** Allowed relative scalar error. */
|
||||
protected double scalRelativeTolerance;
|
||||
|
||||
/** Allowed absolute vectorial error. */
|
||||
protected double[] vecAbsoluteTolerance;
|
||||
|
||||
/** Allowed relative vectorial error. */
|
||||
protected double[] vecRelativeTolerance;
|
||||
|
||||
/** Step handler. */
|
||||
protected StepHandler handler;
|
||||
|
||||
/** Switching functions handler. */
|
||||
protected SwitchingFunctionsHandler switchesHandler;
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This class implements the classical fourth order Runge-Kutta
|
||||
* integrator for Ordinary Differential Equations (it is the most
|
||||
* often used Runge-Kutta method).
|
||||
|
||||
* <p>This method is an explicit Runge-Kutta method, its Butcher-array
|
||||
* is the following one :
|
||||
* <pre>
|
||||
* 0 | 0 0 0 0
|
||||
* 1/2 | 1/2 0 0 0
|
||||
* 1/2 | 0 1/2 0 0
|
||||
* 1 | 0 0 1 0
|
||||
* |--------------------
|
||||
* | 1/6 1/3 1/3 1/6
|
||||
* </pre>
|
||||
* </p>
|
||||
|
||||
* @see EulerIntegrator
|
||||
* @see GillIntegrator
|
||||
* @see MidpointIntegrator
|
||||
* @see ThreeEighthesIntegrator
|
||||
|
||||
* @version $Id: ClassicalRungeKuttaIntegrator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class ClassicalRungeKuttaIntegrator
|
||||
extends RungeKuttaIntegrator {
|
||||
|
||||
private static final String methodName = new String("classical Runge-Kutta");
|
||||
|
||||
private static final double[] c = {
|
||||
1.0 / 2.0, 1.0 / 2.0, 1.0
|
||||
};
|
||||
|
||||
private static final double[][] a = {
|
||||
{ 1.0 / 2.0 },
|
||||
{ 0.0, 1.0 / 2.0 },
|
||||
{ 0.0, 0.0, 1.0 }
|
||||
};
|
||||
|
||||
private static final double[] b = {
|
||||
1.0 / 6.0, 1.0 / 3.0, 1.0 / 3.0, 1.0 / 6.0
|
||||
};
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a fourth-order Runge-Kutta integrator with the given
|
||||
* step.
|
||||
* @param step integration step
|
||||
*/
|
||||
public ClassicalRungeKuttaIntegrator(double step) {
|
||||
super(false, c, a, b, new ClassicalRungeKuttaStepInterpolator(), step);
|
||||
}
|
||||
|
||||
/** Get the name of the method.
|
||||
* @return name of the method
|
||||
*/
|
||||
public String getName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This class implements a step interpolator for the classical fourth
|
||||
* order Runge-Kutta integrator.
|
||||
|
||||
* <p>This interpolator allows to compute dense output inside the last
|
||||
* step computed. The interpolation equation is consistent with the
|
||||
* integration scheme :
|
||||
|
||||
* <pre>
|
||||
* y(t_n + theta h) = y (t_n + h)
|
||||
* + (1 - theta) (h/6) [ (-4 theta^2 + 5 theta - 1) y'_1
|
||||
* +(4 theta^2 - 2 theta - 2) (y'_2 + y'_3)
|
||||
* -(4 theta^2 + theta + 1) y'_4
|
||||
* ]
|
||||
* </pre>
|
||||
|
||||
* where theta belongs to [0 ; 1] and where y'_1 to y'_4 are the four
|
||||
* evaluations of the derivatives already computed during the
|
||||
* step.</p>
|
||||
|
||||
* @see ClassicalRungeKuttaIntegrator
|
||||
|
||||
* @version $Id: ClassicalRungeKuttaStepInterpolator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
class ClassicalRungeKuttaStepInterpolator
|
||||
extends RungeKuttaStepInterpolator {
|
||||
|
||||
/** Simple constructor.
|
||||
* This constructor builds an instance that is not usable yet, the
|
||||
* {@link RungeKuttaStepInterpolator#reinitialize} method should be
|
||||
* called before using the instance in order to initialize the
|
||||
* internal arrays. This constructor is used only in order to delay
|
||||
* the initialization in some cases. The {@link RungeKuttaIntegrator}
|
||||
* class uses the prototyping design pattern to create the step
|
||||
* interpolators by cloning an uninitialized model and latter initializing
|
||||
* the copy.
|
||||
*/
|
||||
public ClassicalRungeKuttaStepInterpolator() {
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* @param interpolator interpolator to copy from. The copy is a deep
|
||||
* copy: its arrays are separated from the original arrays of the
|
||||
* instance
|
||||
*/
|
||||
public ClassicalRungeKuttaStepInterpolator(ClassicalRungeKuttaStepInterpolator interpolator) {
|
||||
super(interpolator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the instance.
|
||||
* the copy is a deep copy: its arrays are separated from the
|
||||
* original arrays of the instance
|
||||
* @return a copy of the instance
|
||||
*/
|
||||
public Object clone() {
|
||||
return new ClassicalRungeKuttaStepInterpolator(this);
|
||||
}
|
||||
|
||||
/** Compute the state at the interpolated time.
|
||||
* This is the main processing method that should be implemented by
|
||||
* the derived classes to perform the interpolation.
|
||||
* @param theta normalized interpolation abscissa within the step
|
||||
* (theta is zero at the previous time step and one at the current time step)
|
||||
* @param oneMinusThetaH time gap between the interpolated time and
|
||||
* the current time
|
||||
* @throws DerivativeException this exception is propagated to the caller if the
|
||||
* underlying user function triggers one
|
||||
*/
|
||||
protected void computeInterpolatedState(double theta,
|
||||
double oneMinusThetaH)
|
||||
throws DerivativeException {
|
||||
|
||||
double fourTheta = 4 * theta;
|
||||
double s = oneMinusThetaH / 6.0;
|
||||
double coeff1 = s * ((-fourTheta + 5) * theta - 1);
|
||||
double coeff23 = s * (( fourTheta - 2) * theta - 2);
|
||||
double coeff4 = s * ((-fourTheta - 1) * theta - 1);
|
||||
|
||||
for (int i = 0; i < interpolatedState.length; ++i) {
|
||||
interpolatedState[i] = currentState[i]
|
||||
+ coeff1 * yDotK[0][i]
|
||||
+ coeff23 * (yDotK[1][i] + yDotK[2][i])
|
||||
+ coeff4 * yDotK[3][i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -6576285612589783992L;
|
||||
|
||||
}
|
|
@ -0,0 +1,375 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* This class stores all information provided by an ODE integrator
|
||||
* during the integration process and build a continuous model of the
|
||||
* solution from this.
|
||||
|
||||
* <p>This class act as a step handler from the integrator point of
|
||||
* view. It is called iteratively during the integration process and
|
||||
* stores a copy of all steps information in a sorted collection for
|
||||
* later use. Once the integration process is over, the user can use
|
||||
* the {@link #setInterpolatedTime setInterpolatedTime} and {@link
|
||||
* #getInterpolatedState getInterpolatedState} to retrieve this
|
||||
* information at any time. It is important to wait for the
|
||||
* integration to be over before attempting to call {@link
|
||||
* #setInterpolatedTime setInterpolatedTime} because some internal
|
||||
* variables are set only once the last step has been handled.</p>
|
||||
|
||||
* <p>This is useful for example if the main loop of the user
|
||||
* application should remain independant from the integration process
|
||||
* or if one needs to mimic the behaviour of an analytical model
|
||||
* despite a numerical model is used (i.e. one needs the ability to
|
||||
* get the model value at any time or to navigate through the
|
||||
* data).</p>
|
||||
|
||||
* <p>If problem modelization is done with several separate
|
||||
* integration phases for contiguous intervals, the same
|
||||
* ContinuousOutputModel can be used as step handler for all
|
||||
* integration phases as long as they are performed in order and in
|
||||
* the same direction. As an example, one can extrapolate the
|
||||
* trajectory of a satellite with one model (i.e. one set of
|
||||
* differential equations) up to the beginning of a maneuver, use
|
||||
* another more complex model including thrusters modelization and
|
||||
* accurate attitude control during the maneuver, and revert to the
|
||||
* first model after the end of the maneuver. If the same continuous
|
||||
* output model handles the steps of all integration phases, the user
|
||||
* do not need to bother when the maneuver begins or ends, he has all
|
||||
* the data available in a transparent manner.</p>
|
||||
|
||||
* <p>An important feature of this class is that it implements the
|
||||
* <code>Serializable</code> interface. This means that the result of
|
||||
* an integration can be serialized and reused later (if stored into a
|
||||
* persistent medium like a filesystem or a database) or elsewhere (if
|
||||
* sent to another application). Only the result of the integration is
|
||||
* stored, there is no reference to the integrated problem by
|
||||
* itself.</p>
|
||||
|
||||
* <p>One should be aware that the amount of data stored in a
|
||||
* ContinuousOutputModel instance can be important if the state vector
|
||||
* is large, if the integration interval is long or if the steps are
|
||||
* small (which can result from small tolerance settings in {@link
|
||||
* AdaptiveStepsizeIntegrator adaptive step size integrators}).</p>
|
||||
|
||||
* @see StepHandler
|
||||
* @see StepInterpolator
|
||||
|
||||
* @version $Id: ContinuousOutputModel.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class ContinuousOutputModel
|
||||
implements StepHandler, Serializable {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an empty continuous output model.
|
||||
*/
|
||||
public ContinuousOutputModel() {
|
||||
steps = new ArrayList();
|
||||
reset();
|
||||
}
|
||||
|
||||
/** Append another model at the end of the instance.
|
||||
* @param model model to add at the end of the instance
|
||||
* @exception IllegalArgumentException if the model to append is not
|
||||
* compatible with the instance (dimension of the state vector,
|
||||
* propagation direction, hole between the dates)
|
||||
*/
|
||||
public void append(ContinuousOutputModel model) {
|
||||
|
||||
if (model.steps.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (steps.size() == 0) {
|
||||
initialTime = model.initialTime;
|
||||
forward = model.forward;
|
||||
} else {
|
||||
|
||||
if (getInterpolatedState().length != model.getInterpolatedState().length) {
|
||||
throw new IllegalArgumentException("state vector dimension mismatch");
|
||||
}
|
||||
|
||||
if (forward ^ model.forward) {
|
||||
throw new IllegalArgumentException("propagation direction mismatch");
|
||||
}
|
||||
|
||||
StepInterpolator lastInterpolator = (StepInterpolator) steps.get(index);
|
||||
double current = lastInterpolator.getCurrentTime();
|
||||
double previous = lastInterpolator.getPreviousTime();
|
||||
double step = current - previous;
|
||||
double gap = model.getInitialTime() - current;
|
||||
if (Math.abs(gap) > 1.0e-3 * Math.abs(step)) {
|
||||
throw new IllegalArgumentException("hole between time ranges");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (Iterator iter = model.steps.iterator(); iter.hasNext(); ) {
|
||||
AbstractStepInterpolator ai = (AbstractStepInterpolator) iter.next();
|
||||
steps.add(ai.clone());
|
||||
}
|
||||
|
||||
index = steps.size() - 1;
|
||||
finalTime = ((StepInterpolator) steps.get(index)).getCurrentTime();
|
||||
|
||||
}
|
||||
|
||||
/** Determines whether this handler needs dense output.
|
||||
* <p>The essence of this class is to provide dense output over all
|
||||
* steps, hence it requires the internal steps to provide themselves
|
||||
* dense output. The method therefore returns always true.</p>
|
||||
* @return always true
|
||||
*/
|
||||
public boolean requiresDenseOutput() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Reset the step handler.
|
||||
* Initialize the internal data as required before the first step is
|
||||
* handled.
|
||||
*/
|
||||
public void reset() {
|
||||
initialTime = Double.NaN;
|
||||
finalTime = Double.NaN;
|
||||
forward = true;
|
||||
index = 0;
|
||||
steps.clear();
|
||||
}
|
||||
|
||||
/** Handle the last accepted step.
|
||||
* A copy of the information provided by the last step is stored in
|
||||
* the instance for later use.
|
||||
* @param interpolator interpolator for the last accepted step.
|
||||
* @param isLast true if the step is the last one
|
||||
* @throws DerivativeException this exception is propagated to the
|
||||
* caller if the underlying user function triggers one
|
||||
*/
|
||||
public void handleStep(StepInterpolator interpolator, boolean isLast)
|
||||
throws DerivativeException {
|
||||
|
||||
AbstractStepInterpolator ai = (AbstractStepInterpolator) interpolator;
|
||||
|
||||
if (steps.size() == 0) {
|
||||
initialTime = interpolator.getPreviousTime();
|
||||
forward = interpolator.isForward();
|
||||
}
|
||||
|
||||
ai.finalizeStep();
|
||||
steps.add(ai.clone());
|
||||
|
||||
if (isLast) {
|
||||
finalTime = ai.getCurrentTime();
|
||||
index = steps.size() - 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the initial integration time.
|
||||
* @return initial integration time
|
||||
*/
|
||||
public double getInitialTime() {
|
||||
return initialTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the final integration time.
|
||||
* @return final integration time
|
||||
*/
|
||||
public double getFinalTime() {
|
||||
return finalTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time of the interpolated point.
|
||||
* If {@link #setInterpolatedTime} has not been called, it returns
|
||||
* the final integration time.
|
||||
* @return interpolation point time
|
||||
*/
|
||||
public double getInterpolatedTime() {
|
||||
return ((StepInterpolator) steps.get(index)).getInterpolatedTime();
|
||||
}
|
||||
|
||||
/** Set the time of the interpolated point.
|
||||
* <p>This method should <strong>not</strong> be called before the
|
||||
* integration is over because some internal variables are set only
|
||||
* once the last step has been handled.</p>
|
||||
* <p>Setting the time outside of the integration interval is now
|
||||
* allowed (it was not allowed up to version 5.9 of Mantissa), but
|
||||
* should be used with care since the accuracy of the interpolator
|
||||
* will probably be very poor far from this interval. This allowance
|
||||
* has been added to simplify implementation of search algorithms
|
||||
* near the interval endpoints.</p>
|
||||
* @param time time of the interpolated point
|
||||
*/
|
||||
public void setInterpolatedTime(double time) {
|
||||
|
||||
try {
|
||||
// initialize the search with the complete steps table
|
||||
int iMin = 0;
|
||||
StepInterpolator sMin = (StepInterpolator) steps.get(iMin);
|
||||
double tMin = 0.5 * (sMin.getPreviousTime() + sMin.getCurrentTime());
|
||||
|
||||
int iMax = steps.size() - 1;
|
||||
StepInterpolator sMax = (StepInterpolator) steps.get(iMax);
|
||||
double tMax = 0.5 * (sMax.getPreviousTime() + sMax.getCurrentTime());
|
||||
|
||||
// handle points outside of the integration interval
|
||||
// or in the first and last step
|
||||
if (locatePoint(time, sMin) <= 0) {
|
||||
index = iMin;
|
||||
sMin.setInterpolatedTime(time);
|
||||
return;
|
||||
}
|
||||
if (locatePoint(time, sMax) >= 0) {
|
||||
index = iMax;
|
||||
sMax.setInterpolatedTime(time);
|
||||
return;
|
||||
}
|
||||
|
||||
// reduction of the table slice size
|
||||
while (iMax - iMin > 5) {
|
||||
|
||||
// use the last estimated index as the splitting index
|
||||
StepInterpolator si = (StepInterpolator) steps.get(index);
|
||||
int location = locatePoint(time, si);
|
||||
if (location < 0) {
|
||||
iMax = index;
|
||||
tMax = 0.5 * (si.getPreviousTime() + si.getCurrentTime());
|
||||
} else if (location > 0) {
|
||||
iMin = index;
|
||||
tMin = 0.5 * (si.getPreviousTime() + si.getCurrentTime());
|
||||
} else {
|
||||
// we have found the target step, no need to continue searching
|
||||
si.setInterpolatedTime(time);
|
||||
return;
|
||||
}
|
||||
|
||||
// compute a new estimate of the index in the reduced table slice
|
||||
int iMed = (iMin + iMax) / 2;
|
||||
StepInterpolator sMed = (StepInterpolator) steps.get(iMed);
|
||||
double tMed = 0.5 * (sMed.getPreviousTime() + sMed.getCurrentTime());
|
||||
|
||||
if ((Math.abs(tMed - tMin) < 1e-6) || (Math.abs(tMax - tMed) < 1e-6)) {
|
||||
// too close to the bounds, we estimate using a simple dichotomy
|
||||
index = iMed;
|
||||
} else {
|
||||
// estimate the index using a reverse quadratic polynom
|
||||
// (reverse means we have i = P(t), thus allowing to simply
|
||||
// compute index = P(time) rather than solving a quadratic equation)
|
||||
double d12 = tMax - tMed;
|
||||
double d23 = tMed - tMin;
|
||||
double d13 = tMax - tMin;
|
||||
double dt1 = time - tMax;
|
||||
double dt2 = time - tMed;
|
||||
double dt3 = time - tMin;
|
||||
double iLagrange = ( (dt2 * dt3 * d23) * iMax
|
||||
- (dt1 * dt3 * d13) * iMed
|
||||
+ (dt1 * dt2 * d12) * iMin)
|
||||
/ (d12 * d23 * d13);
|
||||
index = (int) Math.rint(iLagrange);
|
||||
}
|
||||
|
||||
// force the next size reduction to be at least one tenth
|
||||
int low = Math.max(iMin + 1, (9 * iMin + iMax) / 10);
|
||||
int high = Math.min(iMax - 1, (iMin + 9 * iMax) / 10);
|
||||
if (index < low) {
|
||||
index = low;
|
||||
} else if (index > high) {
|
||||
index = high;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// now the table slice is very small, we perform an iterative search
|
||||
index = iMin;
|
||||
while ((index <= iMax)
|
||||
&& (locatePoint(time, (StepInterpolator) steps.get(index)) > 0)) {
|
||||
++index;
|
||||
}
|
||||
|
||||
StepInterpolator si = (StepInterpolator) steps.get(index);
|
||||
|
||||
si.setInterpolatedTime(time);
|
||||
|
||||
} catch (DerivativeException de) {
|
||||
throw new RuntimeException("unexpected DerivativeException caught", de);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state vector of the interpolated point.
|
||||
* @return state vector at time {@link #getInterpolatedTime}
|
||||
*/
|
||||
public double[] getInterpolatedState() {
|
||||
return ((StepInterpolator) steps.get(index)).getInterpolatedState();
|
||||
}
|
||||
|
||||
/** Compare a step interval and a double.
|
||||
* @param time point to locate
|
||||
* @param interval step interval
|
||||
* @return -1 if the double is before the interval, 0 if it is in
|
||||
* the interval, and +1 if it is after the interval, according to
|
||||
* the interval direction
|
||||
*/
|
||||
private int locatePoint(double time, StepInterpolator interval) {
|
||||
if (forward) {
|
||||
if (time < interval.getPreviousTime()) {
|
||||
return -1;
|
||||
} else if (time > interval.getCurrentTime()) {
|
||||
return +1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (time > interval.getPreviousTime()) {
|
||||
return -1;
|
||||
} else if (time < interval.getCurrentTime()) {
|
||||
return +1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Initial integration time. */
|
||||
private double initialTime;
|
||||
|
||||
/** Final integration time. */
|
||||
private double finalTime;
|
||||
|
||||
/** Integration direction indicator. */
|
||||
private boolean forward;
|
||||
|
||||
/** Current interpolator index. */
|
||||
private int index;
|
||||
|
||||
/** Steps table. */
|
||||
private ArrayList steps;
|
||||
|
||||
private static final long serialVersionUID = 2259286184268533249L;
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
import org.spaceroots.mantissa.MantissaException;
|
||||
|
||||
/**
|
||||
* This exception is made available to users to report
|
||||
* the error conditions that are trigegred while computing
|
||||
* the differential equations.
|
||||
* @author Luc Maisonobe
|
||||
* @version $Id: DerivativeException.java 1705 2006-09-17 19:57:39Z luc $
|
||||
*/
|
||||
public class DerivativeException
|
||||
extends MantissaException {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an exception by translating and formating a message
|
||||
* @param specifier format specifier (to be translated)
|
||||
* @param parts to insert in the format (no translation)
|
||||
*/
|
||||
public DerivativeException(String specifier, String[] parts) {
|
||||
super(specifier, parts);
|
||||
}
|
||||
|
||||
/** Build an instance from an underlying cause.
|
||||
* @param cause cause for the exception
|
||||
*/
|
||||
public DerivativeException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -4100440615830558122L;
|
||||
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This class implements the 5(4) Dormand-Prince integrator for Ordinary
|
||||
* Differential Equations.
|
||||
|
||||
* <p>This integrator is an embedded Runge-Kutta-Fehlberg integrator
|
||||
* of order 5(4) used in local extrapolation mode (i.e. the solution
|
||||
* is computed using the high order formula) with stepsize control
|
||||
* (and automatic step initialization) and continuous output. This
|
||||
* method uses 7 functions evaluations per step. However, since this
|
||||
* is an <i>fsal</i>, the last evaluation of one step is the same as
|
||||
* the first evaluation of the next step and hence can be avoided. So
|
||||
* the cost is really 6 functions evaluations per step.</p>
|
||||
|
||||
* <p>This method has been published (whithout the continuous output
|
||||
* that was added by Shampine in 1986) in the following article :
|
||||
* <pre>
|
||||
* A family of embedded Runge-Kutta formulae
|
||||
* J. R. Dormand and P. J. Prince
|
||||
* Journal of Computational and Applied Mathematics
|
||||
* volume 6, no 1, 1980, pp. 19-26
|
||||
* </pre></p>
|
||||
|
||||
* @version $Id: DormandPrince54Integrator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class DormandPrince54Integrator
|
||||
extends RungeKuttaFehlbergIntegrator {
|
||||
|
||||
private static final String methodName = new String("Dormand-Prince 5(4)");
|
||||
|
||||
private static final double[] c = {
|
||||
1.0/5.0, 3.0/10.0, 4.0/5.0, 8.0/9.0, 1.0, 1.0
|
||||
};
|
||||
|
||||
private static final double[][] a = {
|
||||
{1.0/5.0},
|
||||
{3.0/40.0, 9.0/40.0},
|
||||
{44.0/45.0, -56.0/15.0, 32.0/9.0},
|
||||
{19372.0/6561.0, -25360.0/2187.0, 64448.0/6561.0, -212.0/729.0},
|
||||
{9017.0/3168.0, -355.0/33.0, 46732.0/5247.0, 49.0/176.0, -5103.0/18656.0},
|
||||
{35.0/384.0, 0.0, 500.0/1113.0, 125.0/192.0, -2187.0/6784.0, 11.0/84.0}
|
||||
};
|
||||
|
||||
private static final double[] b = {
|
||||
35.0/384.0, 0.0, 500.0/1113.0, 125.0/192.0, -2187.0/6784.0, 11.0/84.0, 0.0
|
||||
};
|
||||
|
||||
private static final double e1 = 71.0 / 57600.0;
|
||||
private static final double e3 = -71.0 / 16695.0;
|
||||
private static final double e4 = 71.0 / 1920.0;
|
||||
private static final double e5 = -17253.0 / 339200.0;
|
||||
private static final double e6 = 22.0 / 525.0;
|
||||
private static final double e7 = -1.0 / 40.0;
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a fifth order Dormand-Prince integrator with the given step bounds
|
||||
* @param minStep minimal step (must be positive even for backward
|
||||
* integration), the last step can be smaller than this
|
||||
* @param maxStep maximal step (must be positive even for backward
|
||||
* integration)
|
||||
* @param scalAbsoluteTolerance allowed absolute error
|
||||
* @param scalRelativeTolerance allowed relative error
|
||||
*/
|
||||
public DormandPrince54Integrator(double minStep, double maxStep,
|
||||
double scalAbsoluteTolerance,
|
||||
double scalRelativeTolerance) {
|
||||
super(true, c, a, b, new DormandPrince54StepInterpolator(),
|
||||
minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a fifth order Dormand-Prince integrator with the given step bounds
|
||||
* @param minStep minimal step (must be positive even for backward
|
||||
* integration), the last step can be smaller than this
|
||||
* @param maxStep maximal step (must be positive even for backward
|
||||
* integration)
|
||||
* @param vecAbsoluteTolerance allowed absolute error
|
||||
* @param vecRelativeTolerance allowed relative error
|
||||
*/
|
||||
public DormandPrince54Integrator(double minStep, double maxStep,
|
||||
double[] vecAbsoluteTolerance,
|
||||
double[] vecRelativeTolerance) {
|
||||
super(true, c, a, b, new DormandPrince54StepInterpolator(),
|
||||
minStep, maxStep, vecAbsoluteTolerance, vecRelativeTolerance);
|
||||
}
|
||||
|
||||
/** Get the name of the method.
|
||||
* @return name of the method
|
||||
*/
|
||||
public String getName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
/** Get the order of the method.
|
||||
* @return order of the method
|
||||
*/
|
||||
public int getOrder() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
/** Compute the error ratio.
|
||||
* @param yDotK derivatives computed during the first stages
|
||||
* @param y0 estimate of the step at the start of the step
|
||||
* @param y1 estimate of the step at the end of the step
|
||||
* @param h current step
|
||||
* @return error ratio, greater than 1 if step should be rejected
|
||||
*/
|
||||
protected double estimateError(double[][] yDotK,
|
||||
double[] y0, double[] y1,
|
||||
double h) {
|
||||
|
||||
double error = 0;
|
||||
|
||||
for (int j = 0; j < y0.length; ++j) {
|
||||
double errSum = e1 * yDotK[0][j] + e3 * yDotK[2][j]
|
||||
+ e4 * yDotK[3][j] + e5 * yDotK[4][j]
|
||||
+ e6 * yDotK[5][j] + e7 * yDotK[6][j];
|
||||
|
||||
double yScale = Math.max(Math.abs(y0[j]), Math.abs(y1[j]));
|
||||
double tol = (vecAbsoluteTolerance == null)
|
||||
? (scalAbsoluteTolerance + scalRelativeTolerance * yScale)
|
||||
: (vecAbsoluteTolerance[j] + vecRelativeTolerance[j] * yScale);
|
||||
double ratio = h * errSum / tol;
|
||||
error += ratio * ratio;
|
||||
|
||||
}
|
||||
|
||||
return Math.sqrt(error / y0.length);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This class represents an interpolator over the last step during an
|
||||
* ODE integration for the 5(4) Dormand-Prince integrator.
|
||||
*
|
||||
* @see DormandPrince54Integrator
|
||||
*
|
||||
* @version $Id: DormandPrince54StepInterpolator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
*
|
||||
*/
|
||||
|
||||
class DormandPrince54StepInterpolator
|
||||
extends RungeKuttaStepInterpolator {
|
||||
|
||||
/** Simple constructor.
|
||||
* This constructor builds an instance that is not usable yet, the
|
||||
* {@link #reinitialize} method should be called before using the
|
||||
* instance in order to initialize the internal arrays. This
|
||||
* constructor is used only in order to delay the initialization in
|
||||
* some cases. The {@link RungeKuttaFehlbergIntegrator} uses the
|
||||
* prototyping design pattern to create the step interpolators by
|
||||
* cloning an uninitialized model and latter initializing the copy.
|
||||
*/
|
||||
public DormandPrince54StepInterpolator() {
|
||||
super();
|
||||
v1 = null;
|
||||
v2 = null;
|
||||
v3 = null;
|
||||
v4 = null;
|
||||
vectorsInitialized = false;
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* @param interpolator interpolator to copy from. The copy is a deep
|
||||
* copy: its arrays are separated from the original arrays of the
|
||||
* instance
|
||||
*/
|
||||
public DormandPrince54StepInterpolator(DormandPrince54StepInterpolator interpolator) {
|
||||
|
||||
super(interpolator);
|
||||
|
||||
if (interpolator.v1 == null) {
|
||||
|
||||
v1 = null;
|
||||
v2 = null;
|
||||
v3 = null;
|
||||
v4 = null;
|
||||
vectorsInitialized = false;
|
||||
|
||||
} else {
|
||||
|
||||
int dimension = interpolator.v1.length;
|
||||
|
||||
v1 = new double[dimension];
|
||||
v2 = new double[dimension];
|
||||
v3 = new double[dimension];
|
||||
v4 = new double[dimension];
|
||||
|
||||
System.arraycopy(interpolator.v1, 0, v1, 0, dimension);
|
||||
System.arraycopy(interpolator.v2, 0, v2, 0, dimension);
|
||||
System.arraycopy(interpolator.v3, 0, v3, 0, dimension);
|
||||
System.arraycopy(interpolator.v4, 0, v4, 0, dimension);
|
||||
|
||||
vectorsInitialized = interpolator.vectorsInitialized;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the instance.
|
||||
* the copy is a deep copy: its arrays are separated from the
|
||||
* original arrays of the instance
|
||||
* @return a copy of the instance
|
||||
*/
|
||||
public Object clone() {
|
||||
return new DormandPrince54StepInterpolator(this);
|
||||
}
|
||||
|
||||
/** Reinitialize the instance
|
||||
* @param equations set of differential equations being integrated
|
||||
* @param y reference to the integrator array holding the state at
|
||||
* the end of the step
|
||||
* @param yDotK reference to the integrator array holding all the
|
||||
* intermediate slopes
|
||||
* @param forward integration direction indicator
|
||||
*/
|
||||
public void reinitialize(FirstOrderDifferentialEquations equations,
|
||||
double[] y, double[][] yDotK, boolean forward) {
|
||||
super.reinitialize(equations, y, yDotK, forward);
|
||||
v1 = null;
|
||||
v2 = null;
|
||||
v3 = null;
|
||||
v4 = null;
|
||||
vectorsInitialized = false;
|
||||
}
|
||||
|
||||
/** Store the current step time.
|
||||
* @param t current time
|
||||
*/
|
||||
public void storeTime(double t) {
|
||||
super.storeTime(t);
|
||||
vectorsInitialized = false;
|
||||
}
|
||||
|
||||
/** Compute the state at the interpolated time.
|
||||
* @param theta normalized interpolation abscissa within the step
|
||||
* (theta is zero at the previous time step and one at the current time step)
|
||||
* @param oneMinusThetaH time gap between the interpolated time and
|
||||
* the current time
|
||||
* @throws DerivativeException this exception is propagated to the caller if the
|
||||
* underlying user function triggers one
|
||||
*/
|
||||
protected void computeInterpolatedState(double theta,
|
||||
double oneMinusThetaH)
|
||||
throws DerivativeException {
|
||||
|
||||
if (! vectorsInitialized) {
|
||||
|
||||
if (v1 == null) {
|
||||
v1 = new double[interpolatedState.length];
|
||||
v2 = new double[interpolatedState.length];
|
||||
v3 = new double[interpolatedState.length];
|
||||
v4 = new double[interpolatedState.length];
|
||||
}
|
||||
|
||||
// no step finalization is needed for this interpolator
|
||||
|
||||
// we need to compute the interpolation vectors for this time step
|
||||
for (int i = 0; i < interpolatedState.length; ++i) {
|
||||
v1[i] = h * (a70 * yDotK[0][i] + a72 * yDotK[2][i] + a73 * yDotK[3][i]
|
||||
+ a74 * yDotK[4][i] + a75 * yDotK[5][i]);
|
||||
v2[i] = h * yDotK[0][i] - v1[i];
|
||||
v3[i] = v1[i] - v2[i] - h * yDotK[6][i];
|
||||
v4[i] = h * (d0 * yDotK[0][i] + d2 * yDotK[2][i] + d3 * yDotK[3][i]
|
||||
+ d4 * yDotK[4][i] + d5 * yDotK[5][i] + d6 * yDotK[6][i]);
|
||||
}
|
||||
|
||||
vectorsInitialized = true;
|
||||
|
||||
}
|
||||
|
||||
// interpolate
|
||||
double eta = oneMinusThetaH / h;
|
||||
for (int i = 0; i < interpolatedState.length; ++i) {
|
||||
interpolatedState[i] = currentState[i]
|
||||
- eta * (v1[i]
|
||||
- theta * (v2[i]
|
||||
+ theta * (v3[i]
|
||||
+ eta * v4[i])));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** First vector for interpolation. */
|
||||
private double[] v1;
|
||||
|
||||
/** Second vector for interpolation. */
|
||||
private double[] v2;
|
||||
|
||||
/** Third vector for interpolation. */
|
||||
private double[] v3;
|
||||
|
||||
/** Fourth vector for interpolation. */
|
||||
private double[] v4;
|
||||
|
||||
/** Initialization indicator for the interpolation vectors. */
|
||||
private boolean vectorsInitialized;
|
||||
|
||||
// last row of the Butcher-array internal weights, note that a71 is null
|
||||
private static final double a70 = 35.0 / 384.0;
|
||||
private static final double a72 = 500.0 / 1113.0;
|
||||
private static final double a73 = 125.0 / 192.0;
|
||||
private static final double a74 = -2187.0 / 6784.0;
|
||||
private static final double a75 = 11.0 / 84.0;
|
||||
|
||||
// dense output of Shampine (1986), note that d1 is null
|
||||
private static final double d0 = -12715105075.0 / 11282082432.0;
|
||||
private static final double d2 = 87487479700.0 / 32700410799.0;
|
||||
private static final double d3 = -10690763975.0 / 1880347072.0;
|
||||
private static final double d4 = 701980252875.0 / 199316789632.0;
|
||||
private static final double d5 = -1453857185.0 / 822651844.0;
|
||||
private static final double d6 = 69997945.0 / 29380423.0;
|
||||
|
||||
private static final long serialVersionUID = 4104157279605906956L;
|
||||
}
|
|
@ -0,0 +1,258 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This class implements the 8(5,3) Dormand-Prince integrator for Ordinary
|
||||
* Differential Equations.
|
||||
|
||||
* <p>This integrator is an embedded Runge-Kutta-Fehlberg integrator
|
||||
* of order 8(5,3) used in local extrapolation mode (i.e. the solution
|
||||
* is computed using the high order formula) with stepsize control
|
||||
* (and automatic step initialization) and continuous output. This
|
||||
* method uses 12 functions evaluations per step for integration and 4
|
||||
* evaluations for interpolation. However, since the first
|
||||
* interpolation evaluation is the same as the first integration
|
||||
* evaluation of the next step, we have included it in the integrator
|
||||
* rather than in the interpolator and specified the method was an
|
||||
* <i>fsal</i>. Hence, despite we have 13 stages here, the cost is
|
||||
* really 12 evaluations per step even if no interpolation is done,
|
||||
* and the overcost of interpolation is only 3 evaluations.</p>
|
||||
|
||||
* <p>This method is based on an 8(6) method by Dormand and Prince
|
||||
* (i.e. order 8 for the integration and order 6 for error estimation)
|
||||
* modified by Hairer and Wanner to use a 5th order error estimator
|
||||
* with 3rd order correction. This modification was introduced because
|
||||
* the original method failed in some cases (wrong steps can be
|
||||
* accepted when step size is too large, for example in the
|
||||
* Brusselator problem) and also had <i>severe difficulties when
|
||||
* applied to problems with discontinuities</i>. This modification is
|
||||
* explained in the second edition of the first volume (Nonstiff
|
||||
* Problems) of the reference book by Hairer, Norsett and Wanner:
|
||||
* <i>Solving Ordinary Differential Equations</i> (Springer-Verlag,
|
||||
* ISBN 3-540-56670-8).</p>
|
||||
|
||||
* @version $Id: DormandPrince853Integrator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class DormandPrince853Integrator
|
||||
extends RungeKuttaFehlbergIntegrator {
|
||||
|
||||
private static final String methodName = new String("Dormand-Prince 8 (5, 3)");
|
||||
|
||||
private static final double sqrt6 = Math.sqrt(6.0);
|
||||
|
||||
private static final double[] c = {
|
||||
(12.0 - 2.0 * sqrt6) / 135.0, (6.0 - sqrt6) / 45.0, (6.0 - sqrt6) / 30.0,
|
||||
(6.0 + sqrt6) / 30.0, 1.0/3.0, 1.0/4.0, 4.0/13.0, 127.0/195.0, 3.0/5.0,
|
||||
6.0/7.0, 1.0, 1.0
|
||||
};
|
||||
|
||||
private static final double[][] a = {
|
||||
|
||||
// k2
|
||||
{(12.0 - 2.0 * sqrt6) / 135.0},
|
||||
|
||||
// k3
|
||||
{(6.0 - sqrt6) / 180.0, (6.0 - sqrt6) / 60.0},
|
||||
|
||||
// k4
|
||||
{(6.0 - sqrt6) / 120.0, 0.0, (6.0 - sqrt6) / 40.0},
|
||||
|
||||
// k5
|
||||
{(462.0 + 107.0 * sqrt6) / 3000.0, 0.0,
|
||||
(-402.0 - 197.0 * sqrt6) / 1000.0, (168.0 + 73.0 * sqrt6) / 375.0},
|
||||
|
||||
// k6
|
||||
{1.0 / 27.0, 0.0, 0.0, (16.0 + sqrt6) / 108.0, (16.0 - sqrt6) / 108.0},
|
||||
|
||||
// k7
|
||||
{19.0 / 512.0, 0.0, 0.0, (118.0 + 23.0 * sqrt6) / 1024.0,
|
||||
(118.0 - 23.0 * sqrt6) / 1024.0, -9.0 / 512.0},
|
||||
|
||||
// k8
|
||||
{13772.0 / 371293.0, 0.0, 0.0, (51544.0 + 4784.0 * sqrt6) / 371293.0,
|
||||
(51544.0 - 4784.0 * sqrt6) / 371293.0, -5688.0 / 371293.0, 3072.0 / 371293.0},
|
||||
|
||||
// k9
|
||||
{58656157643.0 / 93983540625.0, 0.0, 0.0,
|
||||
(-1324889724104.0 - 318801444819.0 * sqrt6) / 626556937500.0,
|
||||
(-1324889724104.0 + 318801444819.0 * sqrt6) / 626556937500.0,
|
||||
96044563816.0 / 3480871875.0, 5682451879168.0 / 281950621875.0,
|
||||
-165125654.0 / 3796875.0},
|
||||
|
||||
// k10
|
||||
{8909899.0 / 18653125.0, 0.0, 0.0,
|
||||
(-4521408.0 - 1137963.0 * sqrt6) / 2937500.0,
|
||||
(-4521408.0 + 1137963.0 * sqrt6) / 2937500.0,
|
||||
96663078.0 / 4553125.0, 2107245056.0 / 137915625.0,
|
||||
-4913652016.0 / 147609375.0, -78894270.0 / 3880452869.0},
|
||||
|
||||
// k11
|
||||
{-20401265806.0 / 21769653311.0, 0.0, 0.0,
|
||||
(354216.0 + 94326.0 * sqrt6) / 112847.0,
|
||||
(354216.0 - 94326.0 * sqrt6) / 112847.0,
|
||||
-43306765128.0 / 5313852383.0, -20866708358144.0 / 1126708119789.0,
|
||||
14886003438020.0 / 654632330667.0, 35290686222309375.0 / 14152473387134411.0,
|
||||
-1477884375.0 / 485066827.0},
|
||||
|
||||
// k12
|
||||
{39815761.0 / 17514443.0, 0.0, 0.0,
|
||||
(-3457480.0 - 960905.0 * sqrt6) / 551636.0,
|
||||
(-3457480.0 + 960905.0 * sqrt6) / 551636.0,
|
||||
-844554132.0 / 47026969.0, 8444996352.0 / 302158619.0,
|
||||
-2509602342.0 / 877790785.0, -28388795297996250.0 / 3199510091356783.0,
|
||||
226716250.0 / 18341897.0, 1371316744.0 / 2131383595.0},
|
||||
|
||||
// k13 should be for interpolation only, but since it is the same
|
||||
// stage as the first evaluation of the next step, we perform it
|
||||
// here at no cost by specifying this is an fsal method
|
||||
{104257.0/1920240.0, 0.0, 0.0, 0.0, 0.0, 3399327.0/763840.0,
|
||||
66578432.0/35198415.0, -1674902723.0/288716400.0,
|
||||
54980371265625.0/176692375811392.0, -734375.0/4826304.0,
|
||||
171414593.0/851261400.0, 137909.0/3084480.0}
|
||||
|
||||
};
|
||||
|
||||
private static final double[] b = {
|
||||
104257.0/1920240.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
3399327.0/763840.0,
|
||||
66578432.0/35198415.0,
|
||||
-1674902723.0/288716400.0,
|
||||
54980371265625.0/176692375811392.0,
|
||||
-734375.0/4826304.0,
|
||||
171414593.0/851261400.0,
|
||||
137909.0/3084480.0,
|
||||
0.0
|
||||
};
|
||||
|
||||
private static final double e1_01 = 116092271.0 / 8848465920.0;
|
||||
private static final double e1_06 = -1871647.0 / 1527680.0;
|
||||
private static final double e1_07 = -69799717.0 / 140793660.0;
|
||||
private static final double e1_08 = 1230164450203.0 / 739113984000.0;
|
||||
private static final double e1_09 = -1980813971228885.0 / 5654156025964544.0;
|
||||
private static final double e1_10 = 464500805.0 / 1389975552.0;
|
||||
private static final double e1_11 = 1606764981773.0 / 19613062656000.0;
|
||||
private static final double e1_12 = -137909.0 / 6168960.0;
|
||||
|
||||
private static final double e2_01 = -364463.0 / 1920240.0;
|
||||
private static final double e2_06 = 3399327.0 / 763840.0;
|
||||
private static final double e2_07 = 66578432.0 / 35198415.0;
|
||||
private static final double e2_08 = -1674902723.0 / 288716400.0;
|
||||
private static final double e2_09 = -74684743568175.0 / 176692375811392.0;
|
||||
private static final double e2_10 = -734375.0 / 4826304.0;
|
||||
private static final double e2_11 = 171414593.0 / 851261400.0;
|
||||
private static final double e2_12 = 69869.0 / 3084480.0;
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an eighth order Dormand-Prince integrator with the given step bounds
|
||||
* @param minStep minimal step (must be positive even for backward
|
||||
* integration), the last step can be smaller than this
|
||||
* @param maxStep maximal step (must be positive even for backward
|
||||
* integration)
|
||||
* @param scalAbsoluteTolerance allowed absolute error
|
||||
* @param scalRelativeTolerance allowed relative error
|
||||
*/
|
||||
public DormandPrince853Integrator(double minStep, double maxStep,
|
||||
double scalAbsoluteTolerance,
|
||||
double scalRelativeTolerance) {
|
||||
super(true, c, a, b,
|
||||
new DormandPrince853StepInterpolator(),
|
||||
minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an eighth order Dormand-Prince integrator with the given step bounds
|
||||
* @param minStep minimal step (must be positive even for backward
|
||||
* integration), the last step can be smaller than this
|
||||
* @param maxStep maximal step (must be positive even for backward
|
||||
* integration)
|
||||
* @param vecAbsoluteTolerance allowed absolute error
|
||||
* @param vecRelativeTolerance allowed relative error
|
||||
*/
|
||||
public DormandPrince853Integrator(double minStep, double maxStep,
|
||||
double[] vecAbsoluteTolerance,
|
||||
double[] vecRelativeTolerance) {
|
||||
super(true, c, a, b,
|
||||
new DormandPrince853StepInterpolator(),
|
||||
minStep, maxStep, vecAbsoluteTolerance, vecRelativeTolerance);
|
||||
}
|
||||
|
||||
/** Get the name of the method.
|
||||
* @return name of the method
|
||||
*/
|
||||
public String getName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
/** Get the order of the method.
|
||||
* @return order of the method
|
||||
*/
|
||||
public int getOrder() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
/** Compute the error ratio.
|
||||
* @param yDotK derivatives computed during the first stages
|
||||
* @param y0 estimate of the step at the start of the step
|
||||
* @param y1 estimate of the step at the end of the step
|
||||
* @param h current step
|
||||
* @return error ratio, greater than 1 if step should be rejected
|
||||
*/
|
||||
protected double estimateError(double[][] yDotK,
|
||||
double[] y0, double[] y1,
|
||||
double h) {
|
||||
double error1 = 0;
|
||||
double error2 = 0;
|
||||
|
||||
for (int j = 0; j < y0.length; ++j) {
|
||||
double errSum1 = e1_01 * yDotK[0][j] + e1_06 * yDotK[5][j]
|
||||
+ e1_07 * yDotK[6][j] + e1_08 * yDotK[7][j]
|
||||
+ e1_09 * yDotK[8][j] + e1_10 * yDotK[9][j]
|
||||
+ e1_11 * yDotK[10][j] + e1_12 * yDotK[11][j];
|
||||
double errSum2 = e2_01 * yDotK[0][j] + e2_06 * yDotK[5][j]
|
||||
+ e2_07 * yDotK[6][j] + e2_08 * yDotK[7][j]
|
||||
+ e2_09 * yDotK[8][j] + e2_10 * yDotK[9][j]
|
||||
+ e2_11 * yDotK[10][j] + e2_12 * yDotK[11][j];
|
||||
|
||||
double yScale = Math.max(Math.abs(y0[j]), Math.abs(y1[j]));
|
||||
double tol = (vecAbsoluteTolerance == null)
|
||||
? (scalAbsoluteTolerance + scalRelativeTolerance * yScale)
|
||||
: (vecAbsoluteTolerance[j] + vecRelativeTolerance[j] * yScale);
|
||||
double ratio1 = errSum1 / tol;
|
||||
error1 += ratio1 * ratio1;
|
||||
double ratio2 = errSum2 / tol;
|
||||
error2 += ratio2 * ratio2;
|
||||
}
|
||||
|
||||
double den = error1 + 0.01 * error2;
|
||||
if (den <= 0.0) {
|
||||
den = 1.0;
|
||||
}
|
||||
|
||||
return Math.abs(h) * error1 / Math.sqrt(y0.length * den);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,415 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class represents an interpolator over the last step during an
|
||||
* ODE integration for the 8(5,3) Dormand-Prince integrator.
|
||||
*
|
||||
* @see DormandPrince853Integrator
|
||||
*
|
||||
* @version $Id: DormandPrince853StepInterpolator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
*
|
||||
*/
|
||||
|
||||
class DormandPrince853StepInterpolator
|
||||
extends RungeKuttaStepInterpolator {
|
||||
|
||||
/** Simple constructor.
|
||||
* This constructor builds an instance that is not usable yet, the
|
||||
* {@link #reinitialize} method should be called before using the
|
||||
* instance in order to initialize the internal arrays. This
|
||||
* constructor is used only in order to delay the initialization in
|
||||
* some cases. The {@link RungeKuttaFehlbergIntegrator} uses the
|
||||
* prototyping design pattern to create the step interpolators by
|
||||
* cloning an uninitialized model and latter initializing the copy.
|
||||
*/
|
||||
public DormandPrince853StepInterpolator() {
|
||||
super();
|
||||
yDotKLast = null;
|
||||
yTmp = null;
|
||||
v = null;
|
||||
vectorsInitialized = false;
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* @param interpolator interpolator to copy from. The copy is a deep
|
||||
* copy: its arrays are separated from the original arrays of the
|
||||
* instance
|
||||
*/
|
||||
public DormandPrince853StepInterpolator(DormandPrince853StepInterpolator interpolator) {
|
||||
|
||||
super(interpolator);
|
||||
|
||||
if (interpolator.currentState == null) {
|
||||
|
||||
yDotKLast = null;
|
||||
v = null;
|
||||
vectorsInitialized = false;
|
||||
|
||||
} else {
|
||||
|
||||
int dimension = interpolator.currentState.length;
|
||||
|
||||
yDotKLast = new double[3][];
|
||||
for (int k = 0; k < yDotKLast.length; ++k) {
|
||||
yDotKLast[k] = new double[dimension];
|
||||
System.arraycopy(interpolator.yDotKLast[k], 0, yDotKLast[k], 0,
|
||||
dimension);
|
||||
}
|
||||
|
||||
v = new double[7][];
|
||||
for (int k = 0; k < v.length; ++k) {
|
||||
v[k] = new double[dimension];
|
||||
System.arraycopy(interpolator.v[k], 0, v[k], 0, dimension);
|
||||
}
|
||||
|
||||
vectorsInitialized = interpolator.vectorsInitialized;
|
||||
|
||||
}
|
||||
|
||||
// the step has been finalized, we don't need this anymore
|
||||
yTmp = null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the instance.
|
||||
* the copy is a deep copy: its arrays are separated from the
|
||||
* original arrays of the instance
|
||||
* @return a copy of the instance
|
||||
*/
|
||||
public Object clone() {
|
||||
return new DormandPrince853StepInterpolator(this);
|
||||
}
|
||||
|
||||
/** Reinitialize the instance
|
||||
* Some Runge-Kutta-Fehlberg integrators need fewer functions
|
||||
* evaluations than their counterpart step interpolators. So the
|
||||
* interpolator should perform the last evaluations they need by
|
||||
* themselves. The {@link RungeKuttaFehlbergIntegrator
|
||||
* RungeKuttaFehlbergIntegrator} abstract class calls this method in
|
||||
* order to let the step interpolator perform the evaluations it
|
||||
* needs. These evaluations will be performed during the call to
|
||||
* <code>doFinalize</code> if any, i.e. only if the step handler
|
||||
* either calls the {@link AbstractStepInterpolator#finalizeStep
|
||||
* finalizeStep} method or the {@link
|
||||
* AbstractStepInterpolator#getInterpolatedState getInterpolatedState}
|
||||
* method (for an interpolator which needs a finalization) or if it clones
|
||||
* the step interpolator.
|
||||
* @param equations set of differential equations being integrated
|
||||
* @param y reference to the integrator array holding the state at
|
||||
* the end of the step
|
||||
* @param yDotK reference to the integrator array holding all the
|
||||
* intermediate slopes
|
||||
* @param forward integration direction indicator
|
||||
*/
|
||||
public void reinitialize(FirstOrderDifferentialEquations equations,
|
||||
double[] y, double[][] yDotK, boolean forward) {
|
||||
|
||||
super.reinitialize(equations, y, yDotK, forward);
|
||||
|
||||
int dimension = currentState.length;
|
||||
|
||||
yDotKLast = new double[3][];
|
||||
for (int k = 0; k < yDotKLast.length; ++k) {
|
||||
yDotKLast[k] = new double[dimension];
|
||||
}
|
||||
|
||||
yTmp = new double[dimension];
|
||||
|
||||
v = new double[7][];
|
||||
for (int k = 0; k < v.length; ++k) {
|
||||
v[k] = new double[dimension];
|
||||
}
|
||||
|
||||
vectorsInitialized = false;
|
||||
|
||||
}
|
||||
|
||||
/** Store the current step time.
|
||||
* @param t current time
|
||||
*/
|
||||
public void storeTime(double t) {
|
||||
super.storeTime(t);
|
||||
vectorsInitialized = false;
|
||||
}
|
||||
|
||||
/** Compute the state at the interpolated time.
|
||||
* This is the main processing method that should be implemented by
|
||||
* the derived classes to perform the interpolation.
|
||||
* @param theta normalized interpolation abscissa within the step
|
||||
* (theta is zero at the previous time step and one at the current time step)
|
||||
* @param oneMinusThetaH time gap between the interpolated time and
|
||||
* the current time
|
||||
* @throws DerivativeException this exception is propagated to the caller if the
|
||||
* underlying user function triggers one
|
||||
*/
|
||||
protected void computeInterpolatedState(double theta,
|
||||
double oneMinusThetaH)
|
||||
throws DerivativeException {
|
||||
|
||||
if (! vectorsInitialized) {
|
||||
|
||||
if (v == null) {
|
||||
v = new double[7][];
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
v[k] = new double[interpolatedState.length];
|
||||
}
|
||||
}
|
||||
|
||||
// perform the last evaluations if they have not been done yet
|
||||
finalizeStep();
|
||||
|
||||
// compute the interpolation vectors for this time step
|
||||
for (int i = 0; i < interpolatedState.length; ++i) {
|
||||
v[0][i] = h * (b_01 * yDotK[0][i] + b_06 * yDotK[5][i] + b_07 * yDotK[6][i]
|
||||
+ b_08 * yDotK[7][i] + b_09 * yDotK[8][i] + b_10 * yDotK[9][i]
|
||||
+ b_11 * yDotK[10][i] + b_12 * yDotK[11][i]);
|
||||
v[1][i] = h * yDotK[0][i] - v[0][i];
|
||||
v[2][i] = v[0][i] - v[1][i] - h * yDotK[12][i];
|
||||
for (int k = 0; k < d.length; ++k) {
|
||||
v[k+3][i] = h * (d[k][0] * yDotK[0][i] + d[k][1] * yDotK[5][i] + d[k][2] * yDotK[6][i]
|
||||
+ d[k][3] * yDotK[7][i] + d[k][4] * yDotK[8][i] + d[k][5] * yDotK[9][i]
|
||||
+ d[k][6] * yDotK[10][i] + d[k][7] * yDotK[11][i] + d[k][8] * yDotK[12][i]
|
||||
+ d[k][9] * yDotKLast[0][i]
|
||||
+ d[k][10] * yDotKLast[1][i]
|
||||
+ d[k][11] * yDotKLast[2][i]);
|
||||
}
|
||||
}
|
||||
|
||||
vectorsInitialized = true;
|
||||
|
||||
}
|
||||
|
||||
double eta = oneMinusThetaH / h;
|
||||
|
||||
for (int i = 0; i < interpolatedState.length; ++i) {
|
||||
interpolatedState[i] = currentState[i]
|
||||
- eta * (v[0][i]
|
||||
- theta * (v[1][i]
|
||||
+ theta * (v[2][i]
|
||||
+ eta * (v[3][i]
|
||||
+ theta * (v[4][i]
|
||||
+ eta * (v[5][i]
|
||||
+ theta * (v[6][i])))))));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Really finalize the step.
|
||||
* Perform the last 3 functions evaluations (k14, k15, k16)
|
||||
* @throws DerivativeException this exception is propagated to the caller if the
|
||||
* underlying user function triggers one
|
||||
*/
|
||||
protected void doFinalize()
|
||||
throws DerivativeException {
|
||||
|
||||
double s;
|
||||
|
||||
// k14
|
||||
for (int j = 0; j < currentState.length; ++j) {
|
||||
s = k14_01 * yDotK[0][j] + k14_06 * yDotK[5][j] + k14_07 * yDotK[6][j]
|
||||
+ k14_08 * yDotK[7][j] + k14_09 * yDotK[8][j] + k14_10 * yDotK[9][j]
|
||||
+ k14_11 * yDotK[10][j] + k14_12 * yDotK[11][j] + k14_13 * yDotK[12][j];
|
||||
yTmp[j] = currentState[j] + h * s;
|
||||
}
|
||||
equations.computeDerivatives(previousTime + c14 * h, yTmp, yDotKLast[0]);
|
||||
|
||||
// k15
|
||||
for (int j = 0; j < currentState.length; ++j) {
|
||||
s = k15_01 * yDotK[0][j] + k15_06 * yDotK[5][j] + k15_07 * yDotK[6][j]
|
||||
+ k15_08 * yDotK[7][j] + k15_09 * yDotK[8][j] + k15_10 * yDotK[9][j]
|
||||
+ k15_11 * yDotK[10][j] + k15_12 * yDotK[11][j] + k15_13 * yDotK[12][j]
|
||||
+ k15_14 * yDotKLast[0][j];
|
||||
yTmp[j] = currentState[j] + h * s;
|
||||
}
|
||||
equations.computeDerivatives(previousTime + c15 * h, yTmp, yDotKLast[1]);
|
||||
|
||||
// k16
|
||||
for (int j = 0; j < currentState.length; ++j) {
|
||||
s = k16_01 * yDotK[0][j] + k16_06 * yDotK[5][j] + k16_07 * yDotK[6][j]
|
||||
+ k16_08 * yDotK[7][j] + k16_09 * yDotK[8][j] + k16_10 * yDotK[9][j]
|
||||
+ k16_11 * yDotK[10][j] + k16_12 * yDotK[11][j] + k16_13 * yDotK[12][j]
|
||||
+ k16_14 * yDotKLast[0][j] + k16_15 * yDotKLast[1][j];
|
||||
yTmp[j] = currentState[j] + h * s;
|
||||
}
|
||||
equations.computeDerivatives(previousTime + c16 * h, yTmp, yDotKLast[2]);
|
||||
|
||||
}
|
||||
|
||||
/** Save the state of the instance.
|
||||
* @param out stream where to save the state
|
||||
* @exception IOException in case of write error
|
||||
*/
|
||||
public void writeExternal(ObjectOutput out)
|
||||
throws IOException {
|
||||
|
||||
try {
|
||||
// save the local attributes
|
||||
finalizeStep();
|
||||
} catch (DerivativeException e) {
|
||||
IOException ioe = new IOException();
|
||||
ioe.initCause(e);
|
||||
throw ioe;
|
||||
}
|
||||
out.writeInt(currentState.length);
|
||||
for (int i = 0; i < currentState.length; ++i) {
|
||||
out.writeDouble(yDotKLast[0][i]);
|
||||
out.writeDouble(yDotKLast[1][i]);
|
||||
out.writeDouble(yDotKLast[2][i]);
|
||||
}
|
||||
|
||||
// save the state of the base class
|
||||
super.writeExternal(out);
|
||||
|
||||
}
|
||||
|
||||
/** Read the state of the instance.
|
||||
* @param in stream where to read the state from
|
||||
* @exception IOException in case of read error
|
||||
*/
|
||||
public void readExternal(ObjectInput in)
|
||||
throws IOException {
|
||||
|
||||
// read the local attributes
|
||||
yDotKLast = new double[3][];
|
||||
int dimension = in.readInt();
|
||||
yDotKLast[0] = new double[dimension];
|
||||
yDotKLast[1] = new double[dimension];
|
||||
yDotKLast[2] = new double[dimension];
|
||||
|
||||
for (int i = 0; i < dimension; ++i) {
|
||||
yDotKLast[0][i] = in.readDouble();
|
||||
yDotKLast[1][i] = in.readDouble();
|
||||
yDotKLast[2][i] = in.readDouble();
|
||||
}
|
||||
|
||||
// read the base state
|
||||
super.readExternal(in);
|
||||
|
||||
}
|
||||
|
||||
/** Last evaluations. */
|
||||
private double[][] yDotKLast;
|
||||
|
||||
/** Temporary state vector. */
|
||||
private double[] yTmp;
|
||||
|
||||
/** Vectors for interpolation. */
|
||||
private double[][] v;
|
||||
|
||||
/** Initialization indicator for the interpolation vectors. */
|
||||
private boolean vectorsInitialized;
|
||||
|
||||
// external weights of the integrator,
|
||||
// note that b_02 through b_05 are null
|
||||
private static double b_01 = 104257.0 / 1920240.0;
|
||||
private static double b_06 = 3399327.0 / 763840.0;
|
||||
private static double b_07 = 66578432.0 / 35198415.0;
|
||||
private static double b_08 = -1674902723.0 / 288716400.0;
|
||||
private static double b_09 = 54980371265625.0 / 176692375811392.0;
|
||||
private static double b_10 = -734375.0 / 4826304.0;
|
||||
private static double b_11 = 171414593.0 / 851261400.0;
|
||||
private static double b_12 = 137909.0 / 3084480.0;
|
||||
|
||||
// k14 for interpolation only
|
||||
private static double c14 = 1.0 / 10.0;
|
||||
|
||||
private static double k14_01 = 13481885573.0 / 240030000000.0 - b_01;
|
||||
private static double k14_06 = 0.0 - b_06;
|
||||
private static double k14_07 = 139418837528.0 / 549975234375.0 - b_07;
|
||||
private static double k14_08 = -11108320068443.0 / 45111937500000.0 - b_08;
|
||||
private static double k14_09 = -1769651421925959.0 / 14249385146080000.0 - b_09;
|
||||
private static double k14_10 = 57799439.0 / 377055000.0 - b_10;
|
||||
private static double k14_11 = 793322643029.0 / 96734250000000.0 - b_11;
|
||||
private static double k14_12 = 1458939311.0 / 192780000000.0 - b_12;
|
||||
private static double k14_13 = -4149.0 / 500000.0;
|
||||
|
||||
// k15 for interpolation only
|
||||
private static double c15 = 1.0 / 5.0;
|
||||
|
||||
private static double k15_01 = 1595561272731.0 / 50120273500000.0 - b_01;
|
||||
private static double k15_06 = 975183916491.0 / 34457688031250.0 - b_06;
|
||||
private static double k15_07 = 38492013932672.0 / 718912673015625.0 - b_07;
|
||||
private static double k15_08 = -1114881286517557.0 / 20298710767500000.0 - b_08;
|
||||
private static double k15_09 = 0.0 - b_09;
|
||||
private static double k15_10 = 0.0 - b_10;
|
||||
private static double k15_11 = -2538710946863.0 / 23431227861250000.0 - b_11;
|
||||
private static double k15_12 = 8824659001.0 / 23066716781250.0 - b_12;
|
||||
private static double k15_13 = -11518334563.0 / 33831184612500.0;
|
||||
private static double k15_14 = 1912306948.0 / 13532473845.0;
|
||||
|
||||
// k16 for interpolation only
|
||||
private static double c16 = 7.0 / 9.0;
|
||||
|
||||
private static double k16_01 = -13613986967.0 / 31741908048.0 - b_01;
|
||||
private static double k16_06 = -4755612631.0 / 1012344804.0 - b_06;
|
||||
private static double k16_07 = 42939257944576.0 / 5588559685701.0 - b_07;
|
||||
private static double k16_08 = 77881972900277.0 / 19140370552944.0 - b_08;
|
||||
private static double k16_09 = 22719829234375.0 / 63689648654052.0 - b_09;
|
||||
private static double k16_10 = 0.0 - b_10;
|
||||
private static double k16_11 = 0.0 - b_11;
|
||||
private static double k16_12 = 0.0 - b_12;
|
||||
private static double k16_13 = -1199007803.0 / 857031517296.0;
|
||||
private static double k16_14 = 157882067000.0 / 53564469831.0;
|
||||
private static double k16_15 = -290468882375.0 / 31741908048.0;
|
||||
|
||||
// interpolation weights
|
||||
// (beware that only the non-null values are in the table)
|
||||
private static double[][] d = {
|
||||
|
||||
{ -17751989329.0 / 2106076560.0, 4272954039.0 / 7539864640.0,
|
||||
-118476319744.0 / 38604839385.0, 755123450731.0 / 316657731600.0,
|
||||
3692384461234828125.0 / 1744130441634250432.0, -4612609375.0 / 5293382976.0,
|
||||
2091772278379.0 / 933644586600.0, 2136624137.0 / 3382989120.0,
|
||||
-126493.0 / 1421424.0, 98350000.0 / 5419179.0,
|
||||
-18878125.0 / 2053168.0, -1944542619.0 / 438351368.0},
|
||||
|
||||
{ 32941697297.0 / 3159114840.0, 456696183123.0 / 1884966160.0,
|
||||
19132610714624.0 / 115814518155.0, -177904688592943.0 / 474986597400.0,
|
||||
-4821139941836765625.0 / 218016305204281304.0, 30702015625.0 / 3970037232.0,
|
||||
-85916079474274.0 / 2800933759800.0, -5919468007.0 / 634310460.0,
|
||||
2479159.0 / 157936.0, -18750000.0 / 602131.0,
|
||||
-19203125.0 / 2053168.0, 15700361463.0 / 438351368.0},
|
||||
|
||||
{ 12627015655.0 / 631822968.0, -72955222965.0 / 188496616.0,
|
||||
-13145744952320.0 / 69488710893.0, 30084216194513.0 / 56998391688.0,
|
||||
-296858761006640625.0 / 25648977082856624.0, 569140625.0 / 82709109.0,
|
||||
-18684190637.0 / 18672891732.0, 69644045.0 / 89549712.0,
|
||||
-11847025.0 / 4264272.0, -978650000.0 / 16257537.0,
|
||||
519371875.0 / 6159504.0, 5256837225.0 / 438351368.0},
|
||||
|
||||
{ -450944925.0 / 17550638.0, -14532122925.0 / 94248308.0,
|
||||
-595876966400.0 / 2573655959.0, 188748653015.0 / 527762886.0,
|
||||
2545485458115234375.0 / 27252038150535163.0, -1376953125.0 / 36759604.0,
|
||||
53995596795.0 / 518691437.0, 210311225.0 / 7047894.0,
|
||||
-1718875.0 / 39484.0, 58000000.0 / 602131.0,
|
||||
-1546875.0 / 39484.0, -1262172375.0 / 8429834.0}
|
||||
|
||||
};
|
||||
|
||||
private static final long serialVersionUID = 4165537490327432186L;
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This class is a step handler that do nothing.
|
||||
|
||||
* <p>This class is provided as a convenience for users who are only
|
||||
* interested in the final state of an integration and not in the
|
||||
* intermediate steps. Its handleStep method does nothing.</p>
|
||||
|
||||
* <p>Since this class has no internal state, it is implemented using
|
||||
* the Singleton design pattern. This means that only one instance is
|
||||
* ever created, which can be retrieved using the getInstance
|
||||
* method. This explains why there is no public constructor.</p>
|
||||
|
||||
* @see StepHandler
|
||||
|
||||
* @version $Id: DummyStepHandler.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class DummyStepHandler
|
||||
implements StepHandler {
|
||||
|
||||
/** Private constructor.
|
||||
* The constructor is private to prevent users from creating
|
||||
* instances (Singleton design-pattern).
|
||||
*/
|
||||
private DummyStepHandler() {
|
||||
}
|
||||
|
||||
/** Get the only instance.
|
||||
* @return the only instance
|
||||
*/
|
||||
public static DummyStepHandler getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new DummyStepHandler();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/** Determines whether this handler needs dense output.
|
||||
* Since this handler does nothing, it does not require dense output.
|
||||
* @return always false
|
||||
*/
|
||||
public boolean requiresDenseOutput() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Reset the step handler.
|
||||
* Initialize the internal data as required before the first step is
|
||||
* handled.
|
||||
*/
|
||||
public void reset() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the last accepted step.
|
||||
* This method does nothing in this class.
|
||||
* @param interpolator interpolator for the last accepted step. For
|
||||
* efficiency purposes, the various integrators reuse the same
|
||||
* object on each call, so if the instance wants to keep it across
|
||||
* all calls (for example to provide at the end of the integration a
|
||||
* continuous model valid throughout the integration range), it
|
||||
* should build a local copy using the clone method and store this
|
||||
* copy.
|
||||
* @param isLast true if the step is the last one
|
||||
*/
|
||||
public void handleStep(StepInterpolator interpolator, boolean isLast) {
|
||||
}
|
||||
|
||||
/** The only instance. */
|
||||
private static DummyStepHandler instance = null;
|
||||
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
/** This class is a step interpolator that does nothing.
|
||||
*
|
||||
* <p>This class is used when the {@link StepHandler "step handler"}
|
||||
* set up by the user does not need step interpolation. It does not
|
||||
* recompute the state when {@link AbstractStepInterpolator#setInterpolatedTime
|
||||
* setInterpolatedTime} is called. This implies the interpolated state
|
||||
* is always the state at the end of the current step.</p>
|
||||
*
|
||||
* @see StepHandler
|
||||
*
|
||||
* @version $Id: DummyStepInterpolator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
*
|
||||
*/
|
||||
|
||||
public class DummyStepInterpolator
|
||||
extends AbstractStepInterpolator {
|
||||
|
||||
/** Simple constructor.
|
||||
* This constructor builds an instance that is not usable yet, the
|
||||
* {@link AbstractStepInterpolator#reinitialize} method should be called
|
||||
* before using the instance in order to initialize the internal arrays. This
|
||||
* constructor is used only in order to delay the initialization in
|
||||
* some cases. As an example, the {@link
|
||||
* RungeKuttaFehlbergIntegrator} uses the prototyping design pattern
|
||||
* to create the step interpolators by cloning an uninitialized
|
||||
* model and latter initializing the copy.
|
||||
*/
|
||||
protected DummyStepInterpolator() {
|
||||
super();
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* @param y reference to the integrator array holding the state at
|
||||
* the end of the step
|
||||
* @param forward integration direction indicator
|
||||
*/
|
||||
protected DummyStepInterpolator(double[] y, boolean forward) {
|
||||
super(y, forward);
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
|
||||
* <p>The copied interpolator should have been finalized before the
|
||||
* copy, otherwise the copy will not be able to perform correctly
|
||||
* any interpolation and will throw a {@link NullPointerException}
|
||||
* later. Since we don't want this constructor to throw the
|
||||
* exceptions finalization may involve and since we don't want this
|
||||
* method to modify the state of the copied interpolator,
|
||||
* finalization is <strong>not</strong> done automatically, it
|
||||
* remains under user control.</p>
|
||||
|
||||
* <p>The copy is a deep copy: its arrays are separated from the
|
||||
* original arrays of the instance.</p>
|
||||
|
||||
* @param interpolator interpolator to copy from.
|
||||
|
||||
*/
|
||||
protected DummyStepInterpolator(DummyStepInterpolator interpolator) {
|
||||
super(interpolator);
|
||||
}
|
||||
|
||||
/** Copy the instance.
|
||||
* the copy is a deep copy: its arrays are separated from the
|
||||
* original arrays of the instance
|
||||
* @return a copy of the instance.
|
||||
*/
|
||||
public Object clone() {
|
||||
return new DummyStepInterpolator(this);
|
||||
}
|
||||
|
||||
/** Compute the state at the interpolated time.
|
||||
* In this class, this method does nothing: the interpolated state
|
||||
* is always the state at the end of the current step.
|
||||
* @param theta normalized interpolation abscissa within the step
|
||||
* (theta is zero at the previous time step and one at the current time step)
|
||||
* @param oneMinusThetaH time gap between the interpolated time and
|
||||
* the current time
|
||||
* @throws DerivativeException this exception is propagated to the caller if the
|
||||
* underlying user function triggers one
|
||||
*/
|
||||
protected void computeInterpolatedState(double theta, double oneMinusThetaH)
|
||||
throws DerivativeException {
|
||||
}
|
||||
|
||||
public void writeExternal(ObjectOutput out)
|
||||
throws IOException {
|
||||
// save the state of the base class
|
||||
writeBaseExternal(out);
|
||||
}
|
||||
|
||||
public void readExternal(ObjectInput in)
|
||||
throws IOException {
|
||||
|
||||
// read the base class
|
||||
double t = readBaseExternal(in);
|
||||
|
||||
try {
|
||||
// we can now set the interpolated time and state
|
||||
setInterpolatedTime(t);
|
||||
} catch (DerivativeException e) {
|
||||
IOException ioe = new IOException();
|
||||
ioe.initCause(e);
|
||||
throw ioe;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1708010296707839488L;
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This class implements a simple Euler integrator for Ordinary
|
||||
* Differential Equations.
|
||||
|
||||
* <p>The Euler algorithm is the simplest one that can be used to
|
||||
* integrate ordinary differential equations. It is a simple inversion
|
||||
* of the forward difference expression :
|
||||
* <code>f'=(f(t+h)-f(t))/h</code> which leads to
|
||||
* <code>f(t+h)=f(t)+hf'</code>. The interpolation scheme used for
|
||||
* dense output is the linear scheme already used for integration.</p>
|
||||
|
||||
* <p>This algorithm looks cheap because it needs only one function
|
||||
* evaluation per step. However, as it uses linear estimates, it needs
|
||||
* very small steps to achieve high accuracy, and small steps lead to
|
||||
* numerical errors and instabilities.</p>
|
||||
|
||||
* <p>This algorithm is almost never used and has been included in
|
||||
* this package only as a comparison reference for more useful
|
||||
* integrators.</p>
|
||||
|
||||
* @see MidpointIntegrator
|
||||
* @see ClassicalRungeKuttaIntegrator
|
||||
* @see GillIntegrator
|
||||
* @see ThreeEighthesIntegrator
|
||||
|
||||
* @version $Id: EulerIntegrator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class EulerIntegrator
|
||||
extends RungeKuttaIntegrator {
|
||||
|
||||
private static final String methodName = new String("Euler");
|
||||
|
||||
private static final double[] c = {
|
||||
};
|
||||
|
||||
private static final double[][] a = {
|
||||
};
|
||||
|
||||
private static final double[] b = {
|
||||
1.0
|
||||
};
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an Euler integrator with the given step.
|
||||
* @param step integration step
|
||||
*/
|
||||
public EulerIntegrator(double step) {
|
||||
super(false, c, a, b, new EulerStepInterpolator(), step);
|
||||
}
|
||||
|
||||
/** Get the name of the method.
|
||||
* @return name of the method
|
||||
*/
|
||||
public String getName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This class implements a linear interpolator for step.
|
||||
|
||||
* <p>This interpolator allow to compute dense output inside the last
|
||||
* step computed. The interpolation equation is consistent with the
|
||||
* integration scheme :
|
||||
|
||||
* <pre>
|
||||
* y(t_n + theta h) = y (t_n + h) - (1-theta) h y'
|
||||
* </pre>
|
||||
|
||||
* where theta belongs to [0 ; 1] and where y' is the evaluation of
|
||||
* the derivatives already computed during the step.</p>
|
||||
|
||||
* @see EulerIntegrator
|
||||
|
||||
* @version $Id: EulerStepInterpolator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
class EulerStepInterpolator
|
||||
extends RungeKuttaStepInterpolator {
|
||||
|
||||
/** Simple constructor.
|
||||
* This constructor builds an instance that is not usable yet, the
|
||||
* {@link AbstractStepInterpolator#reinitialize} method should be called
|
||||
* before using the instance in order to initialize the internal arrays. This
|
||||
* constructor is used only in order to delay the initialization in
|
||||
* some cases. The {@link RungeKuttaIntegrator} class uses the
|
||||
* prototyping design pattern to create the step interpolators by
|
||||
* cloning an uninitialized model and latter initializing the copy.
|
||||
*/
|
||||
public EulerStepInterpolator() {
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* @param interpolator interpolator to copy from. The copy is a deep
|
||||
* copy: its arrays are separated from the original arrays of the
|
||||
* instance
|
||||
*/
|
||||
public EulerStepInterpolator(EulerStepInterpolator interpolator) {
|
||||
super(interpolator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the instance.
|
||||
* the copy is a deep copy: its arrays are separated from the
|
||||
* original arrays of the instance
|
||||
* @return a copy of the instance
|
||||
*/
|
||||
public Object clone() {
|
||||
return new EulerStepInterpolator(this);
|
||||
}
|
||||
|
||||
/** Compute the state at the interpolated time.
|
||||
* This is the main processing method that should be implemented by
|
||||
* the derived classes to perform the interpolation.
|
||||
* @param theta normalized interpolation abscissa within the step
|
||||
* (theta is zero at the previous time step and one at the current time step)
|
||||
* @param oneMinusThetaH time gap between the interpolated time and
|
||||
* the current time
|
||||
* @throws DerivativeException this exception is propagated to the caller if the
|
||||
* underlying user function triggers one
|
||||
*/
|
||||
protected void computeInterpolatedState(double theta,
|
||||
double oneMinusThetaH)
|
||||
throws DerivativeException {
|
||||
|
||||
for (int i = 0; i < interpolatedState.length; ++i) {
|
||||
interpolatedState[i] = currentState[i] - oneMinusThetaH * yDotK[0][i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -7179861704951334960L;
|
||||
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/** This class converts second order differential equations to first
|
||||
* order ones.
|
||||
|
||||
* <p>This class is a wrapper around a {@link
|
||||
* SecondOrderDifferentialEquations} which allow to use a {@link
|
||||
* FirstOrderIntegrator} to integrate it.</p>
|
||||
|
||||
* <p>The transformation is done by changing the n dimension state
|
||||
* vector to a 2n dimension vector, where the first n components are
|
||||
* the initial state variables and the n last components are their
|
||||
* first time derivative. The first time derivative of this state
|
||||
* vector then really contains both the first and second time
|
||||
* derivative of the initial state vector, which can be handled by the
|
||||
* underlying second order equations set.</p>
|
||||
|
||||
* <p>One should be aware that the data is duplicated during the
|
||||
* transformation process and that for each call to {@link
|
||||
* #computeDerivatives computeDerivatives}, this wrapper does copy 4n
|
||||
* scalars : 2n before the call to {@link
|
||||
* SecondOrderDifferentialEquations#computeSecondDerivatives
|
||||
* computeSecondDerivatives} in order to dispatch the y state vector
|
||||
* into z and zDot, and 2n after the call to gather zDot and zDDot
|
||||
* into yDot. Since the underlying problem by itself perhaps also
|
||||
* needs to copy data and dispatch the arrays into domain objects,
|
||||
* this has an impact on both memory and CPU usage. The only way to
|
||||
* avoid this duplication is to perform the transformation at the
|
||||
* problem level, i.e. to implement the problem as a first order one
|
||||
* and then avoid using this class.</p>
|
||||
|
||||
* @see FirstOrderIntegrator
|
||||
* @see FirstOrderDifferentialEquations
|
||||
* @see SecondOrderDifferentialEquations
|
||||
|
||||
* @version $Id: FirstOrderConverter.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class FirstOrderConverter
|
||||
implements FirstOrderDifferentialEquations {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a converter around a second order equations set.
|
||||
* @param equations second order equations set to convert
|
||||
*/
|
||||
public FirstOrderConverter (SecondOrderDifferentialEquations equations) {
|
||||
this.equations = equations;
|
||||
dimension = equations.getDimension();
|
||||
z = new double[dimension];
|
||||
zDot = new double[dimension];
|
||||
zDDot = new double[dimension];
|
||||
}
|
||||
|
||||
public int getDimension() {
|
||||
return 2 * dimension;
|
||||
}
|
||||
|
||||
public void computeDerivatives(double t, double[] y, double[] yDot)
|
||||
throws DerivativeException {
|
||||
|
||||
// split the state vector in two
|
||||
System.arraycopy(y, 0, z, 0, dimension);
|
||||
System.arraycopy(y, dimension, zDot, 0, dimension);
|
||||
|
||||
// apply the underlying equations set
|
||||
equations.computeSecondDerivatives(t, z, zDot, zDDot);
|
||||
|
||||
// build the result state derivative
|
||||
System.arraycopy(zDot, 0, yDot, 0, dimension);
|
||||
System.arraycopy(zDDot, 0, yDot, dimension, dimension);
|
||||
|
||||
}
|
||||
|
||||
/** Underlying second order equations set. */
|
||||
private SecondOrderDifferentialEquations equations;
|
||||
|
||||
/** second order problem dimension. */
|
||||
private int dimension;
|
||||
|
||||
/** state vector. */
|
||||
private double[] z;
|
||||
|
||||
/** first time derivative of the state vector. */
|
||||
private double[] zDot;
|
||||
|
||||
/** second time derivative of the state vector. */
|
||||
private double[] zDDot;
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/** This interface represents a first order differential equations set.
|
||||
*
|
||||
* <p>This interface should be implemented by all real first order
|
||||
* differential equation problems before they can be handled by the
|
||||
* integrators {@link FirstOrderIntegrator#integrate} method.</p>
|
||||
*
|
||||
* <p>A first order differential equations problem, as seen by an
|
||||
* integrator is the time derivative <code>dY/dt</code> of a state
|
||||
* vector <code>Y</code>, both being one dimensional arrays. From the
|
||||
* integrator point of view, this derivative depends only on the
|
||||
* current time <code>t</code> and on the state vector
|
||||
* <code>Y</code>.</p>
|
||||
*
|
||||
* <p>For real problems, the derivative depends also on parameters
|
||||
* that do not belong to the state vector (dynamical model constants
|
||||
* for example). These constants are completely outside of the scope
|
||||
* of this interface, the classes that implement it are allowed to
|
||||
* handle them as they want.</p>
|
||||
*
|
||||
* @see FirstOrderIntegrator
|
||||
* @see FirstOrderConverter
|
||||
* @see SecondOrderDifferentialEquations
|
||||
* @see org.spaceroots.mantissa.utilities.ArraySliceMappable
|
||||
*
|
||||
* @version $Id: FirstOrderDifferentialEquations.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
*
|
||||
*/
|
||||
|
||||
public interface FirstOrderDifferentialEquations {
|
||||
|
||||
/** Get the dimension of the problem.
|
||||
* @return dimension of the problem
|
||||
*/
|
||||
public int getDimension();
|
||||
|
||||
/** Get the current time derivative of the state vector.
|
||||
* @param t current value of the independant <I>time</I> variable
|
||||
* @param y array containing the current value of the state vector
|
||||
* @param yDot placeholder array where to put the time derivative of the state vector
|
||||
* @throws DerivativeException this exception is propagated to the caller if the
|
||||
* underlying user function triggers one
|
||||
*/
|
||||
public void computeDerivatives(double t, double[] y, double[] yDot)
|
||||
throws DerivativeException;
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/** This interface represents a first order integrator for
|
||||
* differential equations.
|
||||
|
||||
* <p>The classes which are devoted to solve first order differential
|
||||
* equations should implement this interface. The problems which can
|
||||
* be handled should implement the {@link
|
||||
* FirstOrderDifferentialEquations} interface.</p>
|
||||
|
||||
* @see FirstOrderDifferentialEquations
|
||||
* @see StepHandler
|
||||
* @see SwitchingFunction
|
||||
|
||||
* @version $Id: FirstOrderIntegrator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public interface FirstOrderIntegrator {
|
||||
|
||||
/** Get the name of the method.
|
||||
* @return name of the method
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/** Set the step handler for this integrator.
|
||||
* The handler will be called by the integrator for each accepted
|
||||
* step.
|
||||
* @param handler handler for the accepted steps
|
||||
*/
|
||||
public void setStepHandler (StepHandler handler);
|
||||
|
||||
/** Get the step handler for this integrator.
|
||||
* @return the step handler for this integrator
|
||||
*/
|
||||
public StepHandler getStepHandler();
|
||||
|
||||
/** Add a switching function to the integrator.
|
||||
* @param function switching function
|
||||
* @param maxCheckInterval maximal time interval between switching
|
||||
* function checks (this interval prevents missing sign changes in
|
||||
* case the integration steps becomes very large)
|
||||
* @param convergence convergence threshold in the event time search
|
||||
*/
|
||||
public void addSwitchingFunction(SwitchingFunction function,
|
||||
double maxCheckInterval,
|
||||
double convergence);
|
||||
|
||||
/** Integrate the differential equations up to the given time
|
||||
* @param equations differential equations to integrate
|
||||
* @param t0 initial time
|
||||
* @param y0 initial value of the state vector at t0
|
||||
* @param t target time for the integration
|
||||
* (can be set to a value smaller thant <code>t0</code> for backward integration)
|
||||
* @param y placeholder where to put the state vector at each successful
|
||||
* step (and hence at the end of integration), can be the same object as y0
|
||||
* @throws IntegratorException if the integrator cannot perform integration
|
||||
* @throws DerivativeException this exception is propagated to the caller if
|
||||
* the underlying user function triggers one
|
||||
*/
|
||||
public void integrate (FirstOrderDifferentialEquations equations,
|
||||
double t0, double[] y0,
|
||||
double t, double[] y)
|
||||
throws DerivativeException, IntegratorException;
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This interface represents a handler that should be called after
|
||||
* each successful fixed step.
|
||||
|
||||
* <p>This interface should be implemented by anyone who is interested
|
||||
* in getting the solution of an ordinary differential equation at
|
||||
* fixed time steps. Objects implementing this interface should be
|
||||
* wrapped within an instance of {@link StepNormalizer} that itself
|
||||
* is used as the general {@link StepHandler} by the integrator. The
|
||||
* {@link StepNormalizer} object is called according to the integrator
|
||||
* internal algorithms and it calls objects implementing this
|
||||
* interface as necessary at fixed time steps.</p>
|
||||
|
||||
* @see StepHandler
|
||||
* @see StepNormalizer
|
||||
|
||||
* @version $Id: FixedStepHandler.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public interface FixedStepHandler {
|
||||
|
||||
/**
|
||||
* Handle the last accepted step
|
||||
* @param t time of the current step
|
||||
|
||||
* @param y state vector at t. For efficiency purposes, the {@link
|
||||
* StepNormalizer} class reuse the same array on each call, so if
|
||||
* the instance wants to keep it across all calls (for example to
|
||||
* provide at the end of the integration a complete array of all
|
||||
* steps), it should build a local copy store this copy.
|
||||
|
||||
* @param isLast true if the step is the last one
|
||||
*/
|
||||
public void handleStep(double t, double[] y, boolean isLast);
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This class implements the Gill fourth order Runge-Kutta
|
||||
* integrator for Ordinary Differential Equations .
|
||||
|
||||
* <p>This method is an explicit Runge-Kutta method, its Butcher-array
|
||||
* is the following one :
|
||||
* <pre>
|
||||
* 0 | 0 0 0 0
|
||||
* 1/2 | 1/2 0 0 0
|
||||
* 1/2 | (q-1)/2 (2-q)/2 0 0
|
||||
* 1 | 0 -q/2 (2+q)/2 0
|
||||
* |-------------------------------
|
||||
* | 1/6 (2-q)/6 (2+q)/6 1/6
|
||||
* </pre>
|
||||
* where q = sqrt(2)</p>
|
||||
|
||||
* @see EulerIntegrator
|
||||
* @see ClassicalRungeKuttaIntegrator
|
||||
* @see MidpointIntegrator
|
||||
* @see ThreeEighthesIntegrator
|
||||
|
||||
* @version $Id: GillIntegrator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class GillIntegrator
|
||||
extends RungeKuttaIntegrator {
|
||||
|
||||
private static final String methodName = new String("Gill");
|
||||
|
||||
private static final double sqrt2 = Math.sqrt(2.0);
|
||||
|
||||
private static final double[] c = {
|
||||
1.0 / 2.0, 1.0 / 2.0, 1.0
|
||||
};
|
||||
|
||||
private static final double[][] a = {
|
||||
{ 1.0 / 2.0 },
|
||||
{ (sqrt2 - 1.0) / 2.0, (2.0 - sqrt2) / 2.0 },
|
||||
{ 0.0, -sqrt2 / 2.0, (2.0 + sqrt2) / 2.0 }
|
||||
};
|
||||
|
||||
private static final double[] b = {
|
||||
1.0 / 6.0, (2.0 - sqrt2) / 6.0, (2.0 + sqrt2) / 6.0, 1.0 / 6.0
|
||||
};
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a fourth-order Gill integrator with the given step.
|
||||
* @param step integration step
|
||||
*/
|
||||
public GillIntegrator(double step) {
|
||||
super(false, c, a, b, new GillStepInterpolator(), step);
|
||||
}
|
||||
|
||||
/** Get the name of the method.
|
||||
* @return name of the method
|
||||
*/
|
||||
public String getName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This class implements a step interpolator for the Gill fourth
|
||||
* order Runge-Kutta integrator.
|
||||
|
||||
* <p>This interpolator allows to compute dense output inside the last
|
||||
* step computed. The interpolation equation is consistent with the
|
||||
* integration scheme :
|
||||
|
||||
* <pre>
|
||||
* y(t_n + theta h) = y (t_n + h)
|
||||
* - (1 - theta) (h/6) [ (1 - theta) (1 - 4 theta) y'_1
|
||||
* + (1 - theta) (1 + 2 theta) ((2-q) y'_2 + (2+q) y'_3)
|
||||
* + (1 + theta + 4 theta^2) y'_4
|
||||
* ]
|
||||
* </pre>
|
||||
* where theta belongs to [0 ; 1], q = sqrt(2) and where y'_1 to y'_4
|
||||
* are the four evaluations of the derivatives already computed during
|
||||
* the step.</p>
|
||||
|
||||
* @see GillIntegrator
|
||||
|
||||
* @version $Id: GillStepInterpolator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
class GillStepInterpolator
|
||||
extends RungeKuttaStepInterpolator {
|
||||
|
||||
/** Simple constructor.
|
||||
* This constructor builds an instance that is not usable yet, the
|
||||
* {@link AbstractStepInterpolator#reinitialize} method should be called
|
||||
* before using the instance in order to initialize the internal arrays. This
|
||||
* constructor is used only in order to delay the initialization in
|
||||
* some cases. The {@link RungeKuttaIntegrator} class uses the
|
||||
* prototyping design pattern to create the step interpolators by
|
||||
* cloning an uninitialized model and latter initializing the copy.
|
||||
*/
|
||||
public GillStepInterpolator() {
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* @param interpolator interpolator to copy from. The copy is a deep
|
||||
* copy: its arrays are separated from the original arrays of the
|
||||
* instance
|
||||
*/
|
||||
public GillStepInterpolator(GillStepInterpolator interpolator) {
|
||||
super(interpolator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the instance.
|
||||
* the copy is a deep copy: its arrays are separated from the
|
||||
* original arrays of the instance
|
||||
* @return a copy of the instance
|
||||
*/
|
||||
public Object clone() {
|
||||
return new GillStepInterpolator(this);
|
||||
}
|
||||
|
||||
/** Compute the state at the interpolated time.
|
||||
* This is the main processing method that should be implemented by
|
||||
* the derived classes to perform the interpolation.
|
||||
* @param theta normalized interpolation abscissa within the step
|
||||
* (theta is zero at the previous time step and one at the current time step)
|
||||
* @param oneMinusThetaH time gap between the interpolated time and
|
||||
* the current time
|
||||
* @throws DerivativeException this exception is propagated to the caller if the
|
||||
* underlying user function triggers one
|
||||
*/
|
||||
protected void computeInterpolatedState(double theta,
|
||||
double oneMinusThetaH)
|
||||
throws DerivativeException {
|
||||
|
||||
double fourTheta = 4 * theta;
|
||||
double s = oneMinusThetaH / 6.0;
|
||||
double soMt = s * (1 - theta);
|
||||
double c23 = soMt * (1 + 2 * theta);
|
||||
double coeff1 = soMt * (1 - fourTheta);
|
||||
double coeff2 = c23 * tMq;
|
||||
double coeff3 = c23 * tPq;
|
||||
double coeff4 = s * (1 + theta * (1 + fourTheta));
|
||||
|
||||
for (int i = 0; i < interpolatedState.length; ++i) {
|
||||
interpolatedState[i] = currentState[i]
|
||||
- coeff1 * yDotK[0][i] - coeff2 * yDotK[1][i]
|
||||
- coeff3 * yDotK[2][i] - coeff4 * yDotK[3][i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** First Gill coefficient. */
|
||||
private static final double tMq = 2 - Math.sqrt(2.0);
|
||||
|
||||
/** Second Gill coefficient. */
|
||||
private static final double tPq = 2 + Math.sqrt(2.0);
|
||||
|
||||
private static final long serialVersionUID = -107804074496313322L;
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,404 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class implements an interpolator for the Gragg-Bulirsch-Stoer
|
||||
* integrator.
|
||||
|
||||
* <p>This interpolator compute dense output inside the last step
|
||||
* produced by a Gragg-Bulirsch-Stoer integrator.</p>
|
||||
|
||||
* <p>
|
||||
* This implementation is basically a reimplementation in Java of the
|
||||
* <a
|
||||
* href="http://www.unige.ch/math/folks/hairer/prog/nonstiff/odex.f">odex</a>
|
||||
* fortran code by E. Hairer and G. Wanner. The redistribution policy
|
||||
* for this code is available <a
|
||||
* href="http://www.unige.ch/~hairer/prog/licence.txt">here</a>, for
|
||||
* convenience, it is reproduced below.</p>
|
||||
* </p>
|
||||
|
||||
* <table border="0" width="80%" cellpadding="10" align="center" bgcolor="#E0E0E0">
|
||||
* <tr><td>Copyright (c) 2004, Ernst Hairer</td></tr>
|
||||
|
||||
* <tr><td>Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
* <ul>
|
||||
* <li>Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.</li>
|
||||
* <li>Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.</li>
|
||||
* </ul></td></tr>
|
||||
|
||||
* <tr><td><strong>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</strong></td></tr>
|
||||
* </table>
|
||||
|
||||
* @see GraggBulirschStoerIntegrator
|
||||
|
||||
* @version $Id: GraggBulirschStoerStepInterpolator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author E. Hairer and G. Wanner (fortran version)
|
||||
* @author L. Maisonobe (Java port)
|
||||
|
||||
*/
|
||||
|
||||
class GraggBulirschStoerStepInterpolator
|
||||
extends AbstractStepInterpolator {
|
||||
|
||||
/** Slope at the beginning of the step. */
|
||||
private double[] y0Dot;
|
||||
|
||||
/** State at the end of the step. */
|
||||
private double[] y1;
|
||||
|
||||
/** Slope at the end of the step. */
|
||||
private double[] y1Dot;
|
||||
|
||||
/** Derivatives at the middle of the step.
|
||||
* element 0 is state at midpoint, element 1 is first derivative ...
|
||||
*/
|
||||
private double[][] yMidDots;
|
||||
|
||||
/** Interpolation polynoms. */
|
||||
private double[][] polynoms;
|
||||
|
||||
/** Error coefficients for the interpolation. */
|
||||
private double[] errfac;
|
||||
|
||||
/** Degree of the interpolation polynoms. */
|
||||
private int currentDegree;
|
||||
|
||||
/** Reallocate the internal tables.
|
||||
* Reallocate the internal tables in order to be able to handle
|
||||
* interpolation polynoms up to the given degree
|
||||
* @param maxDegree maximal degree to handle
|
||||
*/
|
||||
private void resetTables(int maxDegree) {
|
||||
|
||||
if (maxDegree < 0) {
|
||||
polynoms = null;
|
||||
errfac = null;
|
||||
currentDegree = -1;
|
||||
} else {
|
||||
|
||||
double[][] newPols = new double[maxDegree + 1][];
|
||||
if (polynoms != null) {
|
||||
System.arraycopy(polynoms, 0, newPols, 0, polynoms.length);
|
||||
for (int i = polynoms.length; i < newPols.length; ++i) {
|
||||
newPols[i] = new double[currentState.length];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < newPols.length; ++i) {
|
||||
newPols[i] = new double[currentState.length];
|
||||
}
|
||||
}
|
||||
polynoms = newPols;
|
||||
|
||||
// initialize the error factors array for interpolation
|
||||
if (maxDegree <= 4) {
|
||||
errfac = null;
|
||||
} else {
|
||||
errfac = new double[maxDegree - 4];
|
||||
for (int i = 0; i < errfac.length; ++i) {
|
||||
int ip5 = i + 5;
|
||||
errfac[i] = 1.0 / (ip5 * ip5);
|
||||
double e = 0.5 * Math.sqrt (((double) (i + 1)) / ip5);
|
||||
for (int j = 0; j <= i; ++j) {
|
||||
errfac[i] *= e / (j + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentDegree = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* This constructor should not be used directly, it is only intended
|
||||
* for the serialization process.
|
||||
*/
|
||||
public GraggBulirschStoerStepInterpolator() {
|
||||
y0Dot = null;
|
||||
y1 = null;
|
||||
y1Dot = null;
|
||||
yMidDots = null;
|
||||
resetTables(-1);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* @param y reference to the integrator array holding the current state
|
||||
* @param y0Dot reference to the integrator array holding the slope
|
||||
* at the beginning of the step
|
||||
* @param y1 reference to the integrator array holding the state at
|
||||
* the end of the step
|
||||
* @param y1Dot reference to the integrator array holding the slope
|
||||
* at theend of the step
|
||||
* @param yMidDots reference to the integrator array holding the
|
||||
* derivatives at the middle point of the step
|
||||
* @param forward integration direction indicator
|
||||
*/
|
||||
public GraggBulirschStoerStepInterpolator(double[] y, double[] y0Dot,
|
||||
double[] y1, double[] y1Dot,
|
||||
double[][] yMidDots,
|
||||
boolean forward) {
|
||||
|
||||
super(y, forward);
|
||||
this.y0Dot = y0Dot;
|
||||
this.y1 = y1;
|
||||
this.y1Dot = y1Dot;
|
||||
this.yMidDots = yMidDots;
|
||||
|
||||
resetTables(yMidDots.length + 4);
|
||||
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* @param interpolator interpolator to copy from. The copy is a deep
|
||||
* copy: its arrays are separated from the original arrays of the
|
||||
* instance
|
||||
*/
|
||||
public GraggBulirschStoerStepInterpolator
|
||||
(GraggBulirschStoerStepInterpolator interpolator) {
|
||||
|
||||
super(interpolator);
|
||||
|
||||
int dimension = currentState.length;
|
||||
|
||||
// the interpolator has been finalized,
|
||||
// the following arrays are not needed anymore
|
||||
y0Dot = null;
|
||||
y1 = null;
|
||||
y1Dot = null;
|
||||
yMidDots = null;
|
||||
|
||||
// copy the interpolation polynoms (up to the current degree only)
|
||||
if (interpolator.polynoms == null) {
|
||||
polynoms = null;
|
||||
currentDegree = -1;
|
||||
} else {
|
||||
resetTables(interpolator.currentDegree);
|
||||
for (int i = 0; i < polynoms.length; ++i) {
|
||||
polynoms[i] = new double[dimension];
|
||||
System.arraycopy(interpolator.polynoms[i], 0,
|
||||
polynoms[i], 0, dimension);
|
||||
}
|
||||
currentDegree = interpolator.currentDegree;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the instance.
|
||||
* the copy is a deep copy: its arrays are separated from the
|
||||
* original arrays of the instance
|
||||
* @return a copy of the instance
|
||||
*/
|
||||
public Object clone() {
|
||||
return new GraggBulirschStoerStepInterpolator(this);
|
||||
}
|
||||
|
||||
/** Compute the interpolation coefficients for dense output.
|
||||
* @param mu degree of the interpolation polynom
|
||||
* @param h current step
|
||||
*/
|
||||
public void computeCoefficients(int mu, double h) {
|
||||
|
||||
if ((polynoms == null) || (polynoms.length <= (mu + 4))) {
|
||||
resetTables(mu + 4);
|
||||
}
|
||||
|
||||
currentDegree = mu + 4;
|
||||
|
||||
for (int i = 0; i < currentState.length; ++i) {
|
||||
|
||||
double yp0 = h * y0Dot[i];
|
||||
double yp1 = h * y1Dot[i];
|
||||
double ydiff = y1[i] - currentState[i];
|
||||
double aspl = ydiff - yp1;
|
||||
double bspl = yp0 - ydiff;
|
||||
|
||||
polynoms[0][i] = currentState[i];
|
||||
polynoms[1][i] = ydiff;
|
||||
polynoms[2][i] = aspl;
|
||||
polynoms[3][i] = bspl;
|
||||
|
||||
if (mu < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// compute the remaining coefficients
|
||||
double ph0 = 0.5 * (currentState[i] + y1[i]) + 0.125 * (aspl + bspl);
|
||||
polynoms[4][i] = 16 * (yMidDots[0][i] - ph0);
|
||||
|
||||
if (mu > 0) {
|
||||
double ph1 = ydiff + 0.25 * (aspl - bspl);
|
||||
polynoms[5][i] = 16 * (yMidDots[1][i] - ph1);
|
||||
|
||||
if (mu > 1) {
|
||||
double ph2 = yp1 - yp0;
|
||||
polynoms[6][i] = 16 * (yMidDots[2][i] - ph2 + polynoms[4][i]);
|
||||
|
||||
if (mu > 2) {
|
||||
double ph3 = 6 * (bspl - aspl);
|
||||
polynoms[7][i] = 16 * (yMidDots[3][i] - ph3 + 3 * polynoms[5][i]);
|
||||
|
||||
for (int j = 4; j <= mu; ++j) {
|
||||
double fac1 = 0.5 * j * (j - 1);
|
||||
double fac2 = 2 * fac1 * (j - 2) * (j - 3);
|
||||
polynoms[j+4][i] = 16 * (yMidDots[j][i]
|
||||
+ fac1 * polynoms[j+2][i]
|
||||
- fac2 * polynoms[j][i]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Estimate interpolation error.
|
||||
* @param scale scaling array
|
||||
* @return estimate of the interpolation error
|
||||
*/
|
||||
public double estimateError(double[] scale) {
|
||||
double error = 0;
|
||||
if (currentDegree >= 5) {
|
||||
for (int i = 0; i < currentState.length; ++i) {
|
||||
double e = polynoms[currentDegree][i] / scale[i];
|
||||
error += e * e;
|
||||
}
|
||||
error = Math.sqrt(error / currentState.length) * errfac[currentDegree-5];
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/** Compute the state at the interpolated time.
|
||||
* This is the main processing method that should be implemented by
|
||||
* the derived classes to perform the interpolation.
|
||||
* @param theta normalized interpolation abscissa within the step
|
||||
* (theta is zero at the previous time step and one at the current time step)
|
||||
* @param oneMinusThetaH time gap between the interpolated time and
|
||||
* the current time
|
||||
* @throws DerivativeException this exception is propagated to the caller if the
|
||||
* underlying user function triggers one
|
||||
*/
|
||||
protected void computeInterpolatedState(double theta,
|
||||
double oneMinusThetaH)
|
||||
throws DerivativeException {
|
||||
|
||||
int dimension = currentState.length;
|
||||
|
||||
double oneMinusTheta = 1.0 - theta;
|
||||
double theta05 = theta - 0.5;
|
||||
double t4 = theta * oneMinusTheta;
|
||||
t4 = t4 * t4;
|
||||
|
||||
for (int i = 0; i < dimension; ++i) {
|
||||
interpolatedState[i] = polynoms[0][i]
|
||||
+ theta * (polynoms[1][i]
|
||||
+ oneMinusTheta * (polynoms[2][i] * theta
|
||||
+ polynoms[3][i] * oneMinusTheta));
|
||||
|
||||
if (currentDegree > 3) {
|
||||
double c = polynoms[currentDegree][i];
|
||||
for (int j = currentDegree - 1; j > 3; --j) {
|
||||
c = polynoms[j][i] + c * theta05 / (j - 3);
|
||||
}
|
||||
interpolatedState[i] += t4 * c;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Save the state of the instance.
|
||||
* @param out stream where to save the state
|
||||
* @exception IOException in case of write error
|
||||
*/
|
||||
public void writeExternal(ObjectOutput out)
|
||||
throws IOException {
|
||||
|
||||
int dimension = currentState.length;
|
||||
|
||||
// save the state of the base class
|
||||
writeBaseExternal(out);
|
||||
|
||||
// save the local attributes (but not the temporary vectors)
|
||||
out.writeInt(currentDegree);
|
||||
for (int k = 0; k <= currentDegree; ++k) {
|
||||
for (int l = 0; l < dimension; ++l) {
|
||||
out.writeDouble(polynoms[k][l]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Read the state of the instance.
|
||||
* @param in stream where to read the state from
|
||||
* @exception IOException in case of read error
|
||||
*/
|
||||
public void readExternal(ObjectInput in)
|
||||
throws IOException {
|
||||
|
||||
// read the base class
|
||||
double t = readBaseExternal(in);
|
||||
int dimension = currentState.length;
|
||||
|
||||
// read the local attributes
|
||||
int degree = in.readInt();
|
||||
resetTables(degree);
|
||||
currentDegree = degree;
|
||||
|
||||
for (int k = 0; k <= currentDegree; ++k) {
|
||||
for (int l = 0; l < dimension; ++l) {
|
||||
polynoms[k][l] = in.readDouble();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// we can now set the interpolated time and state
|
||||
setInterpolatedTime(t);
|
||||
} catch (DerivativeException e) {
|
||||
IOException ioe = new IOException();
|
||||
ioe.initCause(e);
|
||||
throw ioe;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 7320613236731409847L;
|
||||
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This class implements the 5(4) Higham and Hall integrator for
|
||||
* Ordinary Differential Equations.
|
||||
|
||||
* <p>This integrator is an embedded Runge-Kutta-Fehlberg integrator
|
||||
* of order 5(4) used in local extrapolation mode (i.e. the solution
|
||||
* is computed using the high order formula) with stepsize control
|
||||
* (and automatic step initialization) and continuous output. This
|
||||
* method uses 7 functions evaluations per step.</p>
|
||||
|
||||
* @version $Id: HighamHall54Integrator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class HighamHall54Integrator
|
||||
extends RungeKuttaFehlbergIntegrator {
|
||||
|
||||
private static final String methodName = new String("Higham-Hall 5(4)");
|
||||
|
||||
private static final double[] c = {
|
||||
2.0/9.0, 1.0/3.0, 1.0/2.0, 3.0/5.0, 1.0, 1.0
|
||||
};
|
||||
|
||||
private static final double[][] a = {
|
||||
{2.0/9.0},
|
||||
{1.0/12.0, 1.0/4.0},
|
||||
{1.0/8.0, 0.0, 3.0/8.0},
|
||||
{91.0/500.0, -27.0/100.0, 78.0/125.0, 8.0/125.0},
|
||||
{-11.0/20.0, 27.0/20.0, 12.0/5.0, -36.0/5.0, 5.0},
|
||||
{1.0/12.0, 0.0, 27.0/32.0, -4.0/3.0, 125.0/96.0, 5.0/48.0}
|
||||
};
|
||||
|
||||
private static final double[] b = {
|
||||
1.0/12.0, 0.0, 27.0/32.0, -4.0/3.0, 125.0/96.0, 5.0/48.0, 0.0
|
||||
};
|
||||
|
||||
private static final double[] e = {
|
||||
-1.0/20.0, 0.0, 81.0/160.0, -6.0/5.0, 25.0/32.0, 1.0/16.0, -1.0/10.0
|
||||
};
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a fifth order Higham and Hall integrator with the given step bounds
|
||||
* @param minStep minimal step (must be positive even for backward
|
||||
* integration), the last step can be smaller than this
|
||||
* @param maxStep maximal step (must be positive even for backward
|
||||
* integration)
|
||||
* @param scalAbsoluteTolerance allowed absolute error
|
||||
* @param scalRelativeTolerance allowed relative error
|
||||
*/
|
||||
public HighamHall54Integrator(double minStep, double maxStep,
|
||||
double scalAbsoluteTolerance,
|
||||
double scalRelativeTolerance) {
|
||||
super(false, c, a, b, new HighamHall54StepInterpolator(),
|
||||
minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance);
|
||||
}
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a fifth order Higham and Hall integrator with the given step bounds
|
||||
* @param minStep minimal step (must be positive even for backward
|
||||
* integration), the last step can be smaller than this
|
||||
* @param maxStep maximal step (must be positive even for backward
|
||||
* integration)
|
||||
* @param vecAbsoluteTolerance allowed absolute error
|
||||
* @param vecRelativeTolerance allowed relative error
|
||||
*/
|
||||
public HighamHall54Integrator(double minStep, double maxStep,
|
||||
double[] vecAbsoluteTolerance,
|
||||
double[] vecRelativeTolerance) {
|
||||
super(false, c, a, b, new HighamHall54StepInterpolator(),
|
||||
minStep, maxStep, vecAbsoluteTolerance, vecRelativeTolerance);
|
||||
}
|
||||
|
||||
/** Get the name of the method.
|
||||
* @return name of the method
|
||||
*/
|
||||
public String getName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
/** Get the order of the method.
|
||||
* @return order of the method
|
||||
*/
|
||||
public int getOrder() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
/** Compute the error ratio.
|
||||
* @param yDotK derivatives computed during the first stages
|
||||
* @param y0 estimate of the step at the start of the step
|
||||
* @param y1 estimate of the step at the end of the step
|
||||
* @param h current step
|
||||
* @return error ratio, greater than 1 if step should be rejected
|
||||
*/
|
||||
protected double estimateError(double[][] yDotK,
|
||||
double[] y0, double[] y1,
|
||||
double h) {
|
||||
|
||||
double error = 0;
|
||||
|
||||
for (int j = 0; j < y0.length; ++j) {
|
||||
double errSum = e[0] * yDotK[0][j];
|
||||
for (int l = 1; l < e.length; ++l) {
|
||||
errSum += e[l] * yDotK[l][j];
|
||||
}
|
||||
|
||||
double yScale = Math.max(Math.abs(y0[j]), Math.abs(y1[j]));
|
||||
double tol = (vecAbsoluteTolerance == null)
|
||||
? (scalAbsoluteTolerance + scalRelativeTolerance * yScale)
|
||||
: (vecAbsoluteTolerance[j] + vecRelativeTolerance[j] * yScale);
|
||||
double ratio = h * errSum / tol;
|
||||
error += ratio * ratio;
|
||||
|
||||
}
|
||||
|
||||
return Math.sqrt(error / y0.length);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This class represents an interpolator over the last step during an
|
||||
* ODE integration for the 5(4) Higham and Hall integrator.
|
||||
*
|
||||
* @see HighamHall54Integrator
|
||||
*
|
||||
* @version $Id: HighamHall54StepInterpolator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
*
|
||||
*/
|
||||
|
||||
class HighamHall54StepInterpolator
|
||||
extends RungeKuttaStepInterpolator {
|
||||
|
||||
/** Simple constructor.
|
||||
* This constructor builds an instance that is not usable yet, the
|
||||
* {@link AbstractStepInterpolator#reinitialize} method should be called
|
||||
* before using the instance in order to initialize the internal arrays. This
|
||||
* constructor is used only in order to delay the initialization in
|
||||
* some cases. The {@link RungeKuttaFehlbergIntegrator} uses the
|
||||
* prototyping design pattern to create the step interpolators by
|
||||
* cloning an uninitialized model and latter initializing the copy.
|
||||
*/
|
||||
public HighamHall54StepInterpolator() {
|
||||
super();
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* @param interpolator interpolator to copy from. The copy is a deep
|
||||
* copy: its arrays are separated from the original arrays of the
|
||||
* instance
|
||||
*/
|
||||
public HighamHall54StepInterpolator(HighamHall54StepInterpolator interpolator) {
|
||||
super(interpolator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the instance.
|
||||
* the copy is a deep copy: its arrays are separated from the
|
||||
* original arrays of the instance
|
||||
* @return a copy of the instance
|
||||
*/
|
||||
public Object clone() {
|
||||
return new HighamHall54StepInterpolator(this);
|
||||
}
|
||||
|
||||
/** Compute the state at the interpolated time.
|
||||
* @param theta normalized interpolation abscissa within the step
|
||||
* (theta is zero at the previous time step and one at the current time step)
|
||||
* @param oneMinusThetaH time gap between the interpolated time and
|
||||
* the current time
|
||||
* @throws DerivativeException this exception is propagated to the caller if the
|
||||
* underlying user function triggers one
|
||||
*/
|
||||
protected void computeInterpolatedState(double theta,
|
||||
double oneMinusThetaH)
|
||||
throws DerivativeException {
|
||||
|
||||
double theta2 = theta * theta;
|
||||
|
||||
double b0 = h * (-1.0/12.0 + theta * (1.0 + theta * (-15.0/4.0 + theta * (16.0/3.0 + theta * -5.0/2.0))));
|
||||
double b2 = h * (-27.0/32.0 + theta2 * (459.0/32.0 + theta * (-243.0/8.0 + theta * 135.0/8.0)));
|
||||
double b3 = h * (4.0/3.0 + theta2 * (-22.0 + theta * (152.0/3.0 + theta * -30.0)));
|
||||
double b4 = h * (-125.0/96.0 + theta2 * (375.0/32.0 + theta * (-625.0/24.0 + theta * 125.0/8.0)));
|
||||
double b5 = h * (-5.0/48.0 + theta2 * (-5.0/16.0 + theta * 5.0/12.0));
|
||||
|
||||
for (int i = 0; i < interpolatedState.length; ++i) {
|
||||
interpolatedState[i] = currentState[i]
|
||||
+ b0 * yDotK[0][i] + b2 * yDotK[2][i] + b3 * yDotK[3][i]
|
||||
+ b4 * yDotK[4][i] + b5 * yDotK[5][i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -3583240427587318654L;
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
import org.spaceroots.mantissa.MantissaException;
|
||||
|
||||
/**
|
||||
* This exception is made available to users to report
|
||||
* the error conditions that are triggered during integration
|
||||
* @author Luc Maisonobe
|
||||
* @version $Id: IntegratorException.java 1705 2006-09-17 19:57:39Z luc $
|
||||
*/
|
||||
public class IntegratorException
|
||||
extends MantissaException {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build an exception by translating and formating a message
|
||||
* @param specifier format specifier (to be translated)
|
||||
* @param parts to insert in the format (no translation)
|
||||
*/
|
||||
public IntegratorException(String specifier, String[] parts) {
|
||||
super(specifier, parts);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -1390328069787882608L;
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This class implements a second order Runge-Kutta integrator for
|
||||
* Ordinary Differential Equations.
|
||||
|
||||
* <p>This method is an explicit Runge-Kutta method, its Butcher-array
|
||||
* is the following one :
|
||||
* <pre>
|
||||
* 0 | 0 0
|
||||
* 1/2 | 1/2 0
|
||||
* |----------
|
||||
* | 0 1
|
||||
* </pre>
|
||||
* </p>
|
||||
|
||||
* @see EulerIntegrator
|
||||
* @see ClassicalRungeKuttaIntegrator
|
||||
* @see GillIntegrator
|
||||
|
||||
* @version $Id: MidpointIntegrator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public class MidpointIntegrator
|
||||
extends RungeKuttaIntegrator {
|
||||
|
||||
private static final String methodName = new String("midpoint");
|
||||
|
||||
private static final double[] c = {
|
||||
1.0 / 2.0
|
||||
};
|
||||
|
||||
private static final double[][] a = {
|
||||
{ 1.0 / 2.0 }
|
||||
};
|
||||
|
||||
private static final double[] b = {
|
||||
0.0, 1.0
|
||||
};
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a midpoint integrator with the given step.
|
||||
* @param step integration step
|
||||
*/
|
||||
public MidpointIntegrator(double step) {
|
||||
super(false, c, a, b, new MidpointStepInterpolator(), step);
|
||||
}
|
||||
|
||||
/** Get the name of the method.
|
||||
* @return name of the method
|
||||
*/
|
||||
public String getName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This class implements a step interpolator for second order
|
||||
* Runge-Kutta integrator.
|
||||
|
||||
* <p>This interpolator allow to compute dense output inside the last
|
||||
* step computed. The interpolation equation is consistent with the
|
||||
* integration scheme :
|
||||
|
||||
* <pre>
|
||||
* y(t_n + theta h) = y (t_n + h) + (1-theta) h [theta y'_1 - (1+theta) y'_2]
|
||||
* </pre>
|
||||
|
||||
* where theta belongs to [0 ; 1] and where y'_1 and y'_2 are the two
|
||||
* evaluations of the derivatives already computed during the
|
||||
* step.</p>
|
||||
|
||||
* @see MidpointIntegrator
|
||||
|
||||
* @version $Id: MidpointStepInterpolator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
class MidpointStepInterpolator
|
||||
extends RungeKuttaStepInterpolator {
|
||||
|
||||
/** Simple constructor.
|
||||
* This constructor builds an instance that is not usable yet, the
|
||||
* {@link AbstractStepInterpolator#reinitialize} method should be called
|
||||
* before using the instance in order to initialize the internal arrays. This
|
||||
* constructor is used only in order to delay the initialization in
|
||||
* some cases. The {@link RungeKuttaIntegrator} class uses the
|
||||
* prototyping design pattern to create the step interpolators by
|
||||
* cloning an uninitialized model and latter initializing the copy.
|
||||
*/
|
||||
public MidpointStepInterpolator() {
|
||||
}
|
||||
|
||||
/** Copy constructor.
|
||||
* @param interpolator interpolator to copy from. The copy is a deep
|
||||
* copy: its arrays are separated from the original arrays of the
|
||||
* instance
|
||||
*/
|
||||
public MidpointStepInterpolator(MidpointStepInterpolator interpolator) {
|
||||
super(interpolator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the instance.
|
||||
* the copy is a deep copy: its arrays are separated from the
|
||||
* original arrays of the instance
|
||||
* @return a copy of the instance
|
||||
*/
|
||||
public Object clone() {
|
||||
return new MidpointStepInterpolator(this);
|
||||
}
|
||||
|
||||
/** Compute the state at the interpolated time.
|
||||
* This is the main processing method that should be implemented by
|
||||
* the derived classes to perform the interpolation.
|
||||
* @param theta normalized interpolation abscissa within the step
|
||||
* (theta is zero at the previous time step and one at the current time step)
|
||||
* @param oneMinusThetaH time gap between the interpolated time and
|
||||
* the current time
|
||||
* @throws DerivativeException this exception is propagated to the caller if the
|
||||
* underlying user function triggers one
|
||||
*/
|
||||
protected void computeInterpolatedState(double theta,
|
||||
double oneMinusThetaH)
|
||||
throws DerivativeException {
|
||||
|
||||
double coeff1 = oneMinusThetaH * theta;
|
||||
double coeff2 = oneMinusThetaH * (1.0 + theta);
|
||||
|
||||
for (int i = 0; i < interpolatedState.length; ++i) {
|
||||
interpolatedState[i] = currentState[i]
|
||||
+ coeff1 * yDotK[0][i] - coeff2 * yDotK[1][i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -865524111506042509L;
|
||||
|
||||
}
|
|
@ -0,0 +1,397 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This class implements the common part of all Runge-Kutta-Fehlberg
|
||||
* integrators for Ordinary Differential Equations.
|
||||
|
||||
* <p>These methods are embedded explicit Runge-Kutta methods with two
|
||||
* sets of coefficients allowing to estimate the error, their Butcher
|
||||
* arrays are as follows :
|
||||
* <pre>
|
||||
* 0 |
|
||||
* c2 | a21
|
||||
* c3 | a31 a32
|
||||
* ... | ...
|
||||
* cs | as1 as2 ... ass-1
|
||||
* |--------------------------
|
||||
* | b1 b2 ... bs-1 bs
|
||||
* | b'1 b'2 ... b's-1 b's
|
||||
* </pre>
|
||||
* </p>
|
||||
|
||||
* <p>In fact, we rather use the array defined by ej = bj - b'j to
|
||||
* compute directly the error rather than computing two estimates and
|
||||
* then comparing them.</p>
|
||||
|
||||
* <p>Some methods are qualified as <i>fsal</i> (first same as last)
|
||||
* methods. This means the last evaluation of the derivatives in one
|
||||
* step is the same as the first in the next step. Then, this
|
||||
* evaluation can be reused from one step to the next one and the cost
|
||||
* of such a method is really s-1 evaluations despite the method still
|
||||
* has s stages. This behaviour is true only for successful steps, if
|
||||
* the step is rejected after the error estimation phase, no
|
||||
* evaluation is saved. For an <i>fsal</i> method, we have cs = 1 and
|
||||
* asi = bi for all i.</p>
|
||||
|
||||
* @version $Id: RungeKuttaFehlbergIntegrator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public abstract class RungeKuttaFehlbergIntegrator
|
||||
extends AdaptiveStepsizeIntegrator {
|
||||
|
||||
/** Build a Runge-Kutta integrator with the given Butcher array.
|
||||
* @param fsal indicate that the method is an <i>fsal</i>
|
||||
* @param c time steps from Butcher array (without the first zero)
|
||||
* @param a internal weights from Butcher array (without the first empty row)
|
||||
* @param b external weights for the high order method from Butcher array
|
||||
* @param prototype prototype of the step interpolator to use
|
||||
* @param minStep minimal step (must be positive even for backward
|
||||
* integration), the last step can be smaller than this
|
||||
* @param maxStep maximal step (must be positive even for backward
|
||||
* integration)
|
||||
* @param scalAbsoluteTolerance allowed absolute error
|
||||
* @param scalRelativeTolerance allowed relative error
|
||||
*/
|
||||
protected RungeKuttaFehlbergIntegrator(boolean fsal,
|
||||
double[] c, double[][] a, double[] b,
|
||||
RungeKuttaStepInterpolator prototype,
|
||||
double minStep, double maxStep,
|
||||
double scalAbsoluteTolerance,
|
||||
double scalRelativeTolerance) {
|
||||
|
||||
super(minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance);
|
||||
|
||||
this.fsal = fsal;
|
||||
this.c = c;
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
this.prototype = prototype;
|
||||
|
||||
exp = -1.0 / getOrder();
|
||||
|
||||
this.safety = 0.9;
|
||||
|
||||
// set the default values of the algorithm control parameters
|
||||
setMinReduction(0.2);
|
||||
setMaxGrowth(10.0);
|
||||
|
||||
}
|
||||
|
||||
/** Build a Runge-Kutta integrator with the given Butcher array.
|
||||
* @param fsal indicate that the method is an <i>fsal</i>
|
||||
* @param c time steps from Butcher array (without the first zero)
|
||||
* @param a internal weights from Butcher array (without the first empty row)
|
||||
* @param b external weights for the high order method from Butcher array
|
||||
* @param prototype prototype of the step interpolator to use
|
||||
* @param minStep minimal step (must be positive even for backward
|
||||
* integration), the last step can be smaller than this
|
||||
* @param maxStep maximal step (must be positive even for backward
|
||||
* integration)
|
||||
* @param vecAbsoluteTolerance allowed absolute error
|
||||
* @param vecRelativeTolerance allowed relative error
|
||||
*/
|
||||
protected RungeKuttaFehlbergIntegrator(boolean fsal,
|
||||
double[] c, double[][] a, double[] b,
|
||||
RungeKuttaStepInterpolator prototype,
|
||||
double minStep, double maxStep,
|
||||
double[] vecAbsoluteTolerance,
|
||||
double[] vecRelativeTolerance) {
|
||||
|
||||
super(minStep, maxStep, vecAbsoluteTolerance, vecRelativeTolerance);
|
||||
|
||||
this.fsal = fsal;
|
||||
this.c = c;
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
this.prototype = prototype;
|
||||
|
||||
exp = -1.0 / getOrder();
|
||||
|
||||
this.safety = 0.9;
|
||||
|
||||
// set the default values of the algorithm control parameters
|
||||
setMinReduction(0.2);
|
||||
setMaxGrowth(10.0);
|
||||
|
||||
}
|
||||
|
||||
/** Get the name of the method.
|
||||
* @return name of the method
|
||||
*/
|
||||
public abstract String getName();
|
||||
|
||||
/** Get the order of the method.
|
||||
* @return order of the method
|
||||
*/
|
||||
public abstract int getOrder();
|
||||
|
||||
/** Get the safety factor for stepsize control.
|
||||
* @return safety factor
|
||||
*/
|
||||
public double getSafety() {
|
||||
return safety;
|
||||
}
|
||||
|
||||
/** Set the safety factor for stepsize control.
|
||||
* @param safety safety factor
|
||||
*/
|
||||
public void setSafety(double safety) {
|
||||
this.safety = safety;
|
||||
}
|
||||
|
||||
public void integrate(FirstOrderDifferentialEquations equations,
|
||||
double t0, double[] y0,
|
||||
double t, double[] y)
|
||||
throws DerivativeException, IntegratorException {
|
||||
|
||||
// sanity check
|
||||
if (equations.getDimension() != y0.length) {
|
||||
throw new IntegratorException("dimensions mismatch: ODE problem has dimension {0},"
|
||||
+ " state vector has dimension {1}",
|
||||
new String[] {
|
||||
Integer.toString(equations.getDimension()),
|
||||
Integer.toString(y0.length)
|
||||
});
|
||||
}
|
||||
if (Math.abs(t - t0) <= 1.0e-12 * Math.max(Math.abs(t0), Math.abs(t))) {
|
||||
throw new IntegratorException("too small integration interval: length = {0}",
|
||||
new String[] {
|
||||
Double.toString(Math.abs(t - t0))
|
||||
});
|
||||
}
|
||||
|
||||
boolean forward = (t > t0);
|
||||
|
||||
// create some internal working arrays
|
||||
int stages = c.length + 1;
|
||||
if (y != y0) {
|
||||
System.arraycopy(y0, 0, y, 0, y0.length);
|
||||
}
|
||||
double[][] yDotK = new double[stages][];
|
||||
for (int i = 0; i < stages; ++i) {
|
||||
yDotK [i] = new double[y0.length];
|
||||
}
|
||||
double[] yTmp = new double[y0.length];
|
||||
|
||||
// set up an interpolator sharing the integrator arrays
|
||||
AbstractStepInterpolator interpolator;
|
||||
if (handler.requiresDenseOutput() || (! switchesHandler.isEmpty())) {
|
||||
RungeKuttaStepInterpolator rki = (RungeKuttaStepInterpolator) prototype.clone();
|
||||
rki.reinitialize(equations, yTmp, yDotK, forward);
|
||||
interpolator = rki;
|
||||
} else {
|
||||
interpolator = new DummyStepInterpolator(yTmp, forward);
|
||||
}
|
||||
interpolator.storeTime(t0);
|
||||
|
||||
double currentT = t0;
|
||||
double hNew = 0;
|
||||
boolean firstTime = true;
|
||||
boolean lastStep;
|
||||
handler.reset();
|
||||
do {
|
||||
|
||||
interpolator.shift();
|
||||
|
||||
double h = 0;
|
||||
double error = 0;
|
||||
for (boolean loop = true; loop;) {
|
||||
|
||||
if (firstTime || !fsal) {
|
||||
// first stage
|
||||
equations.computeDerivatives(currentT, y, yDotK[0]);
|
||||
}
|
||||
|
||||
if (firstTime) {
|
||||
double[] scale;
|
||||
if (vecAbsoluteTolerance != null) {
|
||||
scale = vecAbsoluteTolerance;
|
||||
} else {
|
||||
scale = new double[y0.length];
|
||||
for (int i = 0; i < scale.length; ++i) {
|
||||
scale[i] = scalAbsoluteTolerance;
|
||||
}
|
||||
}
|
||||
hNew = initializeStep(equations, forward, getOrder(), scale,
|
||||
currentT, y, yDotK[0], yTmp, yDotK[1]);
|
||||
firstTime = false;
|
||||
}
|
||||
|
||||
h = hNew;
|
||||
|
||||
// step adjustment near bounds
|
||||
if ((forward && (currentT + h > t))
|
||||
|| ((! forward) && (currentT + h < t))) {
|
||||
h = t - currentT;
|
||||
}
|
||||
|
||||
// next stages
|
||||
for (int k = 1; k < stages; ++k) {
|
||||
|
||||
for (int j = 0; j < y0.length; ++j) {
|
||||
double sum = a[k-1][0] * yDotK[0][j];
|
||||
for (int l = 1; l < k; ++l) {
|
||||
sum += a[k-1][l] * yDotK[l][j];
|
||||
}
|
||||
yTmp[j] = y[j] + h * sum;
|
||||
}
|
||||
|
||||
equations.computeDerivatives(currentT + c[k-1] * h, yTmp, yDotK[k]);
|
||||
|
||||
}
|
||||
|
||||
// estimate the state at the end of the step
|
||||
for (int j = 0; j < y0.length; ++j) {
|
||||
double sum = b[0] * yDotK[0][j];
|
||||
for (int l = 1; l < stages; ++l) {
|
||||
sum += b[l] * yDotK[l][j];
|
||||
}
|
||||
yTmp[j] = y[j] + h * sum;
|
||||
}
|
||||
|
||||
// estimate the error at the end of the step
|
||||
error = estimateError(yDotK, y, yTmp, h);
|
||||
if (error <= 1.0) {
|
||||
|
||||
// Switching functions handling
|
||||
interpolator.storeTime(currentT + h);
|
||||
if (switchesHandler.evaluateStep(interpolator)) {
|
||||
// reject the step to match exactly the next switch time
|
||||
hNew = switchesHandler.getEventTime() - currentT;
|
||||
} else {
|
||||
// accept the step
|
||||
loop = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
// reject the step and attempt to reduce error by stepsize control
|
||||
double factor = Math.min(maxGrowth,
|
||||
Math.max(minReduction,
|
||||
safety * Math.pow(error, exp)));
|
||||
hNew = filterStep(h * factor, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// the step has been accepted
|
||||
currentT += h;
|
||||
System.arraycopy(yTmp, 0, y, 0, y0.length);
|
||||
switchesHandler.stepAccepted(currentT, y);
|
||||
if (switchesHandler.stop()) {
|
||||
lastStep = true;
|
||||
} else {
|
||||
lastStep = forward ? (currentT >= t) : (currentT <= t);
|
||||
}
|
||||
|
||||
// provide the step data to the step handler
|
||||
interpolator.storeTime(currentT);
|
||||
handler.handleStep(interpolator, lastStep);
|
||||
|
||||
if (fsal) {
|
||||
// save the last evaluation for the next step
|
||||
System.arraycopy(yDotK[stages - 1], 0, yDotK[0], 0, y0.length);
|
||||
}
|
||||
|
||||
switchesHandler.reset(currentT, y);
|
||||
|
||||
if (! lastStep) {
|
||||
// stepsize control for next step
|
||||
double factor = Math.min(maxGrowth,
|
||||
Math.max(minReduction,
|
||||
safety * Math.pow(error, exp)));
|
||||
double scaledH = h * factor;
|
||||
double nextT = currentT + scaledH;
|
||||
boolean nextIsLast = forward ? (nextT >= t) : (nextT <= t);
|
||||
hNew = filterStep(scaledH, nextIsLast);
|
||||
}
|
||||
|
||||
} while (! lastStep);
|
||||
|
||||
}
|
||||
|
||||
/** Get the minimal reduction factor for stepsize control.
|
||||
* @return minimal reduction factor
|
||||
*/
|
||||
public double getMinReduction() {
|
||||
return minReduction;
|
||||
}
|
||||
|
||||
/** Set the minimal reduction factor for stepsize control.
|
||||
* @param minReduction minimal reduction factor
|
||||
*/
|
||||
public void setMinReduction(double minReduction) {
|
||||
this.minReduction = minReduction;
|
||||
}
|
||||
|
||||
/** Get the maximal growth factor for stepsize control.
|
||||
* @return maximal growth factor
|
||||
*/
|
||||
public double getMaxGrowth() {
|
||||
return maxGrowth;
|
||||
}
|
||||
|
||||
/** Set the maximal growth factor for stepsize control.
|
||||
* @param maxGrowth maximal growth factor
|
||||
*/
|
||||
public void setMaxGrowth(double maxGrowth) {
|
||||
this.maxGrowth = maxGrowth;
|
||||
}
|
||||
|
||||
/** Compute the error ratio.
|
||||
* @param yDotK derivatives computed during the first stages
|
||||
* @param y0 estimate of the step at the start of the step
|
||||
* @param y1 estimate of the step at the end of the step
|
||||
* @param h current step
|
||||
* @return error ratio, greater than 1 if step should be rejected
|
||||
*/
|
||||
protected abstract double estimateError(double[][] yDotK,
|
||||
double[] y0, double[] y1,
|
||||
double h);
|
||||
|
||||
/** Indicator for <i>fsal</i> methods. */
|
||||
private boolean fsal;
|
||||
|
||||
/** Time steps from Butcher array (without the first zero). */
|
||||
private double[] c;
|
||||
|
||||
/** Internal weights from Butcher array (without the first empty row). */
|
||||
private double[][] a;
|
||||
|
||||
/** External weights for the high order method from Butcher array. */
|
||||
private double[] b;
|
||||
|
||||
/** Prototype of the step interpolator. */
|
||||
private RungeKuttaStepInterpolator prototype;
|
||||
|
||||
/** Stepsize control exponent. */
|
||||
private double exp;
|
||||
|
||||
/** Safety factor for stepsize control. */
|
||||
private double safety;
|
||||
|
||||
/** Minimal reduction factor for stepsize control. */
|
||||
private double minReduction;
|
||||
|
||||
/** Maximal growth factor for stepsize control. */
|
||||
private double maxGrowth;
|
||||
|
||||
}
|
|
@ -0,0 +1,275 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.spaceroots.mantissa.ode;
|
||||
|
||||
/**
|
||||
* This class implements the common part of all fixed step Runge-Kutta
|
||||
* integrators for Ordinary Differential Equations.
|
||||
|
||||
* <p>These methods are explicit Runge-Kutta methods, their Butcher
|
||||
* arrays are as follows :
|
||||
* <pre>
|
||||
* 0 |
|
||||
* c2 | a21
|
||||
* c3 | a31 a32
|
||||
* ... | ...
|
||||
* cs | as1 as2 ... ass-1
|
||||
* |--------------------------
|
||||
* | b1 b2 ... bs-1 bs
|
||||
* </pre>
|
||||
* </p>
|
||||
|
||||
* <p>Some methods are qualified as <i>fsal</i> (first same as last)
|
||||
* methods. This means the last evaluation of the derivatives in one
|
||||
* step is the same as the first in the next step. Then, this
|
||||
* evaluation can be reused from one step to the next one and the cost
|
||||
* of such a method is really s-1 evaluations despite the method still
|
||||
* has s stages. This behaviour is true only for successful steps, if
|
||||
* the step is rejected after the error estimation phase, no
|
||||
* evaluation is saved. For an <i>fsal</i> method, we have cs = 1 and
|
||||
* asi = bi for all i.</p>
|
||||
|
||||
* @see EulerIntegrator
|
||||
* @see ClassicalRungeKuttaIntegrator
|
||||
* @see GillIntegrator
|
||||
* @see MidpointIntegrator
|
||||
|
||||
* @version $Id: RungeKuttaIntegrator.java 1705 2006-09-17 19:57:39Z luc $
|
||||
* @author L. Maisonobe
|
||||
|
||||
*/
|
||||
|
||||
public abstract class RungeKuttaIntegrator
|
||||
implements FirstOrderIntegrator {
|
||||
|
||||
/** Simple constructor.
|
||||
* Build a Runge-Kutta integrator with the given
|
||||
* step. The default step handler does nothing.
|
||||
* @param fsal indicate that the method is an <i>fsal</i>
|
||||
* @param c time steps from Butcher array (without the first zero)
|
||||
* @param a internal weights from Butcher array (without the first empty row)
|
||||
* @param b external weights for the high order method from Butcher array
|
||||
* @param prototype prototype of the step interpolator to use
|
||||
* @param step integration step
|
||||
*/
|
||||
protected RungeKuttaIntegrator(boolean fsal,
|
||||
double[] c, double[][] a, double[] b,
|
||||
RungeKuttaStepInterpolator prototype,
|
||||
double step) {
|
||||
this.fsal = fsal;
|
||||
this.c = c;
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
this.prototype = prototype;
|
||||
this.step = step;
|
||||
handler = DummyStepHandler.getInstance();
|
||||
switchesHandler = new SwitchingFunctionsHandler();
|
||||
}
|
||||
|
||||
/** Get the name of the method.
|
||||
* @return name of the method
|
||||
*/
|
||||
public abstract String getName();
|
||||
|
||||
/** Set the step handler for this integrator.
|
||||
* The handler will be called by the integrator for each accepted
|
||||
* step.
|
||||
* @param handler handler for the accepted steps
|
||||
*/
|
||||
public void setStepHandler (StepHandler handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
/** Get the step handler for this integrator.
|
||||
* @return the step handler for this integrator
|
||||
*/
|
||||
public StepHandler getStepHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
/** Add a switching function to the integrator.
|
||||
* @param function switching function
|
||||
* @param maxCheckInterval maximal time interval between switching
|
||||
* function checks (this interval prevents missing sign changes in
|
||||
* case the integration steps becomes very large)
|
||||
* @param convergence convergence threshold in the event time search
|
||||
*/
|
||||
public void addSwitchingFunction(SwitchingFunction function,
|
||||
double maxCheckInterval,
|
||||
double convergence) {
|
||||
switchesHandler.add(function, maxCheckInterval, convergence);
|
||||
}
|
||||
|
||||
public void integrate(FirstOrderDifferentialEquations equations,
|
||||
double t0, double[] y0,
|
||||
double t, double[] y)
|
||||
throws DerivativeException, IntegratorException {
|
||||
|
||||
// sanity check
|
||||
if (equations.getDimension() != y0.length) {
|
||||
throw new IntegratorException("dimensions mismatch: ODE problem has dimension {0},"
|
||||
+ " state vector has dimension {1}",
|
||||
new String[] {
|
||||
Integer.toString(equations.getDimension()),
|
||||
Integer.toString(y0.length)
|
||||
});
|
||||
}
|
||||
if (Math.abs(t - t0) <= 1.0e-12 * Math.max(Math.abs(t0), Math.abs(t))) {
|
||||
throw new IntegratorException("too small integration interval: length = {0}",
|
||||
new String[] {
|
||||
Double.toString(Math.abs(t - t0))
|
||||
});
|
||||
}
|
||||
|
||||
boolean forward = (t > t0);
|
||||
|
||||
// create some internal working arrays
|
||||
int stages = c.length + 1;
|
||||
if (y != y0) {
|
||||
System.arraycopy(y0, 0, y, 0, y0.length);
|
||||
}
|
||||
double[][] yDotK = new double[stages][];
|
||||
for (int i = 0; i < stages; ++i) {
|
||||
yDotK [i] = new double[y0.length];
|
||||
}
|
||||
double[] yTmp = new double[y0.length];
|
||||
|
||||
// set up an interpolator sharing the integrator arrays
|
||||
AbstractStepInterpolator interpolator;
|
||||
if (handler.requiresDenseOutput() || (! switchesHandler.isEmpty())) {
|
||||
RungeKuttaStepInterpolator rki = (RungeKuttaStepInterpolator) prototype.clone();
|
||||
rki.reinitialize(equations, yTmp, yDotK, forward);
|
||||
interpolator = rki;
|
||||
} else {
|
||||
interpolator = new DummyStepInterpolator(yTmp, forward);
|
||||
}
|
||||
interpolator.storeTime(t0);
|
||||
|
||||
// recompute the step
|
||||
double currentT = t0;
|
||||
long nbStep = Math.max(1l, Math.abs(Math.round((t - t0) / step)));
|
||||
double h = (t - t0) / nbStep;
|
||||
boolean firstTime = true;
|
||||
boolean lastStep = false;
|
||||
handler.reset();
|
||||
for (long i = 0; ! lastStep; ++i) {
|
||||
|
||||
interpolator.shift();
|
||||
|
||||
boolean needUpdate = false;
|
||||
for (boolean loop = true; loop;) {
|
||||
|
||||
if (firstTime || !fsal) {
|
||||
// first stage
|
||||
equations.computeDerivatives(currentT, y, yDotK[0]);
|
||||
firstTime = false;
|
||||
}
|
||||
|
||||
// next stages
|
||||
for (int k = 1; k < stages; ++k) {
|
||||
|
||||
for (int j = 0; j < y0.length; ++j) {
|
||||
double sum = a[k-1][0] * yDotK[0][j];
|
||||
for (int l = 1; l < k; ++l) {
|
||||
sum += a[k-1][l] * yDotK[l][j];
|
||||
}
|
||||
yTmp[j] = y[j] + h * sum;
|
||||
}
|
||||
|
||||
equations.computeDerivatives(currentT + c[k-1] * h, yTmp, yDotK[k]);
|
||||
|
||||
}
|
||||
|
||||
// estimate the state at the end of the step
|
||||
for (int j = 0; j < y0.length; ++j) {
|
||||
double sum = b[0] * yDotK[0][j];
|
||||
for (int l = 1; l < stages; ++l) {
|
||||
sum += b[l] * yDotK[l][j];
|
||||
}
|
||||
yTmp[j] = y[j] + h * sum;
|
||||
}
|
||||
|
||||
// Switching functions handling
|
||||
interpolator.storeTime(currentT + h);
|
||||
if (switchesHandler.evaluateStep(interpolator)) {
|
||||
needUpdate = true;
|
||||
h = switchesHandler.getEventTime() - currentT;
|
||||
} else {
|
||||
loop = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// the step has been accepted
|
||||
currentT += h;
|
||||
System.arraycopy(yTmp, 0, y, 0, y0.length);
|
||||
switchesHandler.stepAccepted(currentT, y);
|
||||
if (switchesHandler.stop()) {
|
||||
lastStep = true;
|
||||
} else {
|
||||
lastStep = (i == (nbStep - 1));
|
||||
}
|
||||
|
||||
// provide the step data to the step handler
|
||||
interpolator.storeTime(currentT);
|
||||
handler.handleStep(interpolator, lastStep);
|
||||
|
||||
if (fsal) {
|
||||
// save the last evaluation for the next step
|
||||
System.arraycopy(yDotK[stages - 1], 0, yDotK[0], 0, y0.length);
|
||||
}
|
||||
|
||||
switchesHandler.reset(currentT, y);
|
||||
|
||||
if (needUpdate) {
|
||||
// a switching function has changed the step
|
||||
// we need to recompute stepsize
|
||||
nbStep = Math.max(1l, Math.abs(Math.round((t - currentT) / step)));
|
||||
h = (t - currentT) / nbStep;
|
||||
i = -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Indicator for <i>fsal</i> methods. */
|
||||
private boolean fsal;
|
||||
|
||||
/** Time steps from Butcher array (without the first zero). */
|
||||
private double[] c;
|
||||
|
||||
/** Internal weights from Butcher array (without the first empty row). */
|
||||
private double[][] a;
|
||||
|
||||
/** External weights for the high order method from Butcher array. */
|
||||
private double[] b;
|
||||
|
||||
/** Prototype of the step interpolator. */
|
||||
private RungeKuttaStepInterpolator prototype;
|
||||
|
||||
/** Integration step. */
|
||||
private double step;
|
||||
|
||||
/** Step handler. */
|
||||
private StepHandler handler;
|
||||
|
||||
/** Switching functions handler. */
|
||||
protected SwitchingFunctionsHandler switchesHandler;
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue