public class PDLS
extends java.lang.Object
Prioritized Damped Least Squares
This class implements a prioritized damped least squares solver for multivariate systems of constraints which can always be locally linearized (i.e. differentiated). The constraints are paritioned into decreasing-priority levels which are solved in order in the sense that the constraint system at each successive level is satisfied as best as possible without degrading the satisfaction of higher-priority levels. In addition, upper and lower limits may be specified independently for each variable.
Other than time and space usage (detailed below), there are no restrictions on the number of variables, the number of constraints, or their relationship. Further, there are no requirements of well-constrainedness, consistency, or non-singularity.
The algorithm is based on [Baerlocher and Boulic 2004] with additional detail from [Baerlocher 2001]. Additional useful references include [Siciliano and Slotine 1991] who originally formulated the general multiple priority DLS framework, [Buss 2004], [Baerlocher and Boulic 1998], [Baerlocher and Boulic 2000], and [Maciejewski and Klein 1988]. One key feature of this implementation not described in those references is adaptive step size.
The underlying DLS matrix pseudo-inversion is accomplished via a call to
an SVD
driver. The particular SVD backend to use is specified at
construction time. The default is SVD_DGESDD_FOMMIL_NETLIB
which
attempts to use a system-optimized native implementation from the Fortran
netlib, if available. It falls back to a generic reference Fortran
implementation, and then to the pure-java F2J implementation. If
fommil-netlib is itself not available then we fall back to SVD_DGESDD_NETLIB_JAVA
, which is an earlier incarnation of the same library.
Finally, if that is not available, we fall back to SVD_DGESDD_JLAPACK
.
The implementation is split into two parts. At the highest level, solve()
implements successively nested convergence, limiting,
and priority loops. One solve()
cycle consists of one
full iteration of the outer-most convergence loop. The second part of the
implementation is the application-specific updateProblem(int)
method,
which is called at the beginning of every solve()
cycle.
Essentially, application subclasses must define updateProblem(int)
to
set up the particular PDLS problem to be solved at every iteration, and then
the rest of the solve()
cycle will compute a thetaDiff
vector to be added to theta
to drive down residual
. The
next updateProblem(int)
can choose to actually update theta
in
this manner or not (e.g. if the problem structure has changed).
Solve cycles continue, in the thread which has called solve()
,
until a call to updateProblem(int)
returns false. In general no
internal PDLS state should be modified until solve()
returns except
from within a call to updateProblem(int)
. solve()
periodically
checks for thread interrupt and if so shortcuts to the next updateProblem(int)
, without resetting the interrupt flag.
The application may implement various communication and control
structures within updateProblem(int)
. For example, asynchronous problem
updates could be queued and then applied in sequence during the next updateProblem(int)
, and current solution state could also be transmitted
synchronously to other code from there.
In particular, it is the responsibility of the implementation of updateProblem(int)
to determine solver termination and/or to throttle the rate
of convergence loop iterations (by blocking within updateProblem(int)
).
Applications could either be structured to solve one problem and then
terminate the solver, possibly with iteration count, temporal limits, and/or
divergence checks, or they could be structured to run the solver
continuously, possibly pausing it during times when the current problem is
sufficiently solved.
A generic implementation is provided for updateProblem(int)
which
factors into a typical set of subtasks, mainly updateTheta(int)
, updateResidual(int)
, updateJacobian(int)
, updatePostureVariation(int)
and checkConvergence(int)
.
Each convergence iteration computes a new thetaDiff
based on the
current residual
. If the former is too small then it may take many
iterations to converge, and performance will be sluggish; if too large then
the system may overshoot and oscillate, and performance will be
unstable.
We have two means at our disposal for controlling the magnitude of thetaDiff
: we can select the portion of residual
that we'll bite
off at each iteration, which we refer to as step size control, and we can
scale the damping factor we apply (if any) when computing dampedPseudoinverse
. Larger damping factors produce smaller thetaDiff
. Both techniques are implemented. Step size control is turned
on by setting adaptiveStepSizeEnabled
, and damping by dampingEnabled
. In each case, the goal is to produce thetaDiff
with magnitude as large as necessary but not exceeding thetaDiffMaxMag
(if thetaDiffClampingEnabled
is turned on thetaDiff
with magnitude exceeding thetaDiffMaxMag
will be
clamped anyway, but this only a last-resort measure).
Adaptive step size kicks in after the first iteration in each call to
solve()
. If the system remains unconverged and either (1) lastThetaDiffMag
exceeds slowdownThreshold
*thetaDiffMaxMag
, or (2) the maximum auto-computed lastLevelLambda
exceeds autoLambdaSlowdownThreshold
, or (3) the system is diverging
at a priority level less than minDivergableLevel
, a slowdown is
triggered: any unset residualMaxMag
are set to lastResidualMag
, then all residualMaxMag
are multiplied in-place
by slowdownFactor
. When slowing down, residualMaxMag
is
clamped to the lower limit given by slowdownLimit
, if set, else
residualTol
, if set, else eps
. Otherwise, if the system
remains unconverged and (1) lastThetaDiffMag
is below speedupThreshold
*thetaDiffMaxMag
, and (2) the maximum
auto-computed lastLevelLambda
is less than autoLambdaSpeedupThreshold
, and (3) the system is not diverging, a speedup
is triggered: any set residualMaxMag
which caused clamping in th
eprior iteration are multiplied in-place by speedupFactor
and
clamped to speedupLimit
, if set.
If levelLambda
is pre-initialized at a given priority level,
then then it is used as-is. Otherwise, the automatic damping system is
engaged: damping is applied at the priority level iff the minimum non-zero
(i.e. after applying svdTol
) singular value of the restrictedJacobian
is less than both neverDampSigma
and the
quotient (clamped compensated residual mag)/(thetaDiffMaxMag
*autoLambdaThetaDiffMaxMagScale
), or if it's less than alwaysDampSigma
. The damping factor (lambda) is computed on-the-fly
according to the recommendations in [Baerlocher 2001]
which follows [Maciejewski and Klein 1988]. These
formulas, given in the doc for levelLambda
, are aimed to estimate a
damping factor which constrains the thetaDiff
magnitude to thetaDiffMaxMag
*autoLambdaThetaDiffMaxMagScale
, depending on the
clamped compensated residual magnitude and minimum singular value at the
priority level. The computed values are stored in lastLevelLambda
.
Recall that each call to solve()
is structured as nested
convergence, limiting, and priority loops. Within each priority iteration
the time bounds are dominated by one of the following sub-tasks, where
h is the number of constraints in the priority level and nv
is numVariables
:
restrictedJacobian
in
O(max(h, nv)*min(h, nv)^2)nullspaceProjector
and restrictedJacobian
in O(nv^2*h).numVariables
). In practice the average case behavior is essientially a
constant factor (i.e. O(1)) overhead since typically at most a few variables
hit their limits in each solve cycle.
The number of convergence iterations that must be executed before the
residual is reduced sufficiently (PDLS.SolveStatus.CONVERGED
) or progress
slows below some threshold (PDLS.SolveStatus.STALLED
), which may happen
for inconsistently overconstrained problems, is also a major factor
affecting overall computation time. Convergence behavior will vary
according to the problem state and structure, though in practice again the
average case behavior is not unreasonably modeled as a constant factor
overhead since typically convergence (or stall) is achieved within a fixed
maxConvergenceIterations
and maxConvergenceMS
.
Asymptotic space bounds are dominated by one of the following, where
nc is numConstraints
:
jacobian
, which is O(nc*nv)nullspaceProjector
, which is O(nv^2).PDLS.TimeMetrics
of various sub-tasks are accounted in the
*Metrics
state variables where present.
[Baerlocher and Boulic 2004] Paolo Baerlocher and Ronan Boulic. An inverse kinematics architecture enforcing an arbitrary number of strict priority levels. The Visual Computer 20, pp 402--417, 2004. Also available as a preprint which appears to have additional content.
[Baerlocher 2001] Paolo Baerlocher. Inverse kinematics techniques for the interactive posture control of articulated figures. Dissertation number 2383, Swiss Federal Institute of Technology, Lausanne, EPFL, Switzerland.
[Buss 2004] Samuel R. Buss. Introduction to Inverse Kinematics with Jacobian Transpose, Pseudoinverse and Damped Least Squares methods. Published independently on the web in 2004.
[Baerlocher and Boulic 1998] P. Baerlocher, R. Boulic. Task-Priority Formulations for the Kinematic Control of Highly Redundant Articulated Structures. Intelligent Robots and Systems, Proceedings 1998 IEEE/RSJ International Conference on, pp 323--329, vol 1.
[Baerlocher and Boulic 2000] P. Baerlocher, R. Boulic. Kinematic Control of the Mass Properties of Redundant Articulated Bodies. Robotics and Automation, Proceedings 2000 IEEE International Conference on, pp 2557--2562, vol 3.
[Maciejewski and Klein 1988] Numerical Filtering for the Operation of Robotic Manipulators through Kinematically Singular Configurations. Journal of Robotic Systems, 5(6), pp 527--552, 1988.
[Siciliano and Slotine 1991] A general framework for managing multiple tasks in highly redundant robotic systems. Advanced Robotics, 1991. 'Robots in Unstructured Environments', 91 ICAR., Fifth International Conference on, pp 1211--1216, vol 2.
Copyright (C) 2007 Marsette A. Vona, III
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Modifier and Type | Class and Description |
---|---|
static class |
PDLS.SolveStatus
possible return values from
solve() |
protected static class |
PDLS.TimeMetrics
extends superclass with
PDLS.TimeMetrics.dependent |
Modifier and Type | Field and Description |
---|---|
boolean |
abortOnDiverge
whether to abort
solve() on indicated condition |
boolean |
abortOnInterrupt
whether to abort
solve() on indicated condition |
boolean |
abortOnSVDError
whether to abort
solve() on indicated condition |
boolean |
adaptiveStepSizeEnabled
Enable for indicated part of
solve() . |
protected java.util.List<java.lang.String> |
allPriorityMetricNames
collection of all per-priority-level metrics names
|
protected java.util.List<PDLS.TimeMetrics[]> |
allPriorityMetrics
collection of all per-priority-level metrics
|
protected java.util.List<PDLS.TimeMetrics> |
allSolveMetrics
collection of all
solve() metrics |
protected double |
alwaysDampSigma
Singular value (after applying
svdTol ) below which
auto-computed damping will always be applied. |
boolean |
alwaysUpdateWholeProblem
Whether
updateProblem(int) should update everything even if
converged or diverging and abortOnDiverge . |
double |
autoLambdaSlowdownThreshold
If
adaptiveStepSizeEnabled a slowdown is triggered whenever
the largest auto-computed lastLevelLambda exceeds this
threshold. |
double |
autoLambdaSpeedupThreshold
If
adaptiveStepSizeEnabled a speedup is enabled whenever
the largest auto-computed lastLevelLambda does not exceed this
threshold. |
protected double |
autoLambdaThetaDiffMaxMagScale
Scale factor applied to
thetaDiffMaxMag for the purposes of
auto-lambda computation. |
static java.lang.String |
C_FMT
compact decimal printf format
|
protected PDLS.TimeMetrics |
checkConvergenceMetrics
PDLS.TimeMetrics on indicated part of solve() |
boolean |
clampResidualByComponent
Whether
thetaDiffMaxMag or residualMaxMag should be
applied as vector 2-norms or on a per-component basis. |
boolean |
clampThetaDiffByComponent
Whether
thetaDiffMaxMag or residualMaxMag should be
applied as vector 2-norms or on a per-component basis. |
protected double[] |
compensatedResidual
Compensated residual for each priority level.
|
protected PDLS.TimeMetrics[] |
compensatedResidualMetrics
Per-priority-level
PDLS.TimeMetrics on indicated part of solve() . |
protected PDLS.TimeMetrics |
convergenceCycleMetrics
PDLS.TimeMetrics on indicated part of solve() |
boolean |
convergenceEnabled
Enable for indicated part of
solve() . |
private static java.lang.String |
cvsid |
protected double[] |
dampedPseudoinverse
Working space to compute damped pseudoinverse of
restrictedJacobian . |
boolean |
dampingEnabled
Enable for indicated part of
solve() . |
static int |
DBG_ALL
debug flag
|
static int |
DBG_ALL_BUT_MATRICES
debug flag
|
static int |
DBG_CONTROL
debug flag
|
static int |
DBG_LAMBDA
debug flag
|
static int |
DBG_LIMITING
debug flag
|
static int |
DBG_MATRICES
debug flag
|
static int |
DBG_POSTURE
debug flag
|
static int |
DBG_RESIDUAL
debug flag
|
static int |
DBG_STEPSIZE
debug flag
|
static int |
DBG_STEPSIZE_AND_LAMBDA
debug flag
|
static int |
DBG_SVD
debug flag
|
static int |
DBG_THETA
debug flag
|
static int |
DBG_THETA_AND_RESIDUAL
debug flag
|
int |
dbgFlags
debug enable flags, 0 to disable debug
|
java.io.PrintStream |
dbgStream
output stream for debug messages, null to disable debug
|
static double |
DEF_ALWAYS_DAMP_SIGMA
initial/default value of
alwaysDampSigma |
static double |
DEF_AUTO_LAMBDA_SLOWDOWN_THRESHOLD
initial/default value of
autoLambdaSlowdownThreshold |
static double |
DEF_AUTO_LAMBDA_SPEEDUP_THRESHOLD
initial/default value of
autoLambdaSpeedupThreshold |
static double |
DEF_AUTO_LAMBDA_THETA_DIFF_MAX_MAG_SCALE
initial/default value of
autoLambdaThetaDiffMaxMagScale |
static double |
DEF_DIVERGENCE_FACTOR
initial/default value of
divergenceFactor |
static double |
DEF_DIVERGENCE_TOL
initial/default value of
divergenceTol |
static double |
DEF_EPS
initial/default value of
eps |
static int |
DEF_MIN_DIVERGABLE_LEVEL
initial/default value of
minDivergableLevel |
static double |
DEF_NEVER_DAMP_SIGMA
initial/default value of
neverDampSigma |
static double |
DEF_SLOWDOWN_FACTOR
initial/default value of
slowdownFactor |
static double |
DEF_SLOWDOWN_THRESHOLD
initial/default value of
slowdownThreshold |
static double |
DEF_SPEEDUP_FACTOR
initial/default value of
speedupFactor |
static double |
DEF_SPEEDUP_THRESHOLD
initial/default value of
speedupThreshold |
static java.lang.String[] |
DEF_SVD_IMPLS
default
svdImpl names, in order of preference |
static double |
DEF_SVD_TOL
initial/default value of
svdTol |
static double |
DEF_THETA_DIFF_MAX_MAG
initial/default value of
thetaDiffMaxMag |
static double |
DEF_THETA_DIFF_TOL
initial/default value of
thetaDiffTol |
protected double |
divergenceFactor
Used in the default impl of
checkConvergence(int) , see which. |
protected double |
divergenceTol
Used in the default impl of
checkConvergence(int) , see which. |
protected double |
eps
Threshold below which the difference between two doubles is considered
insignificant.
|
static java.lang.String |
FMT
decimal printf format
|
static int |
FMT_WIDTH
field width for
FMT |
protected static java.util.Map<java.lang.String,PDLS.TimeMetrics> |
globalMetrics
global stats, see
globalMetricsEnabled |
protected static boolean |
globalMetricsEnabled
Whether global time metrics are collected across all PDLS instances.
|
protected double[] |
jacobian
|
protected double[] |
lastLevelLambda
Actual per-level lambda values used for the most recent iteration.
|
protected double[] |
lastResidualMag
Unclamped uncompensated residual magnitude at each priority level in
the prior convergence iteration.
|
PDLS.SolveStatus |
lastSolveStatus
status from the most recent call to
solve() , or null if none |
protected double |
lastThetaDiffMag
Unclamped
thetaDiff magnitude of the prior convergence
iteration. |
protected double[] |
levelLambda
Explicit damping constants to use for each priority level, if not
null.
|
protected PDLS.TimeMetrics[] |
levelLambdaMetrics
Per-priority-level
PDLS.TimeMetrics on indicated part of solve() . |
protected PDLS.TimeMetrics[] |
levelThetaDiffMetrics
Per-priority-level
PDLS.TimeMetrics on indicated part of solve() . |
protected PDLS.TimeMetrics |
limitingCycleMetrics
PDLS.TimeMetrics on indicated part of solve() |
boolean |
limitingEnabled
Enable for indicated part of
solve() . |
protected double[] |
limitingVariation
limitingVariation[i] is zero when ith variable (element of
theta ) is unlocked after a solve() cycle, else the
sign of limitingVariation[i] indicates the direction of the limit to
which the ith variable is locked, and the magnitude indicates the
limiting variation, which is the difference between the full desired change
in the ith variable and the maximum allowable change up to the
effective limit. |
protected PDLS.TimeMetrics |
lockingMetrics
PDLS.TimeMetrics on indicated part of solve() |
int |
maxConvergenceIterations
Maximum number of convergence cycle iterations per call to
solve() . |
int |
maxConvergenceMS
Maximum number of time spent in convergence cycle iterations per call
to
solve() . |
boolean |
metricsEnabled
Enable for indicated part of
solve() . |
int |
minDivergableLevel
The lowest-numbered (i.e.
|
protected double |
neverDampSigma
Singular value (after applying
svdTol ) above which
auto-computed damping will never be applied. |
protected double[] |
nullspaceProjector
Projection matrix taking an arbitrary
thetaDiff vector to the
nullspace of superior priority levels. |
protected PDLS.TimeMetrics[] |
nullspaceProjectorMetrics
Per-priority-level
PDLS.TimeMetrics on indicated part of solve() . |
protected int |
numConstraints
Number of scalar constraints.
|
protected int |
numPriorities
Number of priority levels.
|
protected int |
numVariables
Number of scalar variables.
|
protected double[] |
postureVariation
Desired posture variation or null.
|
boolean |
postureVariationEnabled
Enable for indicated part of
solve() . |
protected PDLS.TimeMetrics |
postureVariationMetrics
PDLS.TimeMetrics on indicated part of solve() |
protected PDLS.TimeMetrics[] |
priorityCycleMetrics
Per-priority-level
PDLS.TimeMetrics on indicated part of solve() . |
boolean |
priorityLevelsEnabled
Enable for indicated part of
solve() . |
protected int[] |
priorityPartition
Partition of the constraints into priority levels.
|
protected double[] |
pseudoinverse
Working space to compute pseudoinverse of
restrictedJacobian . |
protected PDLS.TimeMetrics[] |
pseudoinverseMetrics
Per-priority-level
PDLS.TimeMetrics on indicated part of solve() . |
protected PDLS.TimeMetrics |
reallocMetrics
PDLS.TimeMetrics on indicated part of solve() |
protected double[] |
residual
The current residual (error) vector.
|
protected double[] |
residualMaxMag
The magnitude of the uncompensated residual at priority level i
is clamped to have maximum euclidean norm residualMaxMag[i], if the
latter is present.
|
protected double[] |
residualTol
If present, these are the per-level allowable residual magnitudes for
the system to be considered converged in the default impl of
checkConvergence(int) . |
protected double[] |
residualWas
If non-null then the previous value of
residual is saved here
in the default implementation of updateProblem(int) . |
protected double[] |
restrictedJacobian
|
protected PDLS.TimeMetrics[] |
restrictedJacobianMetrics
Per-priority-level
PDLS.TimeMetrics on indicated part of solve() . |
protected int[] |
restrictedJacobianRank
If non-null the computed rank of the
restrictedJacobian at
level i is saved as restrictedJacobianRank[i]. |
boolean |
singleStep
special mode to only do one convergence iteration per
solve() |
double |
slowdownFactor
If
adaptiveStepSizeEnabled , this is the multiplicative change
applied to residualMaxMag in a slowdown. |
protected double[] |
slowdownLimit
Lower limit for adaptive slowdown.
|
double |
slowdownThreshold
If
adaptiveStepSizeEnabled , this is the thetaDiff
magnitude threshold above which a slowdown will be incurred. |
protected PDLS.TimeMetrics |
solveCycleMetrics
PDLS.TimeMetrics on indicated part of solve() |
double |
speedupFactor
If
adaptiveStepSizeEnabled , this is the multiplicative change
applied to residualMaxMag in a speedup. |
protected double[] |
speedupLimit
Upper limit for adaptive speedup.
|
double |
speedupThreshold
If
adaptiveStepSizeEnabled , this is the thetaDiff
magnitude threshold below which a speedup will be incurred. |
protected double[] |
svdA
|
SVD |
svdImpl
The underlying SVD implementation.
|
protected PDLS.TimeMetrics[] |
svdMetrics
Per-priority-level
PDLS.TimeMetrics on indicated part of solve() . |
protected double[] |
svdS
Singular values in decreasing order for
restrictedJacobian . |
protected int |
svdStatus
Status result of the most recent
SVD.thinSVD(int, int, double[], double[], double[], double[]) call. |
protected double |
svdTol
Threshold below which a singular value is clamped to zero.
|
protected double[] |
svdU
Left singular vectors for
restrictedJacobian or right singular
vectors for its transpose. |
protected double[] |
svdVT
Right singular vectors for
restrictedJacobian or left
singular vectors for its transpose. |
protected double[] |
theta
The current solution vector.
|
protected double[] |
thetaDiff
|
boolean |
thetaDiffClampingEnabled
Enable for indicated part of
solve() . |
protected double |
thetaDiffMaxMag
Maximum allowed magnitude of
thetaDiff . |
protected PDLS.TimeMetrics |
thetaDiffMetrics
PDLS.TimeMetrics on indicated part of solve() |
protected double |
thetaDiffTol
|
protected double[] |
thetaLimitLower
Lower limit for each variable.
|
protected double[] |
thetaLimitUpper
Upper limit for each variable.
|
protected double[] |
thetaWas
A copy of the starting
theta is saved here by the default impl
of updateProblem(int) . |
protected PDLS.TimeMetrics |
updateProblemMetrics
PDLS.TimeMetrics on indicated part of solve() |
Constructor and Description |
---|
PDLS()
uses
DEF_SVD_IMPLS |
PDLS(java.lang.String impl)
Conses SVD impl with
SVD.cons(java.lang.String) . |
PDLS(java.lang.String[] impls)
Conses first available SVD impl with
SVD.cons(java.lang.String) . |
PDLS(SVD svdImpl)
Constructor given an SVD impl instance.
|
Modifier and Type | Method and Description |
---|---|
int |
checkConvergence(int convergenceIteration)
Check the current convergence status.
|
double |
clamp(double[] v,
int i,
int n,
double maxMag)
clamp(double[], int, int, double, boolean) , clamps 2-norm of
full index range. |
double |
clamp(double[] v,
int i,
int n,
double maxMag,
boolean byComponent)
Clamp the n-element vector starting at v[i] to the max
2-norm maxMag.
|
void |
clearDebugFlags(int flags)
clear the indicated DBG_* flags
|
(package private) static SVD |
consSVD(java.lang.String[] impls)
Returns first available SVD impl with
SVD.cons(java.lang.String) . |
protected boolean |
dbgEnabled(int flags)
|
void |
dump(java.io.PrintStream s,
double[] v,
int n)
dump an array as one row
|
protected void |
dumpForLevelsMaybe(double[] value,
int np,
java.lang.String msg,
java.io.PrintStream s)
dump human-readable list of per-level values
|
protected void |
dumpForLevelsMaybe(double[] value,
java.lang.String msg,
java.io.PrintStream s)
dumpForLevelsMaybe(double[], int, String, PrintStream) all
effectrive levels excluding posture variation. |
protected void |
dumpForLevelsMaybe(int[] value,
java.lang.String msg,
java.io.PrintStream s)
dump human-readable list of per-level values
|
static void |
dumpGlobalStats()
dumpGlobalStats(PrintStream) to System.out |
static void |
dumpGlobalStats(java.io.PrintStream s)
dump human-readable global PDLS stats
|
void |
dumpJacobian()
dumpJacobian(PrintStream) to System.out |
void |
dumpJacobian(java.io.PrintStream s)
dump full jacobian, theta, and residual
|
void |
dumpMatrix(java.io.PrintStream s,
double[] a,
int m,
int n,
java.lang.String msg)
dump an (m)x(n) matrix
|
void |
dumpNumericDetails()
dumpNumericDetails(PrintStream) to System.out |
void |
dumpNumericDetails(java.io.PrintStream s)
dump human-readable details of this PDLS
|
void |
dumpStats()
dumpStats(PrintStream) to System.out |
void |
dumpStats(java.io.PrintStream s)
dump human-readable stats of this PDLS
|
void |
dumpStructure()
dumpStructure(PrintStream) to System.out |
void |
dumpStructure(java.io.PrintStream s)
dump human-readable stats of this PDLS
|
double |
getAlwaysDampSigma()
get
alwaysDampSigma |
double |
getAutoLambdaSlowdownThreshold()
|
double |
getAutoLambdaSpeedupThreshold()
|
double |
getAutoLambdaThetaDiffMaxMagScale()
|
java.lang.String |
getConstraintName(int constraint,
int width)
Get a semantic human-readable name for a constraint.
|
double |
getDivergenceFactor()
get
divergenceFactor |
double |
getDivergenceTol()
get
divergenceTol |
double |
getLevelLambda(int level)
get
levelLambda at level or NaN if undefined |
protected double |
getLevelParam(double[] param,
int p)
getLevelParam(double[], int, double) default NaN |
protected double |
getLevelParam(double[] param,
int p,
double def)
Get the param value at level p, if allocated and not NaN,
else def.
|
int |
getMaxConvergenceIterations()
|
int |
getMaxConvergenceMS()
get
maxConvergenceMS |
int |
getMaxLevelSize()
Get the size of the largest priority level.
|
double |
getNeverDampSigma()
get
neverDampSigma |
java.lang.String |
getPriorityLevelName(int level)
Get a semantic human-readable name for a priority level.
|
double |
getResidualMaxMag(int level)
get
residualMaxMag at level or NaN if undefined |
double |
getResidualTol(int level)
get
residualTol at level or NaN if undefined |
double |
getSlowdownFactor()
get
slowdownFactor |
double |
getSlowdownLimit(int level)
get
slowdownLimit at level or NaN if undefined |
double |
getSlowdownThreshold()
|
double |
getSpeedupFactor()
get
speedupFactor |
double |
getSpeedupLimit(int level)
get
speedupLimit at level or NaN if undefined |
double |
getSpeedupThreshold()
get
speedupThreshold |
double |
getSVDTol()
get
svdTol |
double |
getThetaDiffMaxMag()
get
thetaDiffMaxMag |
double |
getThetaDiffTol()
get
thetaDiffTol |
java.lang.String |
getVariableName(int variable,
int width)
Get a semantic human-readable name for a variable.
|
protected double[] |
grow(double[] a,
int n)
grow(double[], int, double) with Double.NaN default |
protected double[] |
grow(double[] a,
int n,
double def)
Ensure a is at least length n.
|
double |
mag(double[] v,
int i,
int n)
mag(double[], int, int, boolean) , always computes 2-norm of
full index range. |
double |
mag(double[] v,
int i,
int n,
boolean maxComponentOnly)
Compute the 2-norm of the n-element vector starting at
v[i].
|
static void |
main(java.lang.String[] arg) |
protected PDLS.TimeMetrics |
makeMetrics(java.lang.String name,
java.lang.String globalName)
Make a new metrics object and link it to an associated entry in
globalMetrics . |
protected PDLS.TimeMetrics[] |
makePriorityMetrics(java.lang.String name)
make an entry in
allPriorityMetrics |
protected PDLS.TimeMetrics |
makeSolveMetrics(java.lang.String name)
make an entry in
allSolveMetrics |
protected void |
markEndMaybe(PDLS.TimeMetrics metrics)
TimeMetrics.markEnd() metrics iff enabled |
protected void |
markEndMaybe(PDLS.TimeMetrics[] metrics,
int i)
TimeMetrics.markEnd() metrics[i] iff enabled |
protected void |
markStartMaybe(PDLS.TimeMetrics metrics)
TimeMetrics.markStart() metrics iff enabled |
protected void |
markStartMaybe(PDLS.TimeMetrics[] metrics,
int i)
TimeMetrics.markStart() metrics[i] iff enabled |
static void |
resetGlobalStats()
reset global stats
|
void |
resetStats()
reset stats
|
void |
resetStepsize()
Reset
residualMaxMag , default impl sets nan. |
protected PDLS.TimeMetrics[] |
resizePriorityMetrics(int which,
int np)
resize an entry in
allPriorityMetrics |
protected void |
revertTheta(int convergenceIteration)
Called by generic impl of
updateProblem(int) . |
protected void |
saveCurrentResidual(int convergenceIteration)
Called by generic impl of
updateProblem(int) . |
double |
setAlwaysDampSigma(double threshold)
Set
alwaysDampSigma . |
double |
setAutoLambdaSlowdownThreshold(double threshold)
|
double |
setAutoLambdaSpeedupThreshold(double threshold)
|
double |
setAutoLambdaThetaDiffMaxMagScale(double scale)
|
void |
setDebugFlags(int flags)
set the indicated DBG_* flags
|
double |
setDivergenceFactor(double factor)
Set
divergenceFactor . |
double |
setDivergenceTol(double tol)
Set
divergenceTol . |
void |
setLambda(double l)
setLevelLambda(double, int) on all levels |
double |
setLevelLambda(double l,
int level)
Similar to
setResidualTol(double, int) but sets levelLambda . |
int |
setMaxConvergenceIterations(int m)
set
maxConvergenceIterations , non-positive to disable |
int |
setMaxConvergenceMS(int m)
set
maxConvergenceMS , non-positive to disable |
double |
setNeverDampSigma(double threshold)
Set
neverDampSigma . |
void |
setResidualMaxMag(double m)
setResidualMaxMag(double, int) on all levels |
double |
setResidualMaxMag(double m,
int level)
Similar to
setResidualTol(double, int) but sets residualMaxMag . |
void |
setResidualTol(double tol)
set
residualTol at all levels |
double |
setResidualTol(double tol,
int level)
Set
residualTol at the given level. |
double |
setSlowdownFactor(double factor)
Set
slowdownFactor . |
void |
setSlowdownLimit(double l)
setSlowdownLimit(double, int) on all levels |
double |
setSlowdownLimit(double l,
int level)
Set
slowdownLimit at the given level. |
double |
setSlowdownThreshold(double threshold)
Set
slowdownThreshold . |
double |
setSpeedupFactor(double factor)
Set
speedupFactor . |
void |
setSpeedupLimit(double l)
setSpeedupLimit(double, int) on all levels |
double |
setSpeedupLimit(double l,
int level)
Set
speedupLimit at the given level. |
double |
setSpeedupThreshold(double threshold)
Set
speedupThreshold . |
double |
setSVDTol(double tol)
Set
svdTol . |
double |
setThetaDiffMaxMag(double m)
Set
thetaDiffMaxMag . |
double |
setThetaDiffTol(double m)
Set
thetaDiffTol . |
PDLS.SolveStatus |
solve()
The main solve loop.
|
protected void |
updateJacobian(int convergenceIteration)
Called by generic impl of
updateProblem(int) . |
void |
updateLambda(int convergenceIteration)
Called by generic impl of
updateProblem(int) . |
protected void |
updatePostureVariation(int convergenceIteration)
Called by generic impl of
updateProblem(int) . |
protected int |
updateProblem(int convergenceIteration)
The application-specific problem update hook.
|
protected void |
updateResidual(int convergenceIteration)
Called by generic impl of
updateProblem(int) . |
protected void |
updateTheta(int convergenceIteration)
Called by generic impl of
updateProblem(int) . |
private static final java.lang.String cvsid
public static final java.lang.String[] DEF_SVD_IMPLS
svdImpl
names, in order of preferencepublic static final double DEF_SVD_TOL
svdTol
public static final double DEF_DIVERGENCE_FACTOR
divergenceFactor
public static final double DEF_DIVERGENCE_TOL
divergenceTol
public static final double DEF_EPS
eps
public static final double DEF_THETA_DIFF_MAX_MAG
thetaDiffMaxMag
public static final double DEF_THETA_DIFF_TOL
thetaDiffTol
public static final double DEF_NEVER_DAMP_SIGMA
neverDampSigma
public static final double DEF_ALWAYS_DAMP_SIGMA
alwaysDampSigma
public static final double DEF_AUTO_LAMBDA_THETA_DIFF_MAX_MAG_SCALE
autoLambdaThetaDiffMaxMagScale
public static final double DEF_SPEEDUP_THRESHOLD
speedupThreshold
public static final double DEF_SLOWDOWN_THRESHOLD
slowdownThreshold
public static double DEF_AUTO_LAMBDA_SLOWDOWN_THRESHOLD
autoLambdaSlowdownThreshold
public static double DEF_AUTO_LAMBDA_SPEEDUP_THRESHOLD
autoLambdaSpeedupThreshold
public static final double DEF_SPEEDUP_FACTOR
speedupFactor
public static final double DEF_SLOWDOWN_FACTOR
slowdownFactor
public static final int DEF_MIN_DIVERGABLE_LEVEL
minDivergableLevel
public static final int FMT_WIDTH
FMT
public static final java.lang.String FMT
public static final java.lang.String C_FMT
public volatile java.io.PrintStream dbgStream
public volatile int dbgFlags
public static final int DBG_CONTROL
public static final int DBG_STEPSIZE
public static final int DBG_SVD
public static final int DBG_RESIDUAL
public static final int DBG_LAMBDA
public static final int DBG_THETA
public static final int DBG_MATRICES
public static final int DBG_POSTURE
public static final int DBG_LIMITING
public static final int DBG_STEPSIZE_AND_LAMBDA
public static final int DBG_THETA_AND_RESIDUAL
public static final int DBG_ALL
public static final int DBG_ALL_BUT_MATRICES
protected int numVariables
Number of scalar variables.
This is the active length of theta
and the active number of
jacobian
columns.
Each updateProblem(int)
may change this, but it must always be
non-negative.
protected int numConstraints
Number of scalar constraints.
This is the number of equations in the problem, i.e. the number of
jacobian
rows.
Each updateProblem(int)
may change this, but it must always be
non-negative.
protected int numPriorities
Number of priority levels.
Must be positive whenever numConstraints
is, and always <=
numConstraints
after each updateProblem(int)
. The actual
split of the constraint equations into priority levels is given by priorityPartition
.
If priorityLevelsEnabled is false then solve()
behaves as if
numPriorities
were 1.
protected int[] priorityPartition
Partition of the constraints into priority levels.
After each updateProblem(int)
, this is an array of at least numPriorities
-1 positive integers (or it may be null if numPriorities
is <= 1) such that the sum of the first numPriorities
-1 elements is < numConstraints
. The
ith element specifies how many contiguous jacobian
rows
are to be solved together at priority level i, with the final
priority level implied. Level 0 is the highest-priority level.
If priorityLevelsEnabled is false then solve()
behaves as if
numPriorities
were 1, so priorityPartition
is
effectively ignored.
protected double[] levelLambda
Explicit damping constants to use for each priority level, if not null.
If null or whenever levelLambda[i] is not present or NaN then the damping constant for priority level i is computed (and saved to lastLevelLambda[i]) according to the following formulas adapted from [Baerlocher 2001]:
d[i] = ||In particular, this implies that ifcompensatedResidual
[i]||/ (thetaDiffMaxMag
*autoLambdaThetaDiffMaxMagScale
) minSigma[i] = minimum singular value ofrestrictedJacobian
[i] after applyingsvdTol
levelLambda[i] = 0 if minSigma[i] >= d[i]; else d[i]/2 if minSigma[i] <= d[i]/2; else sqrt(minSigma[i]*(d[i]-minSigma[i]))
residualMaxMag
is
rm for a given level and thetaDiffMaxMag
*autoLambdaThetaDiffMaxMagScale
is tm then the auto-computed
lambda for this level will ramp from 0 when minSigma >= rm/tm up
to (rm/tm)/2 when minSigma <= (rm/tm)/2.protected double[] lastLevelLambda
Actual per-level lambda values used for the most recent iteration.
These will equal the corresponding levelLambda
when that was
set, else they will be the results of auto compute.
Automatically allocated.
protected double thetaDiffMaxMag
Maximum allowed magnitude of thetaDiff
.
This implies levelLambda
[i] as described therein when
levelLambda
[i] itself is NaN. Also used to clamp the
magnitude of thetaDiff
before it is applied iff thetaDiffClampingEnabled
. Set to Double.POSITIVE_INFINITY
to disable, but note that also effectively disables auto-computed levelLambda
.
Initially DEF_THETA_DIFF_MAX_MAG
. May be set to any positive
value by each updateProblem(int)
protected double thetaDiffTol
Minimum thetaDiff
magnitude threshold below which solve()
returns PDLS.SolveStatus.STALLED
.
Stall checking is disabled if negative or NaN.
Initially DEF_THETA_DIFF_TOL
. May be set to any positive
value by each updateProblem(int)
.
protected double lastThetaDiffMag
Unclamped thetaDiff
magnitude of the prior convergence
iteration.
Initially NaN.
protected double[] theta
The current solution vector.
Must have length at least numVariables
after each updateProblem(int)
and represent the current values of the variables.
Initially null.
If non-null, i.e. after the first updateProblem(int)
and solve()
cycle have completed, then updateProblem(int)
can consider
this an input, if it chooses, (normally) update it by thetaDiff
, and then recompute residual
and jacobian
based on the result. updateProblem(int)
is always free to set theta
arbitrarily though, as long as all other problem state is also
consistently set.
protected double[] thetaWas
A copy of the starting theta
is saved here by the default impl
of updateProblem(int)
.
This copy is later used by revertTheta(int)
in the event that the
update diverged and abortOnDiverge
is set.
Automatically allocated as necessary.
protected double[] residual
The current residual (error) vector.
Must have length at least numConstraints
after each updateProblem(int)
, and represent the error of each constraint as a function
of the current theta
: residual[i] is the amount by
which we'd like to see the value of constraint i change. Initially
null.
solve()
acts to drive residual towards the zero vector.
protected double[] thetaLimitLower
Lower limit for each variable.
Must be null or have length at least numVariables
after each
updateProblem(int)
. Initially null. If null then no lower limits are
applied. Otherwise set an element to
Double.NEGATIVE_INFINITY
to disable the lower limit for that
variable.
protected double[] thetaLimitUpper
Upper limit for each variable.
Must be null or have length at least numVariables
after each
updateProblem(int)
and no thetaLimitUpper[i] can be <=
thetaLimitLower
[i]. Initially null. If null then no
upper limits are applied. Otherwise set an element to
Double.POSITIVE_INFINITY
to disable the upper limit for that
variable.
protected double[] jacobian
The jacobian relating the first-order variation of theta
to
the variation of residual
.
Stored packed column major, so jacobian[i+j*numConstraints
] must be the partial derivative of the residual of
constraint i with respect to variable j. Length must be at
least numConstraints
*numVariables
after each updateProblem(int)
. Initially null.
protected double[] postureVariation
Desired posture variation or null.
Must be null or have length at least numVariables
after each
updateProblem(int)
. If non-null and postureVariationEnabled
this is the desired theta
variation which is applied as a
lowest-priority task.
protected double[] thetaDiff
Computed optimal change in theta
after each solve()
cycle.
If non-null then, normally, this is the change in theta
recommended by the prior solve()
cycle, and normally updateProblem(int)
would update theta
by the vector addition of
thetaDiff
. Initially null. If null or shorter than numVariables
after updateProblem(int)
then re-allocated at the start
of the solve()
cycle. Initial content, if any, always ignored by
solve()
.
protected double[] limitingVariation
limitingVariation[i] is zero when ith variable (element of
theta
) is unlocked after a solve()
cycle, else the
sign of limitingVariation[i] indicates the direction of the limit to
which the ith variable is locked, and the magnitude indicates the
limiting variation, which is the difference between the full desired change
in the ith variable and the maximum allowable change up to the
effective limit.
Limiting is only performed if limitingEnabled
.
Initially null. If null or shorter than numVariables
after
updateProblem(int)
then re-allocated at the start of the solve()
cycle. Initial content, if any, always ignored by solve()
.
protected double[] compensatedResidual
Compensated residual for each priority level.
This is used internally by each iteration of the solve()
priority loop. For the first level, it equals the corresponding
components of residual
. For later levels it equals the
corresponding components of residual
minus the forward projection
of the thetaDiff
accumulated so far for earlier levels through
the accumulated jacobian
for those levels.
Initially null. If null or shorter than the tallest priority level
after each updateProblem(int)
, then re-allocated at the start of the
solve()
cycle. Initial content, if any, always ignored by solve()
.
protected double[] restrictedJacobian
The jacobian relating the first-order variation of theta
to
the variation the residual
for an individual priority level,
restricted to the nullspace of the superior priority levels, or its
transpose.
Stored packed column-major for compatibility with LAPACK.
This is used internally by each iteration of the solve()
priority loop. Initially null. If null or if the length is not at least
(tallest priority level height)*numVariables
then re-allocated at
the start of the solve()
cycle. Initial content, if any, always
ignored by solve()
.
protected double[] residualMaxMag
The magnitude of the uncompensated residual at priority level i is clamped to have maximum euclidean norm residualMaxMag[i], if the latter is present.
If postureVariationEnabled
, residualMaxMag
[numPriorities
] is the posture variation limit.
Clamping at level i is performed only if residualMaxMag is non-null and contains at least i+1 elements.
If adaptiveStepSizeEnabled
is set residualMaxMag is
automatically managed as described in the class header doc.
protected double[] residualTol
If present, these are the per-level allowable residual magnitudes for
the system to be considered converged in the default impl of checkConvergence(int)
.
These are also used as a default for slowdownLimit
when that
is not explicitly set.
If postureVariationEnabled
, residualTol
[numPriorities
] is the posture variation tolerance.
protected double[] lastResidualMag
Unclamped uncompensated residual magnitude at each priority level in the prior convergence iteration.
If postureVariationEnabled
, lastResidualMag
[numPriorities
] is the unclamped posture variation magnitude in the prior
convergence iteration.
Automatically allocated.
protected double[] nullspaceProjector
Projection matrix taking an arbitrary thetaDiff
vector to the
nullspace of superior priority levels.
This is used internally by each iteration of the solve()
priority loop. Stored packed column major. Initially null. If null or
if length is not at least numVariables
*numVariables
then
re-allocated at the start of the solve()
cycle. Initial content,
if any, always ignored by solve()
.
protected double[] svdA
Input to SVD.thinSVD(int, int, double[], double[], double[], double[])
.
This starts out as a copy of restrictedJacobian
, but may be
destroyed by the SVD implementation.
protected double[] svdS
Singular values in decreasing order for restrictedJacobian
.
This is used internally by each iteration of the solve()
priority loop. Initially null. If null or if the length is not at least
min((tallest priority level height), numVariables
) then
re-allocated at the start of the solve()
cycle. Initial content,
if any, always ignored by solve()
.
protected double[] svdU
Left singular vectors for restrictedJacobian
or right singular
vectors for its transpose.
Stored packed column-major for compatibility with LAPACK.
This is used internally by each iteration of the solve()
priority loop. Initially null. If null or if the length is not at least
(tallest priority level height)*min((tallest priority level height),
numVariables
) then re-allocated at the start of the solve()
cycle. Initial content, if any, always ignored by solve()
.
protected double[] svdVT
Right singular vectors for restrictedJacobian
or left
singular vectors for its transpose.
Stored packed column-major for compatibility with LAPACK.
This is used internally by each iteration of the solve()
priority loop. Initially null. If null or if the length is not at least
min((tallest priority level height), numVariables
)*numVariables
then re-allocated at the start of the solve()
cycle.
Initial content, if any, always ignored by solve()
.
protected double svdTol
Threshold below which a singular value is clamped to zero.
Not only does this directly affect the numeric rank computations, it
also interacts with auto lambda, since singular values that are clamped to
zero will be less than any non-zero neverDampSigma
.
Initially DEF_SVD_TOL
. May be set to any value by each updateProblem(int)
.
protected int svdStatus
Status result of the most recent SVD.thinSVD(int, int, double[], double[], double[], double[])
call.
public final SVD svdImpl
The underlying SVD implementation.
This should not be used concurrently by anything else.
protected double divergenceTol
Used in the default impl of checkConvergence(int)
, see which.
protected double divergenceFactor
Used in the default impl of checkConvergence(int)
, see which.
protected double neverDampSigma
Singular value (after applying svdTol
) above which
auto-computed damping will never be applied.
Damping is only applied when dampingEnabled
. This threshold
only applies to auto-computed levelLambda
.
Initially DEF_NEVER_DAMP_SIGMA
. May be set to any value by
each updateProblem(int)
. Thresholding disabled if NaN or
infinity.
protected double alwaysDampSigma
Singular value (after applying svdTol
) below which
auto-computed damping will always be applied.
Damping is only applied when dampingEnabled
. This threshold
only applies to auto-computed levelLambda
.
Initially DEF_ALWAYS_DAMP_SIGMA
. May be set to any value by
each updateProblem(int)
. Thresholding disabled if NaN or
infinity.
protected double autoLambdaThetaDiffMaxMagScale
Scale factor applied to thetaDiffMaxMag
for the purposes of
auto-lambda computation.
Initially DEF_AUTO_LAMBDA_THETA_DIFF_MAX_MAG_SCALE
. May be
set to any value by each updateProblem(int)
. Disabled (treated as 1)
if NaN or non-positive.
protected double[] pseudoinverse
Working space to compute pseudoinverse of restrictedJacobian
.
Allocated as necessary.
protected double[] dampedPseudoinverse
Working space to compute damped pseudoinverse of restrictedJacobian
.
Allocated as necessary.
protected double eps
Threshold below which the difference between two doubles is considered insignificant.
Initially DEF_EPS
. May be set to any non-negative value by
each updateProblem(int)
.
protected int[] restrictedJacobianRank
If non-null the computed rank of the restrictedJacobian
at
level i is saved as restrictedJacobianRank[i].
The rank at level i is saved during a solve()
cycle only
if restrictedJacobianRank is non-null and contains at least i+1
elements.
This is computed as a metric only.
protected double[] residualWas
If non-null then the previous value of residual
is saved here
in the default implementation of updateProblem(int)
.
This is used to check for divergence in the default implementation of
checkConvergence(int)
.
If allocated this must have length at least numConstraints
,
and its initial value must be all NaN.
public volatile boolean abortOnInterrupt
solve()
on indicated conditionpublic volatile boolean abortOnSVDError
solve()
on indicated conditionpublic volatile boolean abortOnDiverge
solve()
on indicated conditionpublic volatile boolean alwaysUpdateWholeProblem
Whether updateProblem(int)
should update everything even if
converged or diverging and abortOnDiverge
.
public volatile boolean convergenceEnabled
Enable for indicated part of solve()
.
If convergence is not enabled then solve()
just calls updateProblem(int)
once and then returns.
If limiting is not enabled then variables will not be limited.
If priority levels are not enabled then all variables are solved at level 0.
If posture variation is not enabled then it is not applied.
If thetaDiff
clamping is not enabled then the computed thetaDiff
after each convergence iteration will not be clamped to thetaDiffMaxMag
. However, thetaDiffMaxMag
still plays its roll
when auto-computing levelLambda
and in adaptive step size.
public volatile boolean limitingEnabled
Enable for indicated part of solve()
.
If convergence is not enabled then solve()
just calls updateProblem(int)
once and then returns.
If limiting is not enabled then variables will not be limited.
If priority levels are not enabled then all variables are solved at level 0.
If posture variation is not enabled then it is not applied.
If thetaDiff
clamping is not enabled then the computed thetaDiff
after each convergence iteration will not be clamped to thetaDiffMaxMag
. However, thetaDiffMaxMag
still plays its roll
when auto-computing levelLambda
and in adaptive step size.
public volatile boolean priorityLevelsEnabled
Enable for indicated part of solve()
.
If convergence is not enabled then solve()
just calls updateProblem(int)
once and then returns.
If limiting is not enabled then variables will not be limited.
If priority levels are not enabled then all variables are solved at level 0.
If posture variation is not enabled then it is not applied.
If thetaDiff
clamping is not enabled then the computed thetaDiff
after each convergence iteration will not be clamped to thetaDiffMaxMag
. However, thetaDiffMaxMag
still plays its roll
when auto-computing levelLambda
and in adaptive step size.
public volatile boolean postureVariationEnabled
Enable for indicated part of solve()
.
If convergence is not enabled then solve()
just calls updateProblem(int)
once and then returns.
If limiting is not enabled then variables will not be limited.
If priority levels are not enabled then all variables are solved at level 0.
If posture variation is not enabled then it is not applied.
If thetaDiff
clamping is not enabled then the computed thetaDiff
after each convergence iteration will not be clamped to thetaDiffMaxMag
. However, thetaDiffMaxMag
still plays its roll
when auto-computing levelLambda
and in adaptive step size.
public volatile boolean thetaDiffClampingEnabled
Enable for indicated part of solve()
.
If convergence is not enabled then solve()
just calls updateProblem(int)
once and then returns.
If limiting is not enabled then variables will not be limited.
If priority levels are not enabled then all variables are solved at level 0.
If posture variation is not enabled then it is not applied.
If thetaDiff
clamping is not enabled then the computed thetaDiff
after each convergence iteration will not be clamped to thetaDiffMaxMag
. However, thetaDiffMaxMag
still plays its roll
when auto-computing levelLambda
and in adaptive step size.
public volatile boolean dampingEnabled
Enable for indicated part of solve()
.
If convergence is not enabled then solve()
just calls updateProblem(int)
once and then returns.
If limiting is not enabled then variables will not be limited.
If priority levels are not enabled then all variables are solved at level 0.
If posture variation is not enabled then it is not applied.
If thetaDiff
clamping is not enabled then the computed thetaDiff
after each convergence iteration will not be clamped to thetaDiffMaxMag
. However, thetaDiffMaxMag
still plays its roll
when auto-computing levelLambda
and in adaptive step size.
public volatile boolean adaptiveStepSizeEnabled
Enable for indicated part of solve()
.
If convergence is not enabled then solve()
just calls updateProblem(int)
once and then returns.
If limiting is not enabled then variables will not be limited.
If priority levels are not enabled then all variables are solved at level 0.
If posture variation is not enabled then it is not applied.
If thetaDiff
clamping is not enabled then the computed thetaDiff
after each convergence iteration will not be clamped to thetaDiffMaxMag
. However, thetaDiffMaxMag
still plays its roll
when auto-computing levelLambda
and in adaptive step size.
public volatile boolean metricsEnabled
Enable for indicated part of solve()
.
If convergence is not enabled then solve()
just calls updateProblem(int)
once and then returns.
If limiting is not enabled then variables will not be limited.
If priority levels are not enabled then all variables are solved at level 0.
If posture variation is not enabled then it is not applied.
If thetaDiff
clamping is not enabled then the computed thetaDiff
after each convergence iteration will not be clamped to thetaDiffMaxMag
. However, thetaDiffMaxMag
still plays its roll
when auto-computing levelLambda
and in adaptive step size.
public volatile boolean singleStep
solve()
public volatile boolean clampThetaDiffByComponent
Whether thetaDiffMaxMag
or residualMaxMag
should be
applied as vector 2-norms or on a per-component basis.
public volatile boolean clampResidualByComponent
Whether thetaDiffMaxMag
or residualMaxMag
should be
applied as vector 2-norms or on a per-component basis.
public volatile double speedupThreshold
If adaptiveStepSizeEnabled
, this is the thetaDiff
magnitude threshold below which a speedup will be incurred.
Expressed as a fraction of thetaDiffMaxMag
.
Initially DEF_SPEEDUP_THRESHOLD
. Typically <= 1.
NaN disables speedup.
public volatile double slowdownThreshold
If adaptiveStepSizeEnabled
, this is the thetaDiff
magnitude threshold above which a slowdown will be incurred.
Expressed as a fraction of thetaDiffMaxMag
.
Initially DEF_SLOWDOWN_THRESHOLD
. Typically >= 1.
Infinity or NaN disables check.
public volatile double autoLambdaSlowdownThreshold
If adaptiveStepSizeEnabled
a slowdown is triggered whenever
the largest auto-computed lastLevelLambda
exceeds this
threshold.
Initially DEF_AUTO_LAMBDA_SLOWDOWN_THRESHOLD
. NaN disables
check.
public volatile double autoLambdaSpeedupThreshold
If adaptiveStepSizeEnabled
a speedup is enabled whenever
the largest auto-computed lastLevelLambda
does not exceed this
threshold.
Initially DEF_AUTO_LAMBDA_SPEEDUP_THRESHOLD
. NaN disables
check.
public volatile double speedupFactor
If adaptiveStepSizeEnabled
, this is the multiplicative change
applied to residualMaxMag
in a speedup.
Initially DEF_SPEEDUP_FACTOR
. Typically > 1. Negative or
NaN disables speedup.
public volatile double slowdownFactor
If adaptiveStepSizeEnabled
, this is the multiplicative change
applied to residualMaxMag
in a slowdown.
Initially DEF_SLOWDOWN_FACTOR
. Typically < 1. Negative or
NaN disables slowdown.
protected double[] slowdownLimit
Lower limit for adaptive slowdown.
If set at a level then adaptive slowdown will be clamped to this limit.
Otherwise adaptive slowdown is clamped to residualTol
for the
level, if set, else eps
.
If postureVariationEnabled
, slowdownLimit
[numPriorities
] is the posture variation slowdown limit.
protected double[] speedupLimit
Upper limit for adaptive speedup.
If set at a level then adaptive speedup will be clamped to this limit.
If postureVariationEnabled
, speedupLimit
[numPriorities
] is the posture variation speedup limit.
If adaptiveStepSizeEnabled
and divergence is detected at a
level p, will be (allocated if necessary and) clamped to at most
residualMaxMag
[p] after slowdown.
public volatile int maxConvergenceIterations
Maximum number of convergence cycle iterations per call to solve()
.
If updateProblem(int)
still returns true even after this number of
iterations, solve()
returns PDLS.SolveStatus.MAX_ITERATIONS
.
Check disabled if non-positive.
public volatile int maxConvergenceMS
Maximum number of time spent in convergence cycle iterations per call
to solve()
.
If updateProblem(int)
still returns true even after this amount of
time, solve()
returns PDLS.SolveStatus.MAX_TIME
.
Check disabled if non-positive.
public volatile int minDivergableLevel
The lowest-numbered (i.e. highest priority) priority level that's allowed to diverge.
public volatile PDLS.SolveStatus lastSolveStatus
solve()
, or null if noneprotected static boolean globalMetricsEnabled
Whether global time metrics are collected across all PDLS instances.
TBD: Current impl is not synchronized!
protected static java.util.Map<java.lang.String,PDLS.TimeMetrics> globalMetrics
globalMetricsEnabled
protected final java.util.List<PDLS.TimeMetrics> allSolveMetrics
solve()
metricsprotected final java.util.List<PDLS.TimeMetrics[]> allPriorityMetrics
protected final java.util.List<java.lang.String> allPriorityMetricNames
protected final PDLS.TimeMetrics solveCycleMetrics
PDLS.TimeMetrics
on indicated part of solve()
protected final PDLS.TimeMetrics checkConvergenceMetrics
PDLS.TimeMetrics
on indicated part of solve()
protected final PDLS.TimeMetrics updateProblemMetrics
PDLS.TimeMetrics
on indicated part of solve()
protected final PDLS.TimeMetrics convergenceCycleMetrics
PDLS.TimeMetrics
on indicated part of solve()
protected final PDLS.TimeMetrics reallocMetrics
PDLS.TimeMetrics
on indicated part of solve()
protected final PDLS.TimeMetrics limitingCycleMetrics
PDLS.TimeMetrics
on indicated part of solve()
protected final PDLS.TimeMetrics postureVariationMetrics
PDLS.TimeMetrics
on indicated part of solve()
protected final PDLS.TimeMetrics lockingMetrics
PDLS.TimeMetrics
on indicated part of solve()
protected final PDLS.TimeMetrics thetaDiffMetrics
PDLS.TimeMetrics
on indicated part of solve()
protected PDLS.TimeMetrics[] priorityCycleMetrics
Per-priority-level PDLS.TimeMetrics
on indicated part of solve()
.
protected PDLS.TimeMetrics[] restrictedJacobianMetrics
Per-priority-level PDLS.TimeMetrics
on indicated part of solve()
.
protected PDLS.TimeMetrics[] svdMetrics
Per-priority-level PDLS.TimeMetrics
on indicated part of solve()
.
protected PDLS.TimeMetrics[] compensatedResidualMetrics
Per-priority-level PDLS.TimeMetrics
on indicated part of solve()
.
protected PDLS.TimeMetrics[] levelLambdaMetrics
Per-priority-level PDLS.TimeMetrics
on indicated part of solve()
.
protected PDLS.TimeMetrics[] pseudoinverseMetrics
Per-priority-level PDLS.TimeMetrics
on indicated part of solve()
.
protected PDLS.TimeMetrics[] levelThetaDiffMetrics
Per-priority-level PDLS.TimeMetrics
on indicated part of solve()
.
protected PDLS.TimeMetrics[] nullspaceProjectorMetrics
Per-priority-level PDLS.TimeMetrics
on indicated part of solve()
.
public PDLS(SVD svdImpl)
Constructor given an SVD impl instance.
The SVD impl instance should not be shared with anything else.
public PDLS(java.lang.String[] impls)
Conses first available SVD impl with SVD.cons(java.lang.String)
.
public PDLS(java.lang.String impl)
Conses SVD impl with SVD.cons(java.lang.String)
.
public PDLS()
DEF_SVD_IMPLS
static SVD consSVD(java.lang.String[] impls)
Returns first available SVD impl with SVD.cons(java.lang.String)
.
public PDLS.SolveStatus solve()
The main solve loop.
See the class header documentation for details.
protected int updateProblem(int convergenceIteration)
The application-specific problem update hook.
A default implementation is provided which does
thetaWas
as necessarytheta
to thetaWas
updateTheta(int)
saveCurrentResidual(int)
if iteration > 0updateResidual(int)
saveCurrentResidual(int)
if iteration == 0alwaysUpdateWholeProblem
or checkConvergence(int)
>
0 or checkConvergence(int)
< 0 and not abortOnDiverge
abortOnDiverge
and diverging at < minDivergableLevel
then revertTheta(int)
and updateResidual(int)
checkConvergence(int)
was > 0See the class header documentation for details.
convergenceIteration
- the number of prior convergence iterations in
this call to solve()
protected void saveCurrentResidual(int convergenceIteration)
Called by generic impl of updateProblem(int)
.
Default impl saves residual
to residualWas
.
protected void updateTheta(int convergenceIteration)
Called by generic impl of updateProblem(int)
.
protected void revertTheta(int convergenceIteration)
Called by generic impl of updateProblem(int)
.
protected void updateResidual(int convergenceIteration)
Called by generic impl of updateProblem(int)
.
Default impl does nothing.
protected void updateJacobian(int convergenceIteration)
Called by generic impl of updateProblem(int)
.
Default impl does nothing.
public void updateLambda(int convergenceIteration)
Called by generic impl of updateProblem(int)
.
Default impl does nothing.
protected void updatePostureVariation(int convergenceIteration)
Called by generic impl of updateProblem(int)
.
Default impl does nothing.
public int checkConvergence(int convergenceIteration)
Check the current convergence status.
Called by generic impl of updateProblem(int)
.
If residual
is not null then the magnitude of the residual at
each priority level p is compared with tol, which is
residualTol[p], if present, or with eps
if not. The
return value is the count of priority levels whose residuals do not meet
the tolerance, unless divergence is detected. To detect divergence at a
level p, residualWas
must be non-null and non-NaN at that
level. Divergence is considered to be an increase in the magnitude of the
residual at the level more than divergenceTol
plus divergenceFactor
times its value in residualWas
. If divergence
is detected at level p then the return value is -(p+1).
If priorityLevelsEnabled
false causes this method to behave
exactly as if numPriorities
was 1.
Vector magnitudes are computed as 2-norms uness clampResidualByComponent
, in which case the magnitude of a vector is the
absolute value of its largest component.
public int setMaxConvergenceIterations(int m)
maxConvergenceIterations
, non-positive to disablepublic int getMaxConvergenceIterations()
public int setMaxConvergenceMS(int m)
maxConvergenceMS
, non-positive to disablepublic int getMaxConvergenceMS()
maxConvergenceMS
public double setThetaDiffMaxMag(double m)
Set thetaDiffMaxMag
.
Pass NaN to use DEF_THETA_DIFF_MAX_MAG
, +inf to disable.
public double getThetaDiffMaxMag()
thetaDiffMaxMag
public double setThetaDiffTol(double m)
Set thetaDiffTol
.
Pass NaN to use DEF_THETA_DIFF_TOL
, 0 to disable.
public double getThetaDiffTol()
thetaDiffTol
public double setSVDTol(double tol)
Set svdTol
.
Pass NaN to use DEF_SVD_TOL
, 0 to disable.
public double getSVDTol()
svdTol
public double setResidualTol(double tol, int level)
Set residualTol
at the given level.
If residualTol
is currently null or too short it will be
consed for all levels, but set to NaN except at level.
Pass NaN to use eps
.
public void setResidualTol(double tol)
residualTol
at all levelspublic double getResidualTol(int level)
residualTol
at level or NaN if undefinedpublic double setResidualMaxMag(double m, int level)
Similar to setResidualTol(double, int)
but sets residualMaxMag
.
Pass NaN or +inf to disable.
public void setResidualMaxMag(double m)
setResidualMaxMag(double, int)
on all levelspublic double getResidualMaxMag(int level)
residualMaxMag
at level or NaN if undefinedpublic void resetStepsize()
Reset residualMaxMag
, default impl sets nan.
public double setDivergenceFactor(double factor)
Set divergenceFactor
.
Pass NaN to use DEF_DIVERGENCE_FACTOR
, 0 to disable.
public double getDivergenceFactor()
divergenceFactor
public double setDivergenceTol(double tol)
Set divergenceTol
.
Pass NaN to use DEF_DIVERGENCE_TOL
, 0 to disable.
public double getDivergenceTol()
divergenceTol
public double setNeverDampSigma(double threshold)
Set neverDampSigma
.
Pass NaN to use DEF_NEVER_DAMP_SIGMA
, 0 to disable.
public double getNeverDampSigma()
neverDampSigma
public double setAlwaysDampSigma(double threshold)
Set alwaysDampSigma
.
Pass NaN to use DEF_ALWAYS_DAMP_SIGMA
, 0 to disable.
public double getAlwaysDampSigma()
alwaysDampSigma
public double setAutoLambdaThetaDiffMaxMagScale(double scale)
Set autoLambdaThetaDiffMaxMagScale
.
Pass NaN or non-positive to use DEF_AUTO_LAMBDA_THETA_DIFF_MAX_MAG_SCALE
.
public double getAutoLambdaThetaDiffMaxMagScale()
public double setSpeedupThreshold(double threshold)
Set speedupThreshold
.
Pass NaN to use DEF_SPEEDUP_THRESHOLD
, 0 to disable.
public double getSpeedupThreshold()
speedupThreshold
public double setSlowdownThreshold(double threshold)
Set slowdownThreshold
.
Pass NaN to use DEF_SLOWDOWN_THRESHOLD
, 0 to disable.
public double getSlowdownThreshold()
public double setAutoLambdaSlowdownThreshold(double threshold)
Set autoLambdaSlowdownThreshold
.
Pass NaN to use DEF_AUTO_LAMBDA_SLOWDOWN_THRESHOLD
, 0 to
disable.
public double getAutoLambdaSlowdownThreshold()
public double setAutoLambdaSpeedupThreshold(double threshold)
Set autoLambdaSpeedupThreshold
.
Pass NaN to use DEF_AUTO_LAMBDA_SPEEDUP_THRESHOLD
, 0 to
disable.
public double getAutoLambdaSpeedupThreshold()
public double setSpeedupFactor(double factor)
Set speedupFactor
.
Pass NaN to use DEF_SPEEDUP_FACTOR
, 0 to disable.
public double getSpeedupFactor()
speedupFactor
public double setSlowdownFactor(double factor)
Set slowdownFactor
.
Pass NaN to use DEF_SLOWDOWN_FACTOR
, 0 to disable.
public double getSlowdownFactor()
slowdownFactor
public double setSlowdownLimit(double l, int level)
Set slowdownLimit
at the given level.
If slowdownLimit
is currently null or too short it will be
consed for all levels, but set to NaN except at level.
Pass NaN to unset.
public void setSlowdownLimit(double l)
setSlowdownLimit(double, int)
on all levelspublic double getSlowdownLimit(int level)
slowdownLimit
at level or NaN if undefinedpublic double setSpeedupLimit(double l, int level)
Set speedupLimit
at the given level.
If speedupLimit
is currently null or too short it will be
consed for all levels, but set to NaN except at level.
Pass NaN to unset.
public void setSpeedupLimit(double l)
setSpeedupLimit(double, int)
on all levelspublic double getSpeedupLimit(int level)
speedupLimit
at level or NaN if undefinedpublic double setLevelLambda(double l, int level)
Similar to setResidualTol(double, int)
but sets levelLambda
.
Pass NaN to auto-compute.
public void setLambda(double l)
setLevelLambda(double, int)
on all levelspublic double getLevelLambda(int level)
levelLambda
at level or NaN if undefinedpublic int getMaxLevelSize()
Get the size of the largest priority level.
public double clamp(double[] v, int i, int n, double maxMag, boolean byComponent)
Clamp the n-element vector starting at v[i] to the max 2-norm maxMag.
v
- array containing the vectori
- the index of the first element of the vectorn
- the length of the vector , <= i+v.lengthmaxMag
- the maximum magnitude of the result, sign ignoredbyComponent
- whether to clamp each component of v in the
specified index range separatelypublic double clamp(double[] v, int i, int n, double maxMag)
clamp(double[], int, int, double, boolean)
, clamps 2-norm of
full index range.
public double mag(double[] v, int i, int n, boolean maxComponentOnly)
Compute the 2-norm of the n-element vector starting at v[i].
v
- array containing the vectori
- the index of the first element of the vectorn
- the length of the vector, <= i+v.lengthmaxComponentOnly
- whether to only return the magnitude of the
maximum component of v in the specified index rangepublic double mag(double[] v, int i, int n)
mag(double[], int, int, boolean)
, always computes 2-norm of
full index range.
public void dumpStructure(java.io.PrintStream s)
public void dumpStructure()
dumpStructure(PrintStream)
to System.outprotected PDLS.TimeMetrics makeSolveMetrics(java.lang.String name)
allSolveMetrics
protected PDLS.TimeMetrics[] makePriorityMetrics(java.lang.String name)
allPriorityMetrics
protected PDLS.TimeMetrics[] resizePriorityMetrics(int which, int np)
allPriorityMetrics
protected PDLS.TimeMetrics makeMetrics(java.lang.String name, java.lang.String globalName)
Make a new metrics object and link it to an associated entry in globalMetrics
.
protected void markStartMaybe(PDLS.TimeMetrics metrics)
TimeMetrics.markStart()
metrics iff enabledprotected void markEndMaybe(PDLS.TimeMetrics metrics)
TimeMetrics.markEnd()
metrics iff enabledprotected void markStartMaybe(PDLS.TimeMetrics[] metrics, int i)
TimeMetrics.markStart()
metrics[i] iff enabledprotected void markEndMaybe(PDLS.TimeMetrics[] metrics, int i)
TimeMetrics.markEnd()
metrics[i] iff enabledpublic void dumpStats(java.io.PrintStream s)
public void dumpStats()
dumpStats(PrintStream)
to System.outpublic static void dumpGlobalStats(java.io.PrintStream s)
public static void dumpGlobalStats()
dumpGlobalStats(PrintStream)
to System.outpublic void resetStats()
public static void resetGlobalStats()
protected void dumpForLevelsMaybe(double[] value, int np, java.lang.String msg, java.io.PrintStream s)
protected void dumpForLevelsMaybe(double[] value, java.lang.String msg, java.io.PrintStream s)
dumpForLevelsMaybe(double[], int, String, PrintStream)
all
effectrive levels excluding posture variation.
protected void dumpForLevelsMaybe(int[] value, java.lang.String msg, java.io.PrintStream s)
public void dumpNumericDetails(java.io.PrintStream s)
public void dumpNumericDetails()
dumpNumericDetails(PrintStream)
to System.outpublic java.lang.String getVariableName(int variable, int width)
Get a semantic human-readable name for a variable.
Default impl returns the variable number.
width
- the requested maximum width of the namepublic java.lang.String getConstraintName(int constraint, int width)
Get a semantic human-readable name for a constraint.
Default impl returns the constraint number.
width
- the requested maximum width of the namepublic java.lang.String getPriorityLevelName(int level)
Get a semantic human-readable name for a priority level.
Default impl returns the level number.
public void dumpJacobian(java.io.PrintStream s)
public void dumpJacobian()
dumpJacobian(PrintStream)
to System.outpublic void dump(java.io.PrintStream s, double[] v, int n)
public void dumpMatrix(java.io.PrintStream s, double[] a, int m, int n, java.lang.String msg)
public void setDebugFlags(int flags)
public void clearDebugFlags(int flags)
protected double[] grow(double[] a, int n, double def)
Ensure a is at least length n.
If necessary, a is reallocated. Its current contents are preserved, and any new entries are set to def.
a
- the array to grow, may be nulln
- the minimum new sizedef
- the default value for new entriesprotected double[] grow(double[] a, int n)
grow(double[], int, double)
with Double.NaN defaultprotected double getLevelParam(double[] param, int p, double def)
Get the param value at level p, if allocated and not NaN, else def.
protected double getLevelParam(double[] param, int p)
getLevelParam(double[], int, double)
default NaNprotected boolean dbgEnabled(int flags)
public static void main(java.lang.String[] arg)