6105 lines
232 KiB
C#
6105 lines
232 KiB
C#
using UnityEngine;
|
||
using System.Threading;
|
||
using System.Collections.Generic;
|
||
|
||
namespace BioIK {
|
||
|
||
//----------------------------------------------------------------------------------------------------
|
||
//====================================================================================================
|
||
//Memetic Evolutionary Optimisation
|
||
//====================================================================================================
|
||
//----------------------------------------------------------------------------------------------------
|
||
public class Evolution {
|
||
private Model Model; //Reference to the kinematic model
|
||
private int PopulationSize; //Number of individuals (population size)
|
||
private int Elites; //Number of elite individuals
|
||
private int Dimensionality; //Search space dimensionality
|
||
|
||
private double[] LowerBounds; //Constraints for the lower bounds
|
||
private double[] UpperBounds; //Constraints for the upper bounds
|
||
|
||
private Individual[] Population; //Array for current individuals
|
||
private Individual[] Offspring; //Array for offspring individuals
|
||
|
||
private List<Individual> Pool = new List<Individual>(); //Selection pool for recombination
|
||
private int PoolCount; //Current size of the selection pool
|
||
private double[] Probabilities; //Current probabilities for selection
|
||
private double Gene; //Simple storage variable #1
|
||
private double Weight; //Simple storage variable #2
|
||
private bool[] Constrained;
|
||
|
||
//Variables for elitism exploitation
|
||
private bool UseThreading;
|
||
private bool Evolving = false;
|
||
private bool[] Improved = null;
|
||
private Model[] Models = null;
|
||
private BFGS[] Optimisers = null;
|
||
|
||
//Threading
|
||
private bool ThreadsRunning = false;
|
||
private ManualResetEvent[] Handles = null;
|
||
private Thread[] Threads = null;
|
||
private bool[] Work = null;
|
||
|
||
//Variables for optimisation queries
|
||
private double[] Solution; //Evolutionary solution
|
||
private double Fitness; //Evolutionary fitness
|
||
|
||
private bool Killed = false;
|
||
|
||
//Initialises the algorithm
|
||
public Evolution(Model model, int populationSize, int elites, bool useThreading) {
|
||
Model = model;
|
||
PopulationSize = populationSize;
|
||
Elites = elites;
|
||
Dimensionality = model.GetDoF();
|
||
UseThreading = useThreading;
|
||
|
||
Population = new Individual[PopulationSize];
|
||
Offspring = new Individual[PopulationSize];
|
||
for(int i=0; i<PopulationSize; i++) {
|
||
Population[i] = new Individual(Dimensionality);
|
||
Offspring[i] = new Individual(Dimensionality);
|
||
}
|
||
|
||
LowerBounds = new double[Dimensionality];
|
||
UpperBounds = new double[Dimensionality];
|
||
Constrained = new bool[Dimensionality];
|
||
Probabilities = new double[PopulationSize];
|
||
Solution = new double[Dimensionality];
|
||
|
||
Models = new Model[Elites];
|
||
Optimisers = new BFGS[Elites];
|
||
Improved = new bool[Elites];
|
||
for(int i=0; i<Elites; i++) {
|
||
int index = i;
|
||
Models[index] = new Model(Model.GetCharacter());
|
||
Optimisers[index] = new BFGS(Dimensionality, x => Models[index].ComputeLoss(x), y => Models[index].ComputeGradient(y, 1e-5));
|
||
}
|
||
|
||
if(UseThreading) {
|
||
//Start Threads
|
||
ThreadsRunning = true;
|
||
Work = new bool[Elites];
|
||
Handles = new ManualResetEvent[Elites];
|
||
Threads = new Thread[Elites];
|
||
for(int i=0; i<Elites; i++) {
|
||
int index = i;
|
||
Work[index] = false;
|
||
Handles[index] = new ManualResetEvent(true);
|
||
Threads[index] = new Thread(x => SurviveThread(index));
|
||
//Threads[index].Start();
|
||
}
|
||
} else {
|
||
ThreadsRunning = false;
|
||
}
|
||
}
|
||
|
||
~Evolution() {
|
||
Kill();
|
||
}
|
||
|
||
public void Kill() {
|
||
if(Killed) {
|
||
return;
|
||
}
|
||
Killed = true;
|
||
if(UseThreading) {
|
||
//Stop Threads
|
||
ThreadsRunning = false;
|
||
for(int i=0; i<Elites; i++) {
|
||
if(Threads[i].IsAlive) {
|
||
Handles[i].Set();
|
||
Threads[i].Join();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
public double[] Optimise(int generations, double[] seed) {
|
||
if(UseThreading) {
|
||
for(int i=0; i<Elites; i++) {
|
||
if(!Threads[i].IsAlive) {
|
||
Threads[i].Start();
|
||
}
|
||
}
|
||
}
|
||
|
||
Model.Refresh();
|
||
|
||
for(int i=0; i<Dimensionality; i++) {
|
||
LowerBounds[i] = Model.MotionPtrs[i].Motion.GetLowerLimit(true);
|
||
UpperBounds[i] = Model.MotionPtrs[i].Motion.GetUpperLimit(true);
|
||
Constrained[i] = Model.MotionPtrs[i].Motion.Constrained;
|
||
Solution[i] = seed[i];
|
||
}
|
||
Fitness = Model.ComputeLoss(Solution);
|
||
|
||
if(!Model.CheckConvergence(Solution)) {
|
||
Initialise(seed);
|
||
for(int i=0; i<Elites; i++) {
|
||
Models[i].CopyFrom(Model);
|
||
Optimisers[i].LowerBounds = LowerBounds;
|
||
Optimisers[i].UpperBounds = UpperBounds;
|
||
}
|
||
for(int i=0; i<generations; i++) {
|
||
//for(int i=0; i<25; i++) { //Performance testing
|
||
Evolve();
|
||
}
|
||
}
|
||
|
||
return Solution;
|
||
}
|
||
|
||
//Initialises the population with the seed
|
||
private void Initialise(double[] seed) {
|
||
for(int i=0; i<Dimensionality; i++) {
|
||
Population[0].Genes[i] = seed[i];
|
||
Population[0].Momentum[i] = 0.0;
|
||
}
|
||
Population[0].Fitness = Model.ComputeLoss(Population[0].Genes);
|
||
|
||
for(int i=1; i<PopulationSize; i++) {
|
||
Reroll(Population[i]);
|
||
}
|
||
|
||
SortByFitness();
|
||
|
||
ComputeExtinctions();
|
||
|
||
TryUpdateSolution();
|
||
}
|
||
|
||
//One evolutionary cycle
|
||
private void Evolve() {
|
||
//Create mating pool
|
||
Pool.Clear();
|
||
Pool.AddRange(Population);
|
||
PoolCount = PopulationSize;
|
||
|
||
if(UseThreading) {
|
||
//Evolve offspring
|
||
Evolving = true;
|
||
|
||
//Exploit elites in threads
|
||
for(int i=0; i<Elites; i++) {
|
||
Handles[i].Set();
|
||
}
|
||
|
||
//Evolve non elites sequentially
|
||
for(int i=Elites; i<PopulationSize; i++) {
|
||
if(PoolCount > 0) {
|
||
Individual parentA = Select(Pool);
|
||
Individual parentB = Select(Pool);
|
||
Individual prototype = Select(Pool);
|
||
|
||
//Recombination and Adoption
|
||
Reproduce(Offspring[i], parentA, parentB, prototype);
|
||
|
||
//Pre-Selection Niching
|
||
if(Offspring[i].Fitness < parentA.Fitness) {
|
||
Pool.Remove(parentA);
|
||
PoolCount -= 1;
|
||
}
|
||
if(Offspring[i].Fitness < parentB.Fitness) {
|
||
Pool.Remove(parentB);
|
||
PoolCount -= 1;
|
||
}
|
||
} else {
|
||
//Fill the population
|
||
Reroll(Offspring[i]);
|
||
}
|
||
}
|
||
|
||
//Finish evolving
|
||
Evolving = false;
|
||
|
||
//Wait for threads to finish
|
||
//System.DateTime timer = Utility.GetTimestamp();
|
||
while(HasWork()) {
|
||
//Wait one cycle
|
||
/*
|
||
if(Utility.GetElapsedTime(timer) > 0.5f) {
|
||
Debug.Log("!!! !!! !!! FIXING CRASH !!! !!! !!!");
|
||
for(int i=0; i<Work.Length; i++) {
|
||
Debug.Log("Work: " + i + " : " + Work[i]);
|
||
}
|
||
break;
|
||
}
|
||
*/
|
||
}
|
||
|
||
} else {
|
||
//Evolve offspring
|
||
System.DateTime timestamp = Utility.GetTimestamp();
|
||
for(int i=Elites; i<PopulationSize; i++) {
|
||
if(PoolCount > 0) {
|
||
Individual parentA = Select(Pool);
|
||
Individual parentB = Select(Pool);
|
||
Individual prototype = Select(Pool);
|
||
|
||
//Recombination and Adoption
|
||
Reproduce(Offspring[i], parentA, parentB, prototype);
|
||
|
||
//Pre-Selection Niching
|
||
if(Offspring[i].Fitness < parentA.Fitness) {
|
||
Pool.Remove(parentA);
|
||
PoolCount -= 1;
|
||
}
|
||
if(Offspring[i].Fitness < parentB.Fitness) {
|
||
Pool.Remove(parentB);
|
||
PoolCount -= 1;
|
||
}
|
||
} else {
|
||
//Fill the population
|
||
Reroll(Offspring[i]);
|
||
}
|
||
}
|
||
double duration = Utility.GetElapsedTime(timestamp);
|
||
|
||
//Exploit elites sequentially
|
||
for(int i=0; i<Elites; i++) {
|
||
SurviveSequential(i, duration);
|
||
}
|
||
}
|
||
|
||
//Reroll elite if exploitation was not successful
|
||
for(int i=0; i<Elites; i++) {
|
||
if(!Improved[i]) {
|
||
Reroll(Offspring[i]);
|
||
}
|
||
}
|
||
|
||
//Swap population and offspring
|
||
Swap(ref Population, ref Offspring);
|
||
|
||
//Finalise
|
||
SortByFitness();
|
||
|
||
//Check improvement and wipeout criterion
|
||
if(!TryUpdateSolution() && !HasAnyEliteImproved()) {
|
||
Initialise(Solution);
|
||
} else {
|
||
ComputeExtinctions();
|
||
}
|
||
}
|
||
|
||
//Returns the mutation probability from two parents
|
||
private double GetMutationProbability(Individual parentA, Individual parentB) {
|
||
double extinction = 0.5 * (parentA.Extinction + parentB.Extinction);
|
||
double inverse = 1.0/(double)Dimensionality;
|
||
return extinction * (1.0-inverse) + inverse;
|
||
}
|
||
|
||
//Returns the mutation strength from two parents
|
||
private double GetMutationStrength(Individual parentA, Individual parentB) {
|
||
return 0.5 * (parentA.Extinction + parentB.Extinction);
|
||
}
|
||
|
||
//Computes the extinction factors for all individuals
|
||
private void ComputeExtinctions() {
|
||
double min = Population[0].Fitness;
|
||
double max = Population[PopulationSize-1].Fitness;
|
||
for(int i=0; i<PopulationSize; i++) {
|
||
double grading = (double)i/((double)PopulationSize-1);
|
||
Population[i].Extinction = (Population[i].Fitness + min*(grading-1.0)) / max;
|
||
}
|
||
}
|
||
|
||
private bool HasWork() {
|
||
for(int i=0; i<Elites; i++) {
|
||
if(Work[i]) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
//Returns whether any elite could be improved by the exploitation
|
||
private bool HasAnyEliteImproved() {
|
||
for(int i=0; i<Elites; i++) {
|
||
if(Improved[i]){
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
//Tries to improve the evolutionary solution by the population, and returns whether it was successful
|
||
private bool TryUpdateSolution() {
|
||
double candidateFitness = Population[0].Fitness;
|
||
if(candidateFitness < Fitness) {
|
||
for(int i=0; i<Dimensionality; i++) {
|
||
Solution[i] = Population[0].Genes[i];
|
||
}
|
||
Fitness = candidateFitness;
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
private void SurviveThread(int index) {
|
||
while(ThreadsRunning) {
|
||
Work[index] = true;
|
||
|
||
//Copy elitist survivor
|
||
Individual survivor = Population[index];
|
||
Individual elite = Offspring[index];
|
||
for(int i=0; i<Dimensionality; i++) {
|
||
elite.Genes[i] = survivor.Genes[i];
|
||
elite.Momentum[i] = survivor.Momentum[i];
|
||
}
|
||
|
||
//Exploit
|
||
double fitness = Models[index].ComputeLoss(elite.Genes);
|
||
Optimisers[index].Minimise(elite.Genes, ref Evolving);
|
||
if(Optimisers[index].Value < fitness) {
|
||
for(int i=0; i<Dimensionality; i++) {
|
||
elite.Momentum[i] = Optimisers[index].Solution[i] - elite.Genes[i];
|
||
elite.Genes[i] = Optimisers[index].Solution[i];
|
||
}
|
||
elite.Fitness = Optimisers[index].Value;
|
||
Improved[index] = true;
|
||
} else {
|
||
elite.Fitness = fitness;
|
||
Improved[index] = false;
|
||
}
|
||
|
||
Handles[index].Reset();
|
||
|
||
//Finish
|
||
Work[index] = false;
|
||
|
||
Handles[index].WaitOne();
|
||
}
|
||
}
|
||
|
||
private void SurviveSequential(int index, double timeout) {
|
||
//Copy elitist survivor
|
||
Individual survivor = Population[index];
|
||
Individual elite = Offspring[index];
|
||
for(int i=0; i<Dimensionality; i++) {
|
||
elite.Genes[i] = survivor.Genes[i];
|
||
elite.Momentum[i] = survivor.Momentum[i];
|
||
}
|
||
|
||
//Exploit
|
||
double fitness = Models[index].ComputeLoss(elite.Genes);
|
||
Optimisers[index].Minimise(elite.Genes, timeout);
|
||
if(Optimisers[index].Value < fitness) {
|
||
for(int i=0; i<Dimensionality; i++) {
|
||
elite.Momentum[i] = Optimisers[index].Solution[i] - elite.Genes[i];
|
||
elite.Genes[i] = Optimisers[index].Solution[i];
|
||
}
|
||
elite.Fitness = Optimisers[index].Value;
|
||
Improved[index] = true;
|
||
} else {
|
||
elite.Fitness = fitness;
|
||
Improved[index] = false;
|
||
}
|
||
}
|
||
|
||
//Evolves a new individual
|
||
private void Reproduce(Individual offspring, Individual parentA, Individual parentB, Individual prototype) {
|
||
double mutationProbability = GetMutationProbability(parentA, parentB);
|
||
double mutationStrength = GetMutationStrength(parentA, parentB);
|
||
|
||
for(int i=0; i<Dimensionality; i++) {
|
||
//Recombination
|
||
Weight = Random.value;
|
||
double momentum = Random.value * parentA.Momentum[i] + Random.value * parentB.Momentum[i];
|
||
offspring.Genes[i] = Weight*parentA.Genes[i] + (1.0-Weight)*parentB.Genes[i] + momentum;
|
||
|
||
//Store
|
||
Gene = offspring.Genes[i];
|
||
|
||
//Mutation
|
||
if(Constrained[i]) {
|
||
if(Random.value < mutationProbability) {
|
||
offspring.Genes[i] += (Random.value * (UpperBounds[i] - LowerBounds[i]) + LowerBounds[i]) * mutationStrength;
|
||
}
|
||
}
|
||
|
||
//Adoption
|
||
Weight = Random.value;
|
||
offspring.Genes[i] +=
|
||
Weight * Random.value * (0.5 * (parentA.Genes[i] + parentB.Genes[i]) - offspring.Genes[i])
|
||
+ (1.0-Weight) * Random.value * (prototype.Genes[i] - offspring.Genes[i]);
|
||
|
||
//Project
|
||
if(Constrained[i]) {
|
||
if(offspring.Genes[i] < LowerBounds[i]) {
|
||
offspring.Genes[i] = LowerBounds[i];
|
||
}
|
||
if(offspring.Genes[i] > UpperBounds[i]) {
|
||
offspring.Genes[i] = UpperBounds[i];
|
||
}
|
||
}
|
||
|
||
//Momentum
|
||
offspring.Momentum[i] = Random.value * momentum + (offspring.Genes[i] - Gene);
|
||
}
|
||
|
||
//Fitness
|
||
offspring.Fitness = Model.ComputeLoss(offspring.Genes);
|
||
}
|
||
|
||
//Generates a random individual
|
||
private void Reroll(Individual individual) {
|
||
for(int i=0; i<Dimensionality; i++) {
|
||
if(Constrained[i]) {
|
||
individual.Genes[i] = (double)Random.Range((float)LowerBounds[i], (float)UpperBounds[i]);
|
||
individual.Momentum[i] = 0.0;
|
||
} else {
|
||
individual.Genes[i] = Solution[i];
|
||
individual.Momentum[i] = 0.0;
|
||
}
|
||
}
|
||
individual.Fitness = Model.ComputeLoss(individual.Genes);
|
||
}
|
||
|
||
//Rank-based selection of an individual
|
||
private Individual Select(List<Individual> pool) {
|
||
double rankSum = (double)(PoolCount*(PoolCount+1)) / 2.0;
|
||
for(int i=0; i<PoolCount; i++) {
|
||
Probabilities[i] = (double)(PoolCount-i)/rankSum;
|
||
}
|
||
return pool[GetRandomWeightedIndex(Probabilities, PoolCount)];
|
||
}
|
||
|
||
//Returns a random index with respect to the probability weights
|
||
private int GetRandomWeightedIndex(double[] probabilities, int count) {
|
||
double weightSum = 0.0;
|
||
for(int i=0; i<count; i++) {
|
||
weightSum += probabilities[i];
|
||
}
|
||
double rVal = Random.value * weightSum;
|
||
for(int i=0; i<count; i++) {
|
||
rVal -= probabilities[i];
|
||
if(rVal <= 0.0) {
|
||
return i;
|
||
}
|
||
}
|
||
return count-1;
|
||
}
|
||
|
||
/*
|
||
//Projects a single gene to stay within search space
|
||
private double Project(double gene, double min, double max, bool constrained) {
|
||
if(max - min == 0.0) {
|
||
return 0.0;
|
||
}
|
||
if(type == JointType.Revolute || type == JointType.Prismatic) {
|
||
//Bounce
|
||
while(gene < min || gene > max) {
|
||
if(gene > max) {
|
||
gene = max + max - gene;
|
||
}
|
||
if(gene < min) {
|
||
gene = min + min - gene;
|
||
}
|
||
}
|
||
}
|
||
if(type == JointType.Continuous) {
|
||
//Overflow
|
||
while(gene < -PI || gene > PI) {
|
||
if(gene > PI) {
|
||
gene -= PI + PI;
|
||
}
|
||
if(gene < -PI) {
|
||
gene += PI + PI;
|
||
}
|
||
}
|
||
}
|
||
if(type == JointType.Floating) {
|
||
//nothing
|
||
}
|
||
return gene;
|
||
}
|
||
*/
|
||
|
||
//Sorts the population by their fitness values (descending)
|
||
private void SortByFitness() {
|
||
System.Array.Sort(Population,
|
||
delegate(Individual a, Individual b) {
|
||
return a.Fitness.CompareTo(b.Fitness);
|
||
}
|
||
);
|
||
}
|
||
|
||
//In-place swap by references
|
||
private void Swap(ref Individual[] a, ref Individual[] b) {
|
||
Individual[] tmp = a;
|
||
a = b;
|
||
b = tmp;
|
||
}
|
||
|
||
public Model GetModel() {
|
||
return Model;
|
||
}
|
||
|
||
public double[] GetSolution() {
|
||
return Solution;
|
||
}
|
||
|
||
public double GetFitness() {
|
||
return Fitness;
|
||
}
|
||
|
||
public double[] GetLowerBounds() {
|
||
return LowerBounds;
|
||
}
|
||
|
||
public double[] GetUpperBounds() {
|
||
return UpperBounds;
|
||
}
|
||
|
||
public double[,] GetGeneLandscape() {
|
||
double[,] values = new double[PopulationSize, Dimensionality];
|
||
for(int i=0; i<PopulationSize; i++) {
|
||
for(int j=0; j<Dimensionality; j++) {
|
||
values[i,j] = Population[i].Genes[j];
|
||
}
|
||
}
|
||
return values;
|
||
}
|
||
|
||
public double[] GetFitnessLandscape() {
|
||
double[] values = new double[PopulationSize];
|
||
for(int i=0; i<PopulationSize; i++) {
|
||
values[i] = Population[i].Fitness;
|
||
}
|
||
return values;
|
||
}
|
||
|
||
//Data class for the individuals
|
||
public class Individual {
|
||
public double[] Genes;
|
||
public double[] Momentum;
|
||
public double Fitness;
|
||
public double Extinction;
|
||
|
||
public Individual(int dimensionality) {
|
||
Genes = new double[dimensionality];
|
||
Momentum = new double[dimensionality];
|
||
Fitness = 0.0;
|
||
Extinction = 0.0;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// Limited-memory Broyden–Fletcher–Goldfarb–Shanno (L-BFGS) optimization method.
|
||
|
||
/// The L-BFGS algorithm is a member of the broad family of quasi-Newton optimization
|
||
/// methods. L-BFGS stands for 'Limited memory BFGS'. Indeed, L-BFGS uses a limited
|
||
/// memory variation of the Broyden–Fletcher–Goldfarb–Shanno (BFGS) update to approximate
|
||
/// the inverse Hessian matrix (denoted by Hk). Unlike the original BFGS method which
|
||
/// stores a dense approximation, L-BFGS stores only a few vectors that represent the
|
||
/// approximation implicitly. Due to its moderate memory requirement, L-BFGS method is
|
||
/// particularly well suited for optimization problems with a large number of variables.
|
||
/// L-BFGS never explicitly forms or stores Hk. Instead, it maintains a history of the past
|
||
/// m updates of the position x and gradient g, where generally the history
|
||
/// m can be short, often less than 10. These updates are used to implicitly do operations
|
||
/// requiring the Hk-vector product.
|
||
|
||
/// The framework implementation of this method is based on the original FORTRAN source code
|
||
/// by Jorge Nocedal (see references below). The original FORTRAN source code of L-BFGS (for
|
||
/// unconstrained problems) is available at http://www.netlib.org/opt/lbfgs_um.shar and had
|
||
/// been made available under the public domain.
|
||
///
|
||
/// References:
|
||
/// http://www.netlib.org/opt/lbfgs_um.shar
|
||
/// Jorge Nocedal. Limited memory BFGS method for large scale optimization (Fortran source code). 1990.
|
||
/// Available in http://www.netlib.org/opt/lbfgs_um.shar
|
||
/// Jorge Nocedal. Updating Quasi-Newton Matrices with Limited Storage. Mathematics of Computation,
|
||
/// Vol. 35, No. 151, pp. 773--782, 1980.
|
||
/// Dong C. Liu, Jorge Nocedal. On the limited memory BFGS method for large scale optimization.
|
||
|
||
public partial class BFGS {
|
||
|
||
public enum Task{None, Start, New_X, FG, FG_LN, FG_ST, Abnormal, Convergence, Error, Restart_LN, Warning};
|
||
|
||
public System.Func<double[], double> Function;
|
||
public System.Func<double[], double[]> Gradient;
|
||
public int Dimensionality;
|
||
public double[] Solution;
|
||
public double Value;
|
||
public double[] LowerBounds;
|
||
public double[] UpperBounds;
|
||
|
||
private const double stpmin = 1e-20;
|
||
private const double stpmax = 1e20;
|
||
private int Corrections = 1;
|
||
private double Factor = 1e+5;
|
||
private double Tolerance = 0.0;
|
||
private int IPrint = 101;
|
||
private int TotalSize = 0;
|
||
|
||
private double F;
|
||
private double[] G;
|
||
|
||
private bool[] LSave;
|
||
private int[] ISave;
|
||
private double[] DSave;
|
||
|
||
private int[] IWA;
|
||
private int[] NBD;
|
||
private double[] Work;
|
||
|
||
private Task _Task;
|
||
private Task _CSave;
|
||
|
||
private double NewF;
|
||
private double[] NewG;
|
||
|
||
public BFGS(int dimensionality, System.Func<double[], double> function, System.Func<double[], double[]> gradient) {
|
||
Dimensionality = dimensionality;
|
||
Function = function;
|
||
Gradient = gradient;
|
||
UpperBounds = new double[Dimensionality];
|
||
LowerBounds = new double[Dimensionality];
|
||
Solution = new double[Dimensionality];
|
||
|
||
TotalSize = 2 * Corrections * Dimensionality + 11 * Corrections * Corrections + 5 * Dimensionality + 8 * Corrections;
|
||
NBD = new int[Dimensionality];
|
||
for(int i=0; i<Dimensionality; i++) {
|
||
NBD[i] = 2;
|
||
}
|
||
|
||
F = 0.0;
|
||
G = new double[Dimensionality];
|
||
LSave = new bool[4];
|
||
ISave = new int[44];
|
||
DSave = new double[29];
|
||
IWA = new int[3 * Dimensionality];
|
||
Work = new double[TotalSize];
|
||
_Task = Task.Start;
|
||
_CSave = Task.None;
|
||
NewF = 0;
|
||
NewG = null;
|
||
}
|
||
|
||
public void Minimise(double[] values, ref bool evolving) {
|
||
for(int i=0; i<Dimensionality; i++) {
|
||
Solution[i] = values[i];
|
||
}
|
||
|
||
F = 0.0;
|
||
System.Array.Clear(G, 0, G.Length);
|
||
System.Array.Clear(LSave, 0, LSave.Length);
|
||
System.Array.Clear(ISave, 0, ISave.Length);
|
||
System.Array.Clear(DSave, 0, DSave.Length);
|
||
System.Array.Clear(IWA, 0, IWA.Length);
|
||
System.Array.Clear(Work, 0, Work.Length);
|
||
_Task = Task.Start;
|
||
_CSave = Task.None;
|
||
NewF = 0;
|
||
NewG = null;
|
||
|
||
while(evolving) {
|
||
setulb(
|
||
Dimensionality, Corrections, Solution, 0, LowerBounds, 0, UpperBounds, 0, NBD, 0, ref F, G, 0,
|
||
Factor, Tolerance, Work, 0, IWA, 0, ref _Task, IPrint, ref _CSave,
|
||
LSave, 0, ISave, 0, DSave, 0
|
||
);
|
||
|
||
if(_Task == Task.FG_LN || _Task == Task.FG_ST) {
|
||
NewF = Function(Solution);
|
||
NewG = Gradient(Solution);
|
||
F = NewF;
|
||
for(int i=0; i<Dimensionality; i++) {
|
||
G[i] = NewG[i];
|
||
}
|
||
}
|
||
}
|
||
|
||
Value = Function(Solution);
|
||
}
|
||
|
||
public void Minimise(double[] values, double timeout) {
|
||
for(int i=0; i<Dimensionality; i++) {
|
||
Solution[i] = values[i];
|
||
}
|
||
|
||
F = 0.0;
|
||
System.Array.Clear(G, 0, G.Length);
|
||
System.Array.Clear(LSave, 0, LSave.Length);
|
||
System.Array.Clear(ISave, 0, ISave.Length);
|
||
System.Array.Clear(DSave, 0, DSave.Length);
|
||
System.Array.Clear(IWA, 0, IWA.Length);
|
||
System.Array.Clear(Work, 0, Work.Length);
|
||
_Task = Task.Start;
|
||
_CSave = Task.None;
|
||
NewF = 0;
|
||
NewG = null;
|
||
|
||
System.DateTime timestamp = Utility.GetTimestamp();
|
||
while(Utility.GetElapsedTime(timestamp) < timeout) {
|
||
setulb(
|
||
Dimensionality, Corrections, Solution, 0, LowerBounds, 0, UpperBounds, 0, NBD, 0, ref F, G, 0,
|
||
Factor, Tolerance, Work, 0, IWA, 0, ref _Task, IPrint, ref _CSave,
|
||
LSave, 0, ISave, 0, DSave, 0
|
||
);
|
||
|
||
if(_Task == Task.FG_LN || _Task == Task.FG_ST) {
|
||
NewF = Function(Solution);
|
||
NewG = Gradient(Solution);
|
||
F = NewF;
|
||
for(int i=0; i<Dimensionality; i++) {
|
||
G[i] = NewG[i];
|
||
}
|
||
}
|
||
}
|
||
|
||
Value = Function(Solution);
|
||
}
|
||
|
||
}
|
||
|
||
/*
|
||
public partial class BFGS {
|
||
|
||
public enum Task{None, Start, New_X, FG, FG_LN, FG_ST, Abnormal, Convergence, Error, Restart_LN, Warning};
|
||
|
||
public int NumberOfVariables { get; protected set; }
|
||
public System.Func<double[], double> Function { get; set; }
|
||
public System.Func<double[], double[]> Gradient { get; set; }
|
||
public double[] Solution;
|
||
public double Value;
|
||
public double[] UpperBounds;
|
||
public double[] LowerBounds;
|
||
|
||
private const double stpmin = 1e-20;
|
||
private const double stpmax = 1e20;
|
||
private int corrections = 1;
|
||
private double[] work;
|
||
private double factr = 1e+5;
|
||
private double pgtol = 0.0;
|
||
private int n;
|
||
private int m;
|
||
private Task task = Task.None;
|
||
private Task csave = Task.None;
|
||
private int totalSize;
|
||
private int iprint;
|
||
private bool[] lsave;
|
||
private int[] nbd;
|
||
private int[] iwa;
|
||
private int[] isave;
|
||
private double f;
|
||
private double[] l;
|
||
private double[] u;
|
||
private double[] g;
|
||
private double[] dsave;
|
||
private double newF;
|
||
private double[] newG;
|
||
|
||
public BFGS(int numberOfVariables, System.Func<double[], double> function, System.Func<double[], double[]> gradient) {
|
||
NumberOfVariables = numberOfVariables;
|
||
Function = function;
|
||
Gradient = gradient;
|
||
Solution = new double[numberOfVariables];
|
||
UpperBounds = new double[numberOfVariables];
|
||
LowerBounds = new double[numberOfVariables];
|
||
|
||
n = NumberOfVariables;
|
||
m = corrections;
|
||
totalSize = 2 * m * n + 11 * m * m + 5 * n + 8 * m;
|
||
iprint = 101;
|
||
lsave = new bool[4];
|
||
nbd = new int[n];
|
||
iwa = new int[3*n];
|
||
isave = new int[44];
|
||
l = new double[n];
|
||
u = new double[n];
|
||
g = new double[n];
|
||
dsave = new double[29];
|
||
work = new double[totalSize];
|
||
}
|
||
|
||
private void Prepare(double[] values) {
|
||
for(int i=0; i<NumberOfVariables; i++) {
|
||
Solution[i] = values[i];
|
||
}
|
||
|
||
task = Task.None;
|
||
csave = Task.None;
|
||
for(int i=0; i<4; i++) {
|
||
lsave[i] = false;
|
||
}
|
||
for(int i=0; i<n; i++) {
|
||
nbd[i] = 2;
|
||
}
|
||
for(int i=0; i<3*n; i++) {
|
||
iwa[i] = 0;
|
||
}
|
||
for(int i=0; i<44; i++) {
|
||
isave[i] = 0;
|
||
}
|
||
for(int i=0; i<n; i++) {
|
||
l[i] = LowerBounds[i];
|
||
u[i] = UpperBounds[i];
|
||
}
|
||
for(int i=0; i<29; i++) {
|
||
dsave[i] = 0.0;
|
||
}
|
||
for(int i=0; i<totalSize; i++) {
|
||
work[i] = 0.0;
|
||
}
|
||
|
||
f = 0.0d;
|
||
for(int i=0; i<n; i++) {
|
||
g[i] = 0.0;
|
||
}
|
||
|
||
newF = 0;
|
||
newG = null;
|
||
}
|
||
|
||
public void Minimise(double[] values, ref bool evolving) {
|
||
Prepare(values);
|
||
Optimise(ref evolving);
|
||
Value = Function(Solution);
|
||
}
|
||
|
||
private void Optimise(ref bool evolving) {
|
||
task = Task.Start;
|
||
while(evolving) {
|
||
setulb(n, m, Solution, 0, l, 0, u, 0, nbd, 0, ref f, g, 0,
|
||
factr, pgtol, work, 0, iwa, 0, ref task, iprint, ref csave,
|
||
lsave, 0, isave, 0, dsave, 0);
|
||
|
||
if (task == Task.FG_LN || task == Task.FG_ST) {
|
||
newF = Function(Solution);
|
||
newG = Gradient(Solution);
|
||
f = newF;
|
||
for (int j = 0; j < newG.Length; j++) {
|
||
g[j] = newG[j];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
public void Minimise(double[] values, double timeout) {
|
||
Prepare(values);
|
||
Optimise(timeout);
|
||
Value = Function(Solution);
|
||
}
|
||
|
||
private void Optimise(double timeout) {
|
||
System.DateTime then = System.DateTime.Now;
|
||
task = Task.Start;
|
||
while((System.DateTime.Now-then).Duration().TotalSeconds < timeout) {
|
||
setulb(n, m, Solution, 0, l, 0, u, 0, nbd, 0, ref f, g, 0,
|
||
factr, pgtol, work, 0, iwa, 0, ref task, iprint, ref csave,
|
||
lsave, 0, isave, 0, dsave, 0);
|
||
|
||
if (task == Task.FG_LN || task == Task.FG_ST) {
|
||
newF = Function(Solution);
|
||
newG = Gradient(Solution);
|
||
f = newF;
|
||
for (int j = 0; j < newG.Length; j++) {
|
||
g[j] = newG[j];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
*/
|
||
|
||
partial class BFGS
|
||
{
|
||
|
||
//
|
||
// c======================= The end of mainlb =============================
|
||
//
|
||
//
|
||
//
|
||
// c ************
|
||
// c
|
||
// c Subroutine active
|
||
// c
|
||
// c This subroutine initializes iwhere and projects the initial x to
|
||
// c the feasible set if necessary.
|
||
// c
|
||
// c iwhere is an integer array of dimension n.
|
||
// c On entry iwhere is unspecified.
|
||
// c On exit iwhere(i)=-1 if x(i) has no bounds
|
||
// c 3 if l(i)=u(i)
|
||
// c 0 otherwise.
|
||
// c In cauchy, iwhere is given finer gradations.
|
||
// c
|
||
// c
|
||
// c * * *
|
||
// c
|
||
// c NEOS, November 1994. (Latest revision June 1996.)
|
||
// c Optimization Technology Center.
|
||
// c Argonne National Laboratory and Northwestern University.
|
||
// c Written by
|
||
// c Ciyou Zhu
|
||
// c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
|
||
// c
|
||
// c
|
||
// c ************
|
||
//
|
||
//
|
||
// c Initialize nbdd, prjctd, cnstnd and boxed.
|
||
//
|
||
private static void active(int n, double[] l, int _l_offset, double[] u, int _u_offset, int[] nbd,
|
||
int _nbd_offset, double[] x, int _x_offset, int[] iwhere, int _iwhere_offset, int iprint,
|
||
ref bool prjctd, ref bool cnstnd, ref bool boxed)
|
||
{
|
||
|
||
int nbdd = 0;
|
||
int i = 0;
|
||
nbdd = 0;
|
||
prjctd = false;
|
||
cnstnd = false;
|
||
boxed = true;
|
||
//
|
||
// c Project the initial x to the feasible set if necessary.
|
||
//
|
||
{
|
||
for (i = 1; i <= n; i++)
|
||
{
|
||
if ((nbd[(i - (1)) + _nbd_offset] > 0))
|
||
{
|
||
if (((nbd[(i - (1)) + _nbd_offset] <= 2)
|
||
&& (x[(i - (1)) + _x_offset] <= l[(i - (1)) + _l_offset])))
|
||
{
|
||
if ((x[(i - (1)) + _x_offset] < l[(i - (1)) + _l_offset]))
|
||
{
|
||
prjctd = true;
|
||
x[(i - (1)) + _x_offset] = l[(i - (1)) + _l_offset];
|
||
}
|
||
nbdd = (nbdd + 1);
|
||
}
|
||
else if (((nbd[(i - (1)) + _nbd_offset] >= 2)
|
||
&& (x[(i - (1)) + _x_offset] >= u[(i - (1)) + _u_offset])))
|
||
{
|
||
if ((x[(i - (1)) + _x_offset] > u[(i - (1)) + _u_offset]))
|
||
{
|
||
prjctd = true;
|
||
x[(i - (1)) + _x_offset] = u[(i - (1)) + _u_offset];
|
||
}
|
||
nbdd = (nbdd + 1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
//
|
||
// c Initialize iwhere and assign values to cnstnd and boxed.
|
||
//
|
||
{
|
||
for (i = 1; i <= n; i++)
|
||
{
|
||
if ((nbd[(i - (1)) + _nbd_offset] != 2))
|
||
{
|
||
boxed = false;
|
||
}
|
||
if ((nbd[(i - (1)) + _nbd_offset] == 0))
|
||
{
|
||
// this variable is always free
|
||
iwhere[(i - (1)) + _iwhere_offset] = -1;
|
||
//
|
||
// otherwise set x(i)=mid(x(i), u(i), l(i)).
|
||
}
|
||
else
|
||
{
|
||
cnstnd = true;
|
||
if (((nbd[(i - (1)) + _nbd_offset] == 2) &&
|
||
((u[(i - (1)) + _u_offset] - l[(i - (1)) + _l_offset]) <= 0.0)))
|
||
{
|
||
// this variable is always fixed
|
||
iwhere[(i - (1)) + _iwhere_offset] = 3;
|
||
}
|
||
else
|
||
{
|
||
iwhere[(i - (1)) + _iwhere_offset] = 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
if ((iprint >= 0))
|
||
{
|
||
if (prjctd)
|
||
{
|
||
// DISPLAY: The initial X is infeasible. Restart with its projection.";
|
||
}
|
||
if ((!cnstnd))
|
||
{
|
||
// DISPLAY: "This problem is unconstrained."
|
||
}
|
||
}
|
||
|
||
if ((iprint > 0))
|
||
{
|
||
// DISPLAY: 'At X0 ',i9,' variables are exactly at the bounds'" (nbdd)
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// c====================== The end of dpofa ===============================
|
||
//
|
||
// c
|
||
// c
|
||
// c dtrsl solves systems of the form
|
||
// c
|
||
// c t * x = b
|
||
// c or
|
||
// c trans(t) * x = b
|
||
// c
|
||
// c where t is a triangular matrix of order n. here trans(t)
|
||
// c denotes the transpose of the matrix t.
|
||
// c
|
||
// c on entry
|
||
// c
|
||
// c t double precision(ldt,n)
|
||
// c t contains the matrix of the system. the zero
|
||
// c elements of the matrix are not referenced, and
|
||
// c the corresponding elements of the array can be
|
||
// c used to store other information.
|
||
// c
|
||
// c ldt integer
|
||
// c ldt is the leading dimension of the array t.
|
||
// c
|
||
// c n integer
|
||
// c n is the order of the system.
|
||
// c
|
||
// c b double precision(n).
|
||
// c b contains the right hand side of the system.
|
||
// c
|
||
// c job integer
|
||
// c job specifies what kind of system is to be solved.
|
||
// c if job is
|
||
// c
|
||
// c 00 solve t*x=b, t lower triangular,
|
||
// c 01 solve t*x=b, t upper triangular,
|
||
// c 10 solve trans(t)*x=b, t lower triangular,
|
||
// c 11 solve trans(t)*x=b, t upper triangular.
|
||
// c
|
||
// c on return
|
||
// c
|
||
// c b b contains the solution, if info .eq. 0.
|
||
// c otherwise b is unaltered.
|
||
// c
|
||
// c info integer
|
||
// c info contains zero if the system is nonsingular.
|
||
// c otherwise info contains the index of
|
||
// c the first zero diagonal element of t.
|
||
// c
|
||
// c linpack. this version dated 08/14/78 .
|
||
// c g. w. stewart, university of maryland, argonne national lab.
|
||
// c
|
||
// c subroutines and functions
|
||
// c
|
||
// c blas daxpy,ddot
|
||
// c fortran mod
|
||
// c
|
||
// c internal variables
|
||
// c
|
||
// c
|
||
// c begin block permitting ...exits to 150
|
||
// c
|
||
// c check for zero diagonal elements.
|
||
// c
|
||
|
||
private static void dtrsl(double[] t, int _t_offset, int ldt, int n,
|
||
double[] b, int _b_offset, int job, ref int info)
|
||
{
|
||
double temp = 0.0d;
|
||
int Case = 0;
|
||
int j = 0;
|
||
int jj = 0;
|
||
|
||
{
|
||
for (info = 1; info <= n; info++)
|
||
{
|
||
// ......exit
|
||
if ((t[(info - (1)) + (info - (1)) * (ldt) + _t_offset] == 0.0e0))
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
info = 0;
|
||
|
||
//
|
||
// determine the task and go to it.
|
||
//
|
||
Case = 1;
|
||
|
||
if (((job) % (10) != 0))
|
||
{
|
||
Case = 2;
|
||
}
|
||
|
||
if ((((job) % (100) / 10) != 0))
|
||
{
|
||
Case = (Case + 2);
|
||
}
|
||
|
||
{
|
||
int _cg_tmp = Case;
|
||
if (_cg_tmp == 1)
|
||
goto L20;
|
||
else if (_cg_tmp == 2)
|
||
goto L50;
|
||
else if (_cg_tmp == 3)
|
||
goto L80;
|
||
else if (_cg_tmp == 4)
|
||
goto L110;
|
||
}
|
||
|
||
//
|
||
// solve t*x=b for t lower triangular
|
||
//
|
||
L20:
|
||
|
||
b[(1 - (1)) + _b_offset] = (b[(1 - (1)) + _b_offset]
|
||
/ t[(1 - (1)) + (1 - (1)) * (ldt) + _t_offset]);
|
||
|
||
if ((n < 2))
|
||
{
|
||
return;
|
||
}
|
||
|
||
{
|
||
for (j = 2; j <= n; j++)
|
||
{
|
||
temp = (-(b[((j - 1) - (1)) + _b_offset]));
|
||
daxpy(((n - j) + 1), temp, t, (j - (1)) + ((j - 1)
|
||
- (1)) * (ldt) + _t_offset, 1, b, (j - (1)) + _b_offset, 1);
|
||
b[(j - (1)) + _b_offset] = (b[(j - (1)) + _b_offset] / t[(j - (1))
|
||
+ (j - (1)) * (ldt) + _t_offset]);
|
||
}
|
||
}
|
||
return;
|
||
|
||
//
|
||
// solve t*x=b for t upper triangular.
|
||
//
|
||
L50:
|
||
|
||
b[(n - (1)) + _b_offset] = (b[(n - (1)) + _b_offset]
|
||
/ t[(n - (1)) + (n - (1)) * (ldt) + _t_offset]);
|
||
|
||
if ((n < 2))
|
||
{
|
||
return;
|
||
}
|
||
|
||
{
|
||
for (jj = 2; jj <= n; jj++)
|
||
{
|
||
j = ((n - jj) + 1);
|
||
temp = (-(b[((j + 1) - (1)) + _b_offset]));
|
||
daxpy(j, temp,
|
||
t, (1 - (1)) + ((j + 1) - (1)) * (ldt) + _t_offset, 1,
|
||
b, (1 - (1)) + _b_offset, 1);
|
||
|
||
b[(j - (1)) + _b_offset] = (b[(j - (1)) + _b_offset]
|
||
/ t[(j - (1)) + (j - (1)) * (ldt) + _t_offset]);
|
||
}
|
||
}
|
||
|
||
return;
|
||
//
|
||
// solve trans(t)*x=b for t lower triangular.
|
||
//
|
||
L80:
|
||
b[(n - (1)) + _b_offset] = (b[(n - (1)) + _b_offset]
|
||
/ t[(n - (1)) + (n - (1)) * (ldt) + _t_offset]);
|
||
|
||
if ((n < 2))
|
||
{
|
||
return;
|
||
}
|
||
|
||
{
|
||
for (jj = 2; jj <= n; jj++)
|
||
{
|
||
j = ((n - jj) + 1);
|
||
b[(j - (1)) + _b_offset] = (b[(j - (1)) + _b_offset]
|
||
- ddot((jj - 1), t, ((j + 1) - (1)) + (j - (1)) * (ldt) + _t_offset,
|
||
1, b, ((j + 1) - (1)) + _b_offset, 1));
|
||
|
||
b[(j - (1)) + _b_offset] = (b[(j - (1)) + _b_offset] / t[(j - (1))
|
||
+ (j - (1)) * (ldt) + _t_offset]);
|
||
}
|
||
}
|
||
return;
|
||
|
||
//
|
||
// solve trans(t)*x=b for t upper triangular.
|
||
//
|
||
L110:
|
||
b[(1 - (1)) + _b_offset] = (b[(1 - (1)) + _b_offset]
|
||
/ t[(1 - (1)) + (1 - (1)) * (ldt) + _t_offset]);
|
||
|
||
if ((n < 2))
|
||
{
|
||
return;
|
||
}
|
||
|
||
{
|
||
for (j = 2; j <= n; j++)
|
||
{
|
||
b[(j - (1)) + _b_offset] = (b[(j - (1)) + _b_offset]
|
||
- ddot((j - 1), t, (1 - (1)) + (j - (1)) * (ldt) + _t_offset,
|
||
1, b, (1 - (1)) + _b_offset, 1));
|
||
|
||
b[(j - (1)) + _b_offset] = (b[(j - (1)) + _b_offset]
|
||
/ t[(j - (1)) + (j - (1)) * (ldt) + _t_offset]);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// c======================= The end of active =============================
|
||
//
|
||
//
|
||
//
|
||
// c ************
|
||
// c
|
||
// c Subroutine bmv
|
||
// c
|
||
// c This subroutine computes the product of the 2m x 2m middle matrix
|
||
// c in the compact L-BFGS formula of B and a 2m vector v;
|
||
// c it returns the product in p.
|
||
// c
|
||
// c m is an integer variable.
|
||
// c On entry m is the maximum number of variable metric corrections
|
||
|
||
// c used to define the limited memory matrix.
|
||
// c On exit m is unchanged.
|
||
// c
|
||
// c sy is a double precision array of dimension m x m.
|
||
// c On entry sy specifies the matrix S'Y.
|
||
// c On exit sy is unchanged.
|
||
// c
|
||
// c wt is a double precision array of dimension m x m.
|
||
// c On entry wt specifies the upper triangular matrix J' which is
|
||
// c the Cholesky factor of (thetaS'S+LD^(-1)L').
|
||
// c On exit wt is unchanged.
|
||
// c
|
||
// c col is an integer variable.
|
||
// c On entry col specifies the number of s-vectors (or y-vectors)
|
||
// c stored in the compact L-BFGS formula.
|
||
// c On exit col is unchanged.
|
||
// c
|
||
// c v is a double precision array of dimension 2col.
|
||
// c On entry v specifies vector v.
|
||
// c On exit v is unchanged.
|
||
// c
|
||
// c p is a double precision array of dimension 2col.
|
||
// c On entry p is unspecified.
|
||
// c On exit p is the product Mv.
|
||
// c
|
||
// c info is an integer variable.
|
||
// c On entry info is unspecified.
|
||
// c On exit info = 0 for normal return,
|
||
// c = nonzero for abnormal return when the system
|
||
// c to be solved by dtrsl is singular.
|
||
// c
|
||
// c Subprograms called:
|
||
// c
|
||
// c Linpack ...
|
||
// c
|
||
// c
|
||
// c * * *
|
||
// c
|
||
// c NEOS, November 1994. (Latest revision June 1996.)
|
||
// c Optimization Technology Center.
|
||
// c Argonne National Laboratory and Northwestern University.
|
||
// c Written by
|
||
// c Ciyou Zhu
|
||
// c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
|
||
// c
|
||
// c
|
||
// c ************
|
||
//
|
||
//
|
||
private static void bmv(int m, double[] sy, int _sy_offset, double[] wt, int _wt_offset,
|
||
int col, double[] v, int _v_offset, double[] p, int _p_offset, ref int info)
|
||
{
|
||
|
||
int i = 0;
|
||
int k = 0;
|
||
int i2 = 0;
|
||
double sum = 0.0d;
|
||
|
||
if ((col == 0))
|
||
return;
|
||
|
||
//
|
||
// PART I: solve [ D^(1/2) O ] [ p1 ] = [ v1 ]
|
||
// [ -L*D^(-1/2) J ] [ p2 ] [ v2 ].
|
||
//
|
||
// solve Jp2=v2+LD^(-1)v1.
|
||
//
|
||
p[((col + 1) - (1)) + _p_offset] = v[((col + 1) - (1)) + _v_offset];
|
||
{
|
||
for (i = 2; i <= col; i++)
|
||
{
|
||
i2 = (col + i);
|
||
sum = 0.0e0;
|
||
{
|
||
for (k = 1; k <= (i - 1); k++)
|
||
{
|
||
sum = (sum + ((sy[(i - (1)) + (k - (1)) * (m)
|
||
+ _sy_offset] * v[(k - (1)) + _v_offset]) / sy[(k - (1))
|
||
+ (k - (1)) * (m) + _sy_offset]));
|
||
}
|
||
}
|
||
|
||
p[(i2 - (1)) + _p_offset] = (v[(i2 - (1)) + _v_offset] + sum);
|
||
}
|
||
}
|
||
|
||
// Solve the triangular system
|
||
dtrsl(wt, _wt_offset, m, col, p,
|
||
((col + 1) - (1)) + _p_offset, 11, ref info);
|
||
|
||
//
|
||
// solve D^(1/2)p1=v1.
|
||
{
|
||
for (i = 1; i <= col; i++)
|
||
{
|
||
p[(i - (1)) + _p_offset] = (v[(i - (1)) + _v_offset]
|
||
/ System.Math.Sqrt(sy[(i - (1)) + (i - (1)) * (m) + _sy_offset]));
|
||
}
|
||
}
|
||
|
||
//
|
||
// PART II: solve [ -D^(1/2) D^(-1/2)*L' ] [ p1 ] = [ p1 ]
|
||
// [ 0 J' ] [ p2 ] [ p2 ].
|
||
//
|
||
// solve J^Tp2=p2.
|
||
//
|
||
dtrsl(wt, _wt_offset, m, col,
|
||
p, ((col + 1) - (1)) + _p_offset, 01, ref info);
|
||
|
||
//
|
||
// compute p1 = -D^(-1/2)(p1-D^(-1/2)L'p2)
|
||
// = -D^(-1/2)p1+D^(-1)L'p2.
|
||
{
|
||
for (i = 1; i <= col; i++)
|
||
{
|
||
p[(i - (1)) + _p_offset] = (-((p[(i - (1)) + _p_offset]
|
||
/ System.Math.Sqrt(sy[(i - (1)) + (i - (1)) * (m) + _sy_offset]))));
|
||
}
|
||
}
|
||
|
||
{
|
||
for (i = 1; i <= col; i++)
|
||
{
|
||
sum = 0.0e0;
|
||
{
|
||
for (k = (i + 1); k <= col; k++)
|
||
{
|
||
sum = (sum + ((sy[(k - (1)) + (i - (1)) * (m) + _sy_offset]
|
||
* p[((col + k) - (1)) + _p_offset]) / sy[(i - (1)) + (i - (1)) * (m) + _sy_offset]));
|
||
}
|
||
}
|
||
p[(i - (1)) + _p_offset] = (p[(i - (1)) + _p_offset] + sum);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// c======================== The end of bmv ===============================
|
||
//
|
||
//
|
||
// c ************
|
||
// c
|
||
// c Subroutine cauchy
|
||
// c
|
||
// c For given x, l, u, g (with sbgnrm > 0), and a limited memory
|
||
// c BFGS matrix B defined in terms of matrices WY, WS, WT, and
|
||
// c scalars head, col, and theta, this subroutine computes the
|
||
// c generalized Cauchy point (GCP), defined as the first local
|
||
// c minimizer of the quadratic
|
||
// c
|
||
// c Q(x + s) = g's + 1/2 s'Bs
|
||
// c
|
||
// c along the projected gradient direction P(x-tg,l,u).
|
||
// c The routine returns the GCP in xcp.
|
||
// c
|
||
// c n is an integer variable.
|
||
// c On entry n is the dimension of the problem.
|
||
// c On exit n is unchanged.
|
||
// c
|
||
// c x is a double precision array of dimension n.
|
||
// c On entry x is the starting point for the GCP computation.
|
||
// c On exit x is unchanged.
|
||
// c
|
||
// c l is a double precision array of dimension n.
|
||
// c On entry l is the lower bound of x.
|
||
// c On exit l is unchanged.
|
||
// c
|
||
// c u is a double precision array of dimension n.
|
||
// c On entry u is the upper bound of x.
|
||
// c On exit u is unchanged.
|
||
// c
|
||
// c nbd is an integer array of dimension n.
|
||
// c On entry nbd represents the type of bounds imposed on the
|
||
// c variables, and must be specified as follows:
|
||
// c nbd(i)=0 if x(i) is unbounded,
|
||
// c 1 if x(i) has only a lower bound,
|
||
// c 2 if x(i) has both lower and upper bounds, and
|
||
// c 3 if x(i) has only an upper bound.
|
||
// c On exit nbd is unchanged.
|
||
// c
|
||
// c g is a double precision array of dimension n.
|
||
// c On entry g is the gradient of f(x). g must be a nonzero vector.
|
||
// c On exit g is unchanged.
|
||
// c
|
||
// c iorder is an integer working array of dimension n.
|
||
// c iorder will be used to store the breakpoints in the piecewise
|
||
// c linear path and free variables encountered. On exit,
|
||
// c iorder(1),...,iorder(nleft) are indices of breakpoints
|
||
// c which have not been encountered;
|
||
// c iorder(nleft+1),...,iorder(nbreak) are indices of
|
||
// c encountered breakpoints; and
|
||
// c iorder(nfree),...,iorder(n) are indices of variables which
|
||
// c have no bound constraits along the search direction.
|
||
// c
|
||
// c iwhere is an integer array of dimension n.
|
||
// c On entry iwhere indicates only the permanently fixed (iwhere=3)
|
||
|
||
// c or free (iwhere= -1) components of x.
|
||
// c On exit iwhere records the status of the current x variables.
|
||
// c iwhere(i)=-3 if x(i) is free and has bounds, but is not moved
|
||
// c 0 if x(i) is free and has bounds, and is moved
|
||
// c 1 if x(i) is fixed at l(i), and l(i) .ne. u(i)
|
||
// c 2 if x(i) is fixed at u(i), and u(i) .ne. l(i)
|
||
// c 3 if x(i) is always fixed, i.e., u(i)=x(i)=l(i)
|
||
// c -1 if x(i) is always free, i.e., it has no bounds.
|
||
// c
|
||
// c t is a double precision working array of dimension n.
|
||
// c t will be used to store the break points.
|
||
// c
|
||
// c d is a double precision array of dimension n used to store
|
||
// c the Cauchy direction P(x-tg)-x.
|
||
// c
|
||
// c xcp is a double precision array of dimension n used to return the
|
||
|
||
// c GCP on exit.
|
||
// c
|
||
// c m is an integer variable.
|
||
// c On entry m is the maximum number of variable metric corrections
|
||
// c used to define the limited memory matrix.
|
||
// c On exit m is unchanged.
|
||
// c
|
||
// c ws, wy, sy, and wt are double precision arrays.
|
||
// c On entry they store information that defines the
|
||
// c limited memory BFGS matrix:
|
||
// c ws(n,m) stores S, a set of s-vectors;
|
||
// c wy(n,m) stores Y, a set of y-vectors;
|
||
// c sy(m,m) stores S'Y;
|
||
// c wt(m,m) stores the
|
||
// c Cholesky factorization of (theta*S'S+LD^(-1)L').
|
||
// c On exit these arrays are unchanged.
|
||
// c
|
||
// c theta is a double precision variable.
|
||
// c On entry theta is the scaling factor specifying B_0 = theta I.
|
||
// c On exit theta is unchanged.
|
||
// c
|
||
// c col is an integer variable.
|
||
// c On entry col is the actual number of variable metric
|
||
// c corrections stored so far.
|
||
// c On exit col is unchanged.
|
||
// c
|
||
// c head is an integer variable.
|
||
// c On entry head is the location of the first s-vector (or y-vector
|
||
// c in S (or Y).
|
||
// c On exit col is unchanged.
|
||
// c
|
||
// c p is a double precision working array of dimension 2m.
|
||
// c p will be used to store the vector p = W^(T)d.
|
||
// c
|
||
// c c is a double precision working array of dimension 2m.
|
||
// c c will be used to store the vector c = W^(T)(xcp-x).
|
||
// c
|
||
// c wbp is a double precision working array of dimension 2m.
|
||
// c wbp will be used to store the row of W corresponding
|
||
// c to a breakpoint.
|
||
// c
|
||
// c v is a double precision working array of dimension 2m.
|
||
// c
|
||
// c nseg is an integer variable.
|
||
// c On exit nseg records the number of quadratic segments explored
|
||
// c in searching for the GCP.
|
||
// c
|
||
// c sg and yg are double precision arrays of dimension m.
|
||
// c On entry sg and yg store S'g and Y'g correspondingly.
|
||
// c On exit they are unchanged.
|
||
// c
|
||
// c iprint is an INTEGER variable that must be set by the user.
|
||
// c It controls the frequency and type of output generated:
|
||
// c iprint<0 no output is generated;
|
||
// c iprint=0 print only one line at the last iteration;
|
||
// c 0<iprint<99 print also f and |proj g| every iprint iterations;
|
||
|
||
// c iprint=99 print details of every iteration except n-vectors;
|
||
|
||
// c iprint=100 print also the changes of active set and final x;
|
||
// c iprint>100 print details of every iteration including x and g;
|
||
// c When iprint > 0, the file iterate.dat will be created to
|
||
// c summarize the iteration.
|
||
// c
|
||
// c sbgnrm is a double precision variable.
|
||
// c On entry sbgnrm is the norm of the projected gradient at x.
|
||
// c On exit sbgnrm is unchanged.
|
||
// c
|
||
// c info is an integer variable.
|
||
// c On entry info is 0.
|
||
// c On exit info = 0 for normal return,
|
||
// c = nonzero for abnormal return when the the system
|
||
// c used in routine bmv is singular.
|
||
// c
|
||
// c Subprograms called:
|
||
// c
|
||
// c L-BFGS-B Library ... hpsolb, bmv.
|
||
// c
|
||
// c Linpack ... dscal dcopy,
|
||
// c
|
||
// c
|
||
// c References:
|
||
// c
|
||
// c [1] R. H. Byrd, P. Lu, J. Nocedal and C. Zhu, ``A limited
|
||
// c memory algorithm for bound constrained optimization'',
|
||
// c SIAM J. Scientific Computing 16 (1995), no. 5, pp. 1190--1208.
|
||
// c
|
||
// c [2] C. Zhu, R.H. Byrd, P. Lu, J. Nocedal, ``L-BFGS-B: FORTRAN
|
||
// c Subroutines for Large Scale Bound Constrained Optimization''
|
||
// c Tech. Report, NAM-11, EECS Department, Northwestern University,
|
||
|
||
// c 1994.
|
||
// c
|
||
// c (Postscript files of these papers are available via anonymous
|
||
// c ftp to eecs.nwu.edu in the directory pub/lbfgs/lbfgs_bcm.)
|
||
// c
|
||
// c * * *
|
||
// c
|
||
// c NEOS, November 1994. (Latest revision June 1996.)
|
||
// c Optimization Technology Center.
|
||
// c Argonne National Laboratory and Northwestern University.
|
||
// c Written by
|
||
// c Ciyou Zhu
|
||
// c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
|
||
// c
|
||
// c
|
||
// c ************
|
||
//
|
||
//
|
||
// c Check the status of the variables, reset iwhere(i) if necessary;
|
||
// c compute the Cauchy direction d and the breakpoints t; initialize
|
||
// c the derivative f1 and the vector p = W'd (for theta = 1).
|
||
//
|
||
private static void cauchy(int n, double[] x, int _x_offset, double[] l, int _l_offset,
|
||
double[] u, int _u_offset, int[] nbd, int _nbd_offset, double[] g, int _g_offset,
|
||
int[] iorder, int _iorder_offset, int[] iwhere, int _iwhere_offset, double[] t, int _t_offset,
|
||
double[] d, int _d_offset, double[] xcp, int _xcp_offset, int m,
|
||
double[] wy, int _wy_offset, double[] ws, int _ws_offset, double[] sy, int _sy_offset,
|
||
double[] wt, int _wt_offset, double theta, int col,
|
||
int head, double[] p, int _p_offset, double[] c, int _c_offset,
|
||
double[] wbp, int _wbp_offset, double[] v, int _v_offset, ref int nseg,
|
||
int iprint, double sbgnrm, ref int info, double epsmch)
|
||
{
|
||
|
||
bool xlower = false;
|
||
bool xupper = false;
|
||
bool bnded = false;
|
||
int i = 0;
|
||
int j = 0;
|
||
int col2 = 0;
|
||
int nfree = 0;
|
||
int nbreak = 0;
|
||
int pointr = 0;
|
||
int ibp = 0;
|
||
int nleft = 0;
|
||
int ibkmin = 0;
|
||
int iter = 0;
|
||
double f1 = 0.0d;
|
||
double f2 = 0.0d;
|
||
double dt = 0.0d;
|
||
double dtm = 0.0d;
|
||
double tsum = 0.0d;
|
||
double dibp = 0.0d;
|
||
double zibp = 0.0d;
|
||
double dibp2 = 0.0d;
|
||
double bkmin = 0.0d;
|
||
double tu = 0.0d;
|
||
double tl = 0.0d;
|
||
double wmc = 0.0d;
|
||
double wmp = 0.0d;
|
||
double wmw = 0.0d;
|
||
double tj = 0.0d;
|
||
double tj0 = 0.0d;
|
||
double neggi = 0.0d;
|
||
double f2_org = 0.0d;
|
||
|
||
if ((sbgnrm <= 0.0))
|
||
{
|
||
if ((iprint >= 0))
|
||
{
|
||
// DISPLAY: Subgnorm = 0. GCP = X.
|
||
}
|
||
|
||
dcopy(n, x, _x_offset, 1, xcp, _xcp_offset, 1);
|
||
return;
|
||
}
|
||
|
||
bnded = true;
|
||
nfree = (n + 1);
|
||
nbreak = 0;
|
||
ibkmin = 0;
|
||
bkmin = 0.0;
|
||
col2 = (2 * col);
|
||
f1 = 0.0;
|
||
if ((iprint >= 99))
|
||
{
|
||
// DISPLAY: '---------------- CAUCHY entered-------------------'
|
||
}
|
||
//
|
||
// c We set p to zero and build it up as we determine d.
|
||
//
|
||
{
|
||
for (i = 1; i <= col2; i++)
|
||
{
|
||
p[(i - (1)) + _p_offset] = 0.0;
|
||
}
|
||
}
|
||
//
|
||
// c In the following loop we determine for each variable its bound
|
||
// c status and its breakpoint, and update p accordingly.
|
||
// c Smallest breakpoint is identified.
|
||
//
|
||
{
|
||
for (i = 1; i <= n; i++)
|
||
{
|
||
neggi = (-(g[(i - (1)) + _g_offset]));
|
||
|
||
if (((iwhere[(i - (1)) + _iwhere_offset] != 3)
|
||
&& (iwhere[(i - (1)) + _iwhere_offset] != -1)))
|
||
{
|
||
// c if x(i) is not a constant and has bounds,
|
||
// c compute the difference between x(i) and its bounds.
|
||
if ((nbd[(i - (1)) + _nbd_offset] <= 2))
|
||
{
|
||
tl = (x[(i - (1)) + _x_offset] - l[(i - (1)) + _l_offset]);
|
||
}
|
||
if ((nbd[(i - (1)) + _nbd_offset] >= 2))
|
||
{
|
||
tu = (u[(i - (1)) + _u_offset] - x[(i - (1)) + _x_offset]);
|
||
}
|
||
//
|
||
// c If a variable is close enough to a bound
|
||
// c we treat it as at bound.
|
||
xlower = ((nbd[(i - (1)) + _nbd_offset] <= 2) && (tl <= 0.0));
|
||
xupper = ((nbd[(i - (1)) + _nbd_offset] >= 2) && (tu <= 0.0));
|
||
//
|
||
// c reset iwhere(i).
|
||
iwhere[(i - (1)) + _iwhere_offset] = 0;
|
||
if (xlower)
|
||
{
|
||
if ((neggi <= 0.0))
|
||
{
|
||
iwhere[(i - (1)) + _iwhere_offset] = 1;
|
||
}
|
||
}
|
||
else if (xupper)
|
||
{
|
||
if ((neggi >= 0.0))
|
||
{
|
||
iwhere[(i - (1)) + _iwhere_offset] = 2;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ((System.Math.Abs(neggi) <= 0.0))
|
||
{
|
||
iwhere[(i - (1)) + _iwhere_offset] = -3;
|
||
}
|
||
}
|
||
}
|
||
pointr = head;
|
||
if (((iwhere[(i - (1)) + _iwhere_offset] != 0) && (iwhere[(i - (1)) + _iwhere_offset] != -1)))
|
||
{
|
||
d[(i - (1)) + _d_offset] = 0.0;
|
||
}
|
||
else
|
||
{
|
||
d[(i - (1)) + _d_offset] = neggi;
|
||
f1 = (f1 - (neggi * neggi));
|
||
|
||
// calculate p := p - W'e_i* (g_i).
|
||
{
|
||
for (j = 1; j <= col; j++)
|
||
{
|
||
p[(j - (1)) + _p_offset] = (p[(j - (1))
|
||
+ _p_offset] + (wy[(i - (1)) + (pointr - (1)) * (n) + _wy_offset] * neggi));
|
||
p[((col + j) - (1)) + _p_offset] = (p[((col + j) - (1))
|
||
+ _p_offset] + (ws[(i - (1)) + (pointr - (1)) * (n) + _ws_offset] * neggi));
|
||
pointr = ((pointr) % (m) + 1);
|
||
}
|
||
}
|
||
if ((((nbd[(i - (1)) + _nbd_offset] <= 2)
|
||
&& (nbd[(i - (1)) + _nbd_offset] != 0)) && (neggi < 0.0)))
|
||
{
|
||
// x(i) + d(i) is bounded; compute t(i).
|
||
|
||
nbreak = (nbreak + 1);
|
||
iorder[(nbreak - (1)) + _iorder_offset] = i;
|
||
t[(nbreak - (1)) + _t_offset] = (tl / ((-(neggi))));
|
||
if (((nbreak == 1) || (t[(nbreak - (1)) + _t_offset] < bkmin)))
|
||
{
|
||
bkmin = t[(nbreak - (1)) + _t_offset];
|
||
ibkmin = nbreak;
|
||
}
|
||
}
|
||
else if (((nbd[(i - (1)) + _nbd_offset] >= 2) && (neggi > 0.0)))
|
||
{
|
||
// x(i) + d(i) is bounded; compute t(i).
|
||
|
||
nbreak = (nbreak + 1);
|
||
iorder[(nbreak - (1)) + _iorder_offset] = i;
|
||
t[(nbreak - (1)) + _t_offset] = (tu / neggi);
|
||
if (((nbreak == 1) || (t[(nbreak - (1)) + _t_offset] < bkmin)))
|
||
{
|
||
bkmin = t[(nbreak - (1)) + _t_offset];
|
||
ibkmin = nbreak;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// x(i) + d(i) is not bounded.
|
||
nfree = (nfree - 1);
|
||
iorder[(nfree - (1)) + _iorder_offset] = i;
|
||
if ((System.Math.Abs(neggi) > 0.0))
|
||
{
|
||
bnded = false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
//
|
||
// The indices of the nonzero components of d are now stored
|
||
// in iorder(1),...,iorder(nbreak) and iorder(nfree),...,iorder(n).
|
||
// The smallest of the nbreak breakpoints is in t(ibkmin)=bkmin.
|
||
//
|
||
if ((theta != 1.0))
|
||
{
|
||
// complete the initialization of p for theta not= one.
|
||
dscal(col, theta, p, ((col + 1) - (1)) + _p_offset, 1);
|
||
}
|
||
|
||
//
|
||
// c Initialize GCP xcp = x.
|
||
//
|
||
dcopy(n, x, _x_offset, 1, xcp, _xcp_offset, 1);
|
||
|
||
if (((nbreak == 0) && (nfree == (n + 1))))
|
||
{
|
||
// is a zero vector, return with the initial xcp as GCP.
|
||
return;
|
||
}
|
||
|
||
//
|
||
// c Initialize c = W'(xcp - x) = 0.
|
||
//
|
||
{
|
||
for (j = 1; j <= col2; j++)
|
||
{
|
||
c[(j - (1)) + _c_offset] = 0.0;
|
||
}
|
||
}
|
||
|
||
//
|
||
// c Initialize derivative f2.
|
||
//
|
||
f2 = (-((theta * f1)));
|
||
f2_org = f2;
|
||
if ((col > 0))
|
||
{
|
||
bmv(m, sy, _sy_offset, wt, _wt_offset,
|
||
col, p, _p_offset, v, _v_offset, ref info);
|
||
|
||
f2 = (f2 - BFGS.ddot(col2, v, _v_offset, 1, p, _p_offset, 1));
|
||
}
|
||
|
||
dtm = (-((f1 / f2)));
|
||
tsum = 0.0;
|
||
nseg = 1;
|
||
|
||
if ((iprint >= 99))
|
||
{
|
||
// DISPLAY: "There are " + nbreak + " breakpoints "
|
||
}
|
||
|
||
//
|
||
// c If there are no breakpoints, locate the GCP and return.
|
||
//
|
||
if ((nbreak == 0))
|
||
goto L888;
|
||
|
||
nleft = nbreak;
|
||
iter = 1;
|
||
tj = 0.0;
|
||
|
||
//
|
||
// c------------------- the beginning of the loop -------------------------
|
||
//
|
||
L777:
|
||
//
|
||
// Find the next smallest breakpoint;
|
||
// compute dt = t(nleft) - t(nleft + 1).
|
||
//
|
||
tj0 = tj;
|
||
|
||
if ((iter == 1))
|
||
{
|
||
// Since we already have the smallest breakpoint we need not do
|
||
// heapsort yet. Often only one breakpoint is used and the
|
||
// cost of heapsort is avoided.
|
||
tj = bkmin;
|
||
ibp = iorder[(ibkmin - (1)) + _iorder_offset];
|
||
}
|
||
else
|
||
{
|
||
if ((iter == 2))
|
||
{
|
||
// Replace the already used smallest breakpoint with the
|
||
// breakpoint numbered nbreak > nlast, before heapsort call.
|
||
|
||
if ((ibkmin != nbreak))
|
||
{
|
||
t[(ibkmin - (1)) + _t_offset] = t[(nbreak - (1)) + _t_offset];
|
||
iorder[(ibkmin - (1)) + _iorder_offset] = iorder[(nbreak - (1)) + _iorder_offset];
|
||
}
|
||
// Update heap structure of breakpoints
|
||
// (if iter=2, initialize heap).
|
||
}
|
||
hpsolb(nleft, t, _t_offset, iorder, _iorder_offset, (iter - 2));
|
||
tj = t[(nleft - (1)) + _t_offset];
|
||
ibp = iorder[(nleft - (1)) + _iorder_offset];
|
||
}
|
||
//
|
||
dt = (tj - tj0);
|
||
//
|
||
if (((dt != 0.0) && (iprint >= 100)))
|
||
{
|
||
// DISPLAY: nseg, f1, f2
|
||
// "/,'Piece ',i3,' --f1, f2 at start point ',1p,2(1x,d11.4)"
|
||
//
|
||
// DISPLAY: dt,
|
||
// "'Distance to the next break point = ',1p,d11.4"
|
||
//
|
||
// DISPLAY: dtm,
|
||
// "'Distance to the stationary point = ',1p,d11.4"
|
||
}
|
||
|
||
//
|
||
// If a minimizer is within this interval, locate the GCP and return.
|
||
//
|
||
if ((dtm < dt))
|
||
goto L888;
|
||
|
||
//
|
||
// Otherwise fix one variable and
|
||
// reset the corresponding component of d to zero.
|
||
//
|
||
tsum = (tsum + dt);
|
||
nleft = (nleft - 1);
|
||
iter = (iter + 1);
|
||
dibp = d[(ibp - (1)) + _d_offset];
|
||
d[(ibp - (1)) + _d_offset] = 0.0;
|
||
|
||
if ((dibp > 0.0))
|
||
{
|
||
zibp = (u[(ibp - (1)) + _u_offset] - x[(ibp - (1)) + _x_offset]);
|
||
xcp[(ibp - (1)) + _xcp_offset] = u[(ibp - (1)) + _u_offset];
|
||
iwhere[(ibp - (1)) + _iwhere_offset] = 2;
|
||
}
|
||
else
|
||
{
|
||
zibp = (l[(ibp - (1)) + _l_offset] - x[(ibp - (1)) + _x_offset]);
|
||
xcp[(ibp - (1)) + _xcp_offset] = l[(ibp - (1)) + _l_offset];
|
||
iwhere[(ibp - (1)) + _iwhere_offset] = 1;
|
||
}
|
||
|
||
if ((iprint >= 100))
|
||
{
|
||
// DISPLAY: "Variable " + ibp + " is fixed."
|
||
}
|
||
|
||
if (((nleft == 0) && (nbreak == n)))
|
||
{
|
||
// all n variables are fixed,
|
||
// return with xcp as GCP.
|
||
dtm = dt;
|
||
goto L999;
|
||
}
|
||
|
||
//
|
||
// Update the derivative information.
|
||
//
|
||
nseg = (nseg + 1);
|
||
dibp2 = (System.Math.Pow(dibp, 2));
|
||
|
||
//
|
||
// Update f1 and f2.
|
||
//
|
||
// temporarily set f1 and f2 for col=0.
|
||
//
|
||
f1 = (((f1 + (dt * f2)) + dibp2) - ((theta * dibp) * zibp));
|
||
f2 = (f2 - (theta * dibp2));
|
||
//
|
||
if ((col > 0))
|
||
{
|
||
// update c = c + dt*p.
|
||
daxpy(col2, dt, p, _p_offset, 1, c, _c_offset, 1);
|
||
|
||
// choose wbp,
|
||
// the row of W corresponding to the breakpoint encountered.
|
||
pointr = head;
|
||
{
|
||
for (j = 1; j <= col; j++)
|
||
{
|
||
wbp[(j - (1)) + _wbp_offset] = wy[(ibp - (1))
|
||
+ (pointr - (1)) * (n) + _wy_offset];
|
||
|
||
wbp[((col + j) - (1)) + _wbp_offset] = (theta * ws[(ibp
|
||
- (1)) + (pointr - (1)) * (n) + _ws_offset]);
|
||
|
||
pointr = ((pointr) % (m) + 1);
|
||
}
|
||
}
|
||
|
||
// compute (wbp)Mc, (wbp)Mp, and (wbp)M(wbp)'.
|
||
bmv(m, sy, _sy_offset, wt, _wt_offset, col, wbp,
|
||
_wbp_offset, v, _v_offset, ref info);
|
||
|
||
wmc = ddot(col2, c, _c_offset, 1, v, _v_offset, 1);
|
||
wmp = ddot(col2, p, _p_offset, 1, v, _v_offset, 1);
|
||
wmw = ddot(col2, wbp, _wbp_offset, 1, v, _v_offset, 1);
|
||
|
||
// update p = p - dibp*wbp.
|
||
daxpy(col2, (-(dibp)), wbp, _wbp_offset, 1, p, _p_offset, 1);
|
||
|
||
// complete updating f1 and f2 while col > 0.
|
||
f1 = (f1 + (dibp * wmc));
|
||
f2 = ((f2 + ((2.0e0 * dibp) * wmp)) - (dibp2 * wmw));
|
||
}
|
||
|
||
|
||
f2 = System.Math.Max((epsmch * f2_org), f2);
|
||
|
||
if ((nleft > 0))
|
||
{
|
||
dtm = (-((f1 / f2)));
|
||
goto L777;
|
||
// to repeat the loop for unsearched intervals.
|
||
}
|
||
else if (bnded)
|
||
{
|
||
f1 = 0.0;
|
||
f2 = 0.0;
|
||
dtm = 0.0;
|
||
}
|
||
else
|
||
{
|
||
dtm = (-((f1 / f2)));
|
||
}
|
||
|
||
//
|
||
// c------------------- the end of the loop -------------------------------
|
||
//
|
||
L888:
|
||
|
||
if ((iprint >= 99))
|
||
{
|
||
// DISPLAY: "GCP found in this segment",
|
||
//
|
||
// DISPLAY: nseg, f1, f2
|
||
// 'Piece ',i3,' --f1, f2 at start point ',1p,2(1x,d11.4)"
|
||
// dtm
|
||
// "'Distance to the stationary point = ',1p,d11.4"
|
||
}
|
||
if ((dtm <= 0.0))
|
||
{
|
||
dtm = 0.0;
|
||
}
|
||
tsum = (tsum + dtm);
|
||
|
||
//
|
||
// Move free variables (i.e., the ones w/o breakpoints) and
|
||
// the variables whose breakpoints haven't been reached.
|
||
//
|
||
daxpy(n, tsum, d, _d_offset, 1, xcp, _xcp_offset, 1);
|
||
//
|
||
L999:
|
||
//
|
||
// Update c = c + dtm*p = W'(x^c - x)
|
||
// which will be used in computing r = Z'(B(x^c - x) + g).
|
||
//
|
||
if ((col > 0))
|
||
{
|
||
daxpy(col2, dtm, p, _p_offset, 1, c, _c_offset, 1);
|
||
}
|
||
|
||
|
||
if ((iprint > 100))
|
||
{
|
||
for (i = 1; i <= n; i++)
|
||
{
|
||
// DISPLAY: xcp[(i - (1)) + _xcp_offset];
|
||
}
|
||
// DISPLAY: "'Cauchy X = ',/,(4x,1p,6(1x,d11.4))"
|
||
}
|
||
|
||
if ((iprint >= 99))
|
||
{
|
||
// DISPLAY: '---------------- exit CAUCHY----------------------'
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// c====================== The end of cauchy ==============================
|
||
//
|
||
//
|
||
//
|
||
// c ************
|
||
// c
|
||
// c Subroutine cmprlb
|
||
// c
|
||
// c This subroutine computes r=-Z'B(xcp-xk)-Z'g by using
|
||
// c wa(2m+1)=W'(xcp-x) from subroutine cauchy.
|
||
// c
|
||
// c Subprograms called:
|
||
// c
|
||
// c L-BFGS-B Library ... bmv.
|
||
// c
|
||
// c
|
||
// c * * *
|
||
// c
|
||
// c NEOS, November 1994. (Latest revision June 1996.)
|
||
// c Optimization Technology Center.
|
||
// c Argonne National Laboratory and Northwestern University.
|
||
// c Written by
|
||
// c Ciyou Zhu
|
||
// c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
|
||
// c
|
||
// c
|
||
// c ************
|
||
//
|
||
//
|
||
private static void cmprlb(int n, int m, double[] x, int _x_offset, double[] g, int _g_offset, double[] ws, int _ws_offset, double[] wy, int _wy_offset, double[] sy, int _sy_offset,
|
||
double[] wt, int _wt_offset, double[] z, int _z_offset, double[] r, int _r_offset,
|
||
double[] wa, int _wa_offset, int[] index, int _index_offset, double theta,
|
||
int col, int head, int nfree, bool cnstnd, ref int info)
|
||
{
|
||
|
||
int i = 0;
|
||
int j = 0;
|
||
int k = 0;
|
||
int pointr = 0;
|
||
double a1 = 0.0d;
|
||
double a2 = 0.0d;
|
||
|
||
if (((!cnstnd) && (col > 0)))
|
||
{
|
||
{
|
||
for (i = 1; i <= n; i++)
|
||
{
|
||
r[(i - (1)) + _r_offset] = (-(g[(i - (1)) + _g_offset]));
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
{
|
||
for (i = 1; i <= nfree; i++)
|
||
{
|
||
k = index[(i - (1)) + _index_offset];
|
||
r[(i - (1)) + _r_offset] = ((-((theta * ((z[(k - (1))
|
||
+ _z_offset] - x[(k - (1)) + _x_offset]))))) - g[(k - (1)) + _g_offset]);
|
||
}
|
||
}
|
||
|
||
bmv(m, sy, _sy_offset, wt, _wt_offset, col, wa,
|
||
(((2 * m) + 1) - (1)) + _wa_offset, wa, (1 - (1)) + _wa_offset, ref info);
|
||
|
||
pointr = head;
|
||
|
||
{
|
||
for (j = 1; j <= col; j++)
|
||
{
|
||
a1 = wa[(j - (1)) + _wa_offset];
|
||
a2 = (theta * wa[((col + j) - (1)) + _wa_offset]);
|
||
{
|
||
for (i = 1; i <= nfree; i++)
|
||
{
|
||
k = index[(i - (1)) + _index_offset];
|
||
r[(i - (1)) + _r_offset] = ((r[(i - (1)) + _r_offset]
|
||
+ (wy[(k - (1)) + (pointr - (1)) * (n) + _wy_offset] * a1))
|
||
+ (ws[(k - (1)) + (pointr - (1)) * (n) + _ws_offset] * a2));
|
||
}
|
||
}
|
||
|
||
pointr = ((pointr) % (m) + 1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// c====================== The end of subsm ===============================
|
||
//
|
||
// c **********
|
||
// c
|
||
// c Subroutine dcsrch
|
||
// c
|
||
// c This subroutine finds a step that satisfies a sufficient
|
||
// c decrease condition and a curvature condition.
|
||
// c
|
||
// c Each call of the subroutine updates an interval with
|
||
// c endpoints stx and sty. The interval is initially chosen
|
||
// c so that it contains a minimizer of the modified function
|
||
// c
|
||
// c psi(stp) = f(stp) - f(0) - ftol*stp*f'(0).
|
||
// c
|
||
// c If psi(stp) <= 0 and f'(stp) >= 0 for some step, then the
|
||
// c interval is chosen so that it contains a minimizer of f.
|
||
// c
|
||
// c The algorithm is designed to find a step that satisfies
|
||
// c the sufficient decrease condition
|
||
// c
|
||
// c f(stp) <= f(0) + ftol*stp*f'(0),
|
||
// c
|
||
// c and the curvature condition
|
||
// c
|
||
// c abs(f'(stp)) <= gtol*abs(f'(0)).
|
||
// c
|
||
// c If ftol is less than gtol and if, for example, the function
|
||
// c is bounded below, then there is always a step which satisfies
|
||
// c both conditions.
|
||
// c
|
||
// c If no step can be found that satisfies both conditions, then
|
||
// c the algorithm stops with a warning. In this case stp only
|
||
// c satisfies the sufficient decrease condition.
|
||
// c
|
||
// c A typical invocation of dcsrch has the following outline:
|
||
// c
|
||
// c task = 'START'
|
||
// c 10 continue
|
||
// c call dcsrch( ... )
|
||
// c if (task .eq. 'FG') then
|
||
// c Evaluate the function and the gradient at stp
|
||
// c goto 10
|
||
// c end if
|
||
// c
|
||
// c NOTE: The user must no alter work arrays between calls.
|
||
// c
|
||
// c The subroutine statement is
|
||
// c
|
||
// c subroutine dcsrch(f,g,stp,ftol,gtol,xtol,stpmin,stpmax,
|
||
// c task,isave,dsave)
|
||
// c where
|
||
// c
|
||
// c f is a double precision variable.
|
||
// c On initial entry f is the value of the function at 0.
|
||
// c On subsequent entries f is the value of the
|
||
// c function at stp.
|
||
// c On exit f is the value of the function at stp.
|
||
// c
|
||
// c g is a double precision variable.
|
||
// c On initial entry g is the derivative of the function at 0.
|
||
// c On subsequent entries g is the derivative of the
|
||
// c function at stp.
|
||
// c On exit g is the derivative of the function at stp.
|
||
// c
|
||
// c stp is a double precision variable.
|
||
// c On entry stp is the current estimate of a satisfactory
|
||
// c step. On initial entry, a positive initial estimate
|
||
// c must be provided.
|
||
// c On exit stp is the current estimate of a satisfactory step
|
||
// c if task = 'FG'. If task = 'CONV' then stp satisfies
|
||
// c the sufficient decrease and curvature condition.
|
||
// c
|
||
// c ftol is a double precision variable.
|
||
// c On entry ftol specifies a nonnegative tolerance for the
|
||
// c sufficient decrease condition.
|
||
// c On exit ftol is unchanged.
|
||
// c
|
||
// c gtol is a double precision variable.
|
||
// c On entry gtol specifies a nonnegative tolerance for the
|
||
// c curvature condition.
|
||
// c On exit gtol is unchanged.
|
||
// c
|
||
// c xtol is a double precision variable.
|
||
// c On entry xtol specifies a nonnegative relative tolerance
|
||
// c for an acceptable step. The subroutine exits with a
|
||
// c warning if the relative difference between sty and stx
|
||
// c is less than xtol.
|
||
// c On exit xtol is unchanged.
|
||
// c
|
||
// c stpmin is a double precision variable.
|
||
// c On entry stpmin is a nonnegative lower bound for the step.
|
||
// c On exit stpmin is unchanged.
|
||
// c
|
||
// c stpmax is a double precision variable.
|
||
// c On entry stpmax is a nonnegative upper bound for the step.
|
||
// c On exit stpmax is unchanged.
|
||
// c
|
||
// c task is a character variable of length at least 60.
|
||
// c On initial entry task must be set to 'START'.
|
||
// c On exit task indicates the required action:
|
||
// c
|
||
// c If task(1:2) = 'FG' then evaluate the function and
|
||
// c derivative at stp and call dcsrch again.
|
||
// c
|
||
// c If task(1:4) = 'CONV' then the search is successful.
|
||
// c
|
||
// c If task(1:4) = 'WARN' then the subroutine is not able
|
||
// c to satisfy the convergence conditions. The exit value of
|
||
// c stp contains the best point found during the search.
|
||
// c
|
||
// c If task(1:5) = 'ERROR' then there is an error in the
|
||
// c input arguments.
|
||
// c
|
||
// c On exit with convergence, a warning or an error, the
|
||
// c variable task contains additional information.
|
||
// c
|
||
// c isave is an integer work array of dimension 2.
|
||
// c
|
||
// c dsave is a double precision work array of dimension 13.
|
||
// c
|
||
// c Subprograms called
|
||
// c
|
||
// c MINPACK-2 ... dcstep
|
||
// c
|
||
// c MINPACK-1 Project. June 1983.
|
||
// c Argonne National Laboratory.
|
||
// c Jorge J. More' and David J. Thuente.
|
||
// c
|
||
// c MINPACK-2 Project. October 1993.
|
||
// c Argonne National Laboratory and University of Minnesota.
|
||
// c Brett M. Averick, Richard G. Carter, and Jorge J. More'.
|
||
// c
|
||
// c **********
|
||
//
|
||
//
|
||
// c Initialization block.
|
||
//
|
||
private static void dcsrch(double f, double g, ref double stp, double ftol,
|
||
double gtol, double xtol, double stpmin, double stpmax, ref Task task,
|
||
int[] isave, int _isave_offset, double[] dsave, int _dsave_offset)
|
||
{
|
||
bool brackt = false;
|
||
int stage = 0;
|
||
double finit = 0.0d;
|
||
double ftest = 0.0d;
|
||
double fm = 0.0d;
|
||
double fx = 0.0d;
|
||
double fxm = 0.0d;
|
||
double fy = 0.0d;
|
||
double fym = 0.0d;
|
||
double ginit = 0.0d;
|
||
double gtest = 0.0d;
|
||
double gm = 0.0d;
|
||
double gx = 0.0d;
|
||
double gxm = 0.0d;
|
||
double gy = 0.0d;
|
||
double gym = 0.0d;
|
||
double stx = 0.0d;
|
||
double sty = 0.0d;
|
||
double stmin = 0.0d;
|
||
double stmax = 0.0d;
|
||
double width = 0.0d;
|
||
double width1 = 0.0d;
|
||
|
||
if (task == Task.Start)
|
||
{
|
||
//
|
||
// Initialize local variables.
|
||
//
|
||
brackt = false;
|
||
stage = 1;
|
||
finit = f;
|
||
ginit = g;
|
||
gtest = (ftol * ginit);
|
||
width = (stpmax - stpmin);
|
||
width1 = (width / 0.5);
|
||
|
||
//
|
||
// The variables stx, fx, gx contain the values of the step,
|
||
// function, and derivative at the best step.
|
||
// The variables sty, fy, gy contain the value of the step,
|
||
// function, and derivative at sty.
|
||
// The variables stp, f, g contain the values of the step,
|
||
// function, and derivative at stp.
|
||
//
|
||
stx = 0.0;
|
||
fx = finit;
|
||
gx = ginit;
|
||
sty = 0.0;
|
||
fy = finit;
|
||
gy = ginit;
|
||
stmin = 0.0;
|
||
stmax = (stp + (4.0 * stp));
|
||
task = Task.FG;
|
||
goto L1000;
|
||
}
|
||
else
|
||
{
|
||
// Restore local variables.
|
||
if ((isave[(1 - (1)) + _isave_offset] == 1))
|
||
{
|
||
brackt = true;
|
||
}
|
||
else
|
||
{
|
||
brackt = false;
|
||
}
|
||
stage = isave[(2 - (1)) + _isave_offset];
|
||
ginit = dsave[(1 - (1)) + _dsave_offset];
|
||
gtest = dsave[(2 - (1)) + _dsave_offset];
|
||
gx = dsave[(3 - (1)) + _dsave_offset];
|
||
gy = dsave[(4 - (1)) + _dsave_offset];
|
||
finit = dsave[(5 - (1)) + _dsave_offset];
|
||
fx = dsave[(6 - (1)) + _dsave_offset];
|
||
fy = dsave[(7 - (1)) + _dsave_offset];
|
||
stx = dsave[(8 - (1)) + _dsave_offset];
|
||
sty = dsave[(9 - (1)) + _dsave_offset];
|
||
stmin = dsave[(10 - (1)) + _dsave_offset];
|
||
stmax = dsave[(11 - (1)) + _dsave_offset];
|
||
width = dsave[(12 - (1)) + _dsave_offset];
|
||
width1 = dsave[(13 - (1)) + _dsave_offset];
|
||
}
|
||
|
||
//
|
||
// c If psi(stp) <= 0 and f'(stp) >= 0 for some step, then the
|
||
// c algorithm enters the second stage.
|
||
//
|
||
ftest = (finit + (stp * gtest));
|
||
if ((((stage == 1) && (f <= ftest)) && (g >= 0.0)))
|
||
{
|
||
stage = 2;
|
||
}
|
||
|
||
//
|
||
// c Test for warnings.
|
||
//
|
||
if ((brackt && (((stp <= stmin) || (stp >= stmax)))))
|
||
{
|
||
task = Task.Warning;
|
||
}
|
||
if ((brackt && ((stmax - stmin) <= (xtol * stmax))))
|
||
{
|
||
task = Task.Warning;
|
||
}
|
||
if ((((stp == stpmax) && (f <= ftest)) && (g <= gtest)))
|
||
{
|
||
task = Task.Warning;
|
||
}
|
||
if (((stp == stpmin) && (((f > ftest) || (g >= gtest)))))
|
||
{
|
||
task = Task.Warning;
|
||
}
|
||
|
||
//
|
||
// c Test for convergence.
|
||
//
|
||
if (((f <= ftest) && (System.Math.Abs(g) <= (gtol * ((-(ginit)))))))
|
||
{
|
||
task = Task.Convergence;
|
||
}
|
||
//
|
||
// c Test for termination.
|
||
//
|
||
if (task == Task.Warning || task == Task.Convergence)
|
||
{
|
||
goto L1000;
|
||
}
|
||
|
||
//
|
||
// c A modified function is used to predict the step during the
|
||
// c first stage if a lower function value has been obtained but
|
||
// c the decrease is not sufficient.
|
||
//
|
||
if ((((stage == 1) && (f <= fx)) && (f > ftest)))
|
||
{
|
||
//
|
||
// c Define the modified function and derivative values.
|
||
//
|
||
fm = (f - (stp * gtest));
|
||
fxm = (fx - (stx * gtest));
|
||
fym = (fy - (sty * gtest));
|
||
gm = (g - gtest);
|
||
gxm = (gx - gtest);
|
||
gym = (gy - gtest);
|
||
|
||
//
|
||
// Call dcstep to update stx, sty, and to compute the new step.
|
||
//
|
||
dcstep(ref stx, ref fxm, ref gxm, ref sty, ref fym, ref gym,
|
||
ref stp, fm, gm, ref brackt, stmin, stmax);
|
||
|
||
//
|
||
// Reset the function and derivative values for f.
|
||
//
|
||
fx = (fxm + (stx * gtest));
|
||
fy = (fym + (sty * gtest));
|
||
gx = (gxm + gtest);
|
||
gy = (gym + gtest);
|
||
//
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Call dcstep to update stx, sty, and to compute the new step.
|
||
//
|
||
dcstep(ref stx, ref fx, ref gx, ref sty, ref fy, ref gy,
|
||
ref stp, f, g, ref brackt, stmin, stmax);
|
||
}
|
||
|
||
//
|
||
// c Decide if a bisection step is needed.
|
||
//
|
||
if (brackt)
|
||
{
|
||
if ((System.Math.Abs((sty - stx)) >= (0.6600000000000000310862446895043831318617 * width1)))
|
||
{
|
||
stp = (stx + (0.5 * ((sty - stx))));
|
||
}
|
||
width1 = width;
|
||
width = System.Math.Abs((sty - stx));
|
||
}
|
||
//
|
||
// c Set the minimum and maximum steps allowed for stp.
|
||
//
|
||
if (brackt)
|
||
{
|
||
stmin = System.Math.Min(stx, sty);
|
||
stmax = System.Math.Max(stx, sty);
|
||
}
|
||
else
|
||
{
|
||
stmin = (stp + (1.100000000000000088817841970012523233891 * ((stp - stx))));
|
||
stmax = (stp + (4.0 * ((stp - stx))));
|
||
}
|
||
|
||
//
|
||
// c Force the step to be within the bounds stpmax and stpmin.
|
||
//
|
||
stp = System.Math.Max(stp, stpmin);
|
||
stp = System.Math.Min(stp, stpmax);
|
||
//
|
||
// c If further progress is not possible, let stp be the best
|
||
// c point obtained during the search.
|
||
//
|
||
if (((brackt && (((stp <= stmin) || (stp >= stmax)))) || ((brackt && ((stmax - stmin) <= (xtol * stmax))))))
|
||
{
|
||
stp = stx;
|
||
}
|
||
//
|
||
// c Obtain another function and derivative.
|
||
//
|
||
task = Task.FG;
|
||
|
||
//
|
||
L1000:
|
||
|
||
//
|
||
// c Save local variables.
|
||
//
|
||
if (brackt)
|
||
{
|
||
isave[(1 - (1)) + _isave_offset] = 1;
|
||
}
|
||
else
|
||
{
|
||
isave[(1 - (1)) + _isave_offset] = 0;
|
||
}
|
||
|
||
isave[(2 - (1)) + _isave_offset] = stage;
|
||
dsave[(1 - (1)) + _dsave_offset] = ginit;
|
||
dsave[(2 - (1)) + _dsave_offset] = gtest;
|
||
dsave[(3 - (1)) + _dsave_offset] = gx;
|
||
dsave[(4 - (1)) + _dsave_offset] = gy;
|
||
dsave[(5 - (1)) + _dsave_offset] = finit;
|
||
dsave[(6 - (1)) + _dsave_offset] = fx;
|
||
dsave[(7 - (1)) + _dsave_offset] = fy;
|
||
dsave[(8 - (1)) + _dsave_offset] = stx;
|
||
dsave[(9 - (1)) + _dsave_offset] = sty;
|
||
dsave[(10 - (1)) + _dsave_offset] = stmin;
|
||
dsave[(11 - (1)) + _dsave_offset] = stmax;
|
||
dsave[(12 - (1)) + _dsave_offset] = width;
|
||
dsave[(13 - (1)) + _dsave_offset] = width1;
|
||
}
|
||
|
||
//
|
||
// c====================== The end of dcsrch ==============================
|
||
//
|
||
// c **********
|
||
// c
|
||
// c Subroutine dcstep
|
||
// c
|
||
// c This subroutine computes a safeguarded step for a search
|
||
// c procedure and updates an interval that contains a step that
|
||
// c satisfies a sufficient decrease and a curvature condition.
|
||
// c
|
||
// c The parameter stx contains the step with the least function
|
||
// c value. If brackt is set to .true. then a minimizer has
|
||
// c been bracketed in an interval with endpoints stx and sty.
|
||
// c The parameter stp contains the current step.
|
||
// c The subroutine assumes that if brackt is set to .true. then
|
||
// c
|
||
// c min(stx,sty) < stp < max(stx,sty),
|
||
// c
|
||
// c and that the derivative at stx is negative in the direction
|
||
// c of the step.
|
||
// c
|
||
// c The subroutine statement is
|
||
// c
|
||
// c subroutine dcstep(stx,fx,dx,sty,fy,dy,stp,fp,dp,brackt,
|
||
// c stpmin,stpmax)
|
||
// c
|
||
// c where
|
||
// c
|
||
// c stx is a double precision variable.
|
||
// c On entry stx is the best step obtained so far and is an
|
||
// c endpoint of the interval that contains the minimizer.
|
||
// c On exit stx is the updated best step.
|
||
// c
|
||
// c fx is a double precision variable.
|
||
// c On entry fx is the function at stx.
|
||
// c On exit fx is the function at stx.
|
||
// c
|
||
// c dx is a double precision variable.
|
||
// c On entry dx is the derivative of the function at
|
||
// c stx. The derivative must be negative in the direction of
|
||
// c the step, that is, dx and stp - stx must have opposite
|
||
// c signs.
|
||
// c On exit dx is the derivative of the function at stx.
|
||
// c
|
||
// c sty is a double precision variable.
|
||
// c On entry sty is the second endpoint of the interval that
|
||
// c contains the minimizer.
|
||
// c On exit sty is the updated endpoint of the interval that
|
||
// c contains the minimizer.
|
||
// c
|
||
// c fy is a double precision variable.
|
||
// c On entry fy is the function at sty.
|
||
// c On exit fy is the function at sty.
|
||
// c
|
||
// c dy is a double precision variable.
|
||
// c On entry dy is the derivative of the function at sty.
|
||
// c On exit dy is the derivative of the function at the exit sty.
|
||
|
||
// c
|
||
// c stp is a double precision variable.
|
||
// c On entry stp is the current step. If brackt is set to .true.
|
||
// c then on input stp must be between stx and sty.
|
||
// c On exit stp is a new trial step.
|
||
// c
|
||
// c fp is a double precision variable.
|
||
// c On entry fp is the function at stp
|
||
// c On exit fp is unchanged.
|
||
// c
|
||
// c dp is a double precision variable.
|
||
// c On entry dp is the the derivative of the function at stp.
|
||
// c On exit dp is unchanged.
|
||
// c
|
||
// c brackt is an logical variable.
|
||
// c On entry brackt specifies if a minimizer has been bracketed.
|
||
// c Initially brackt must be set to .false.
|
||
// c On exit brackt specifies if a minimizer has been bracketed.
|
||
// c When a minimizer is bracketed brackt is set to .true.
|
||
// c
|
||
// c stpmin is a double precision variable.
|
||
// c On entry stpmin is a lower bound for the step.
|
||
// c On exit stpmin is unchanged.
|
||
// c
|
||
// c stpmax is a double precision variable.
|
||
// c On entry stpmax is an upper bound for the step.
|
||
// c On exit stpmax is unchanged.
|
||
// c
|
||
// c MINPACK-1 Project. June 1983
|
||
// c Argonne National Laboratory.
|
||
// c Jorge J. More' and David J. Thuente.
|
||
// c
|
||
// c MINPACK-2 Project. October 1993.
|
||
// c Argonne National Laboratory and University of Minnesota.
|
||
// c Brett M. Averick and Jorge J. More'.
|
||
// c
|
||
// c **********
|
||
//
|
||
//
|
||
internal static void dcstep(ref double stx, ref double fx, ref double dx,
|
||
ref double sty, ref double fy, ref double dy, ref double stp,
|
||
double fp, double dp, ref bool brackt, double stpmin, double stpmax)
|
||
{
|
||
double gamma = 0.0d;
|
||
double p = 0.0d;
|
||
double q = 0.0d;
|
||
double r = 0.0d;
|
||
double s = 0.0d;
|
||
double sgnd = 0.0d;
|
||
double stpc = 0.0d;
|
||
double stpf = 0.0d;
|
||
double stpq = 0.0d;
|
||
double theta = 0.0d;
|
||
sgnd = (dp * ((dx / System.Math.Abs(dx))));
|
||
|
||
// c First case: A higher function value. The minimum is bracketed.
|
||
// c If the cubic step is closer to stx than the quadratic step, the
|
||
// c cubic step is taken, otherwise the average of the cubic and
|
||
// c quadratic steps is taken.
|
||
|
||
if ((fp > fx))
|
||
{
|
||
theta = ((((3.0 * ((fx - fp))) / ((stp - stx))) + dx) + dp);
|
||
|
||
s = System.Math.Max(System.Math.Abs(theta), System.Math.Max(System.Math.Abs(dx), System.Math.Abs(dp)));
|
||
|
||
gamma = (s * System.Math.Sqrt(((System.Math.Pow(((theta / s)), 2)) - (((dx / s)) * ((dp / s))))));
|
||
if ((stp < stx))
|
||
{
|
||
gamma = (-(gamma));
|
||
}
|
||
p = (((gamma - dx)) + theta);
|
||
q = (((((gamma - dx)) + gamma)) + dp);
|
||
r = (p / q);
|
||
stpc = (stx + (r * ((stp - stx))));
|
||
stpq = (stx + (((((dx / (((((fx - fp)) / ((stp - stx))) + dx)))) / 2.0)) * ((stp - stx))));
|
||
|
||
if ((System.Math.Abs((stpc - stx)) < System.Math.Abs((stpq - stx))))
|
||
{
|
||
stpf = stpc;
|
||
}
|
||
else
|
||
{
|
||
stpf = (stpc + (((stpq - stpc)) / 2.0));
|
||
}
|
||
|
||
brackt = true;
|
||
|
||
//
|
||
// c Second case: A lower function value and derivatives of opposite
|
||
// c sign. The minimum is bracketed. If the cubic step is farther from
|
||
// c stp than the secant step, the cubic step is taken, otherwise the
|
||
|
||
// c secant step is taken.
|
||
//
|
||
}
|
||
else if ((sgnd < 0.0))
|
||
{
|
||
theta = ((((3.0 * ((fx - fp))) / ((stp - stx))) + dx) + dp);
|
||
s = System.Math.Max(System.Math.Abs(theta), System.Math.Max(System.Math.Abs(dx), System.Math.Abs(dp)));
|
||
gamma = (s * System.Math.Sqrt(((System.Math.Pow(((theta / s)), 2)) - (((dx / s)) * ((dp / s))))));
|
||
|
||
if ((stp > stx))
|
||
{
|
||
gamma = (-(gamma));
|
||
}
|
||
|
||
p = (((gamma - dp)) + theta);
|
||
q = (((((gamma - dp)) + gamma)) + dx);
|
||
r = (p / q);
|
||
stpc = (stp + (r * ((stx - stp))));
|
||
stpq = (stp + (((dp / ((dp - dx)))) * ((stx - stp))));
|
||
|
||
if ((System.Math.Abs((stpc - stp)) > System.Math.Abs((stpq - stp))))
|
||
{
|
||
stpf = stpc;
|
||
}
|
||
else
|
||
{
|
||
stpf = stpq;
|
||
}
|
||
|
||
brackt = true;
|
||
//
|
||
// c Third case: A lower function value, derivatives of the same sign,
|
||
|
||
// c and the magnitude of the derivative decreases.
|
||
//
|
||
}
|
||
else if ((System.Math.Abs(dp) < System.Math.Abs(dx)))
|
||
{
|
||
//
|
||
// c The cubic step is computed only if the cubic tends to infinity
|
||
// c in the direction of the step or if the minimum of the cubic
|
||
// c is beyond stp. Otherwise the cubic step is defined to be the
|
||
// c secant step.
|
||
//
|
||
theta = ((((3.0 * ((fx - fp))) / ((stp - stx))) + dx) + dp);
|
||
s = System.Math.Max(System.Math.Abs(theta), System.Math.Max(System.Math.Abs(dx), System.Math.Abs(dp)));
|
||
|
||
//
|
||
// c The case gamma = 0 only arises if the cubic does not tend
|
||
// c to infinity in the direction of the step.
|
||
//
|
||
gamma = (s * System.Math.Sqrt(System.Math.Max(0.0,
|
||
((System.Math.Pow(((theta / s)), 2)) - (((dx / s)) * ((dp / s)))))));
|
||
|
||
if ((stp > stx))
|
||
{
|
||
gamma = (-(gamma));
|
||
}
|
||
|
||
p = (((gamma - dp)) + theta);
|
||
q = (((gamma + ((dx - dp)))) + gamma);
|
||
r = (p / q);
|
||
|
||
if (((r < 0.0) && (gamma != 0.0)))
|
||
{
|
||
stpc = (stp + (r * ((stx - stp))));
|
||
}
|
||
else if ((stp > stx))
|
||
{
|
||
stpc = stpmax;
|
||
}
|
||
else
|
||
{
|
||
stpc = stpmin;
|
||
}
|
||
|
||
stpq = (stp + (((dp / ((dp - dx)))) * ((stx - stp))));
|
||
|
||
if (brackt)
|
||
{
|
||
//
|
||
// c A minimizer has been bracketed. If the cubic step is
|
||
// c closer to stp than the secant step, the cubic step is
|
||
// c taken, otherwise the secant step is taken.
|
||
//
|
||
if ((System.Math.Abs((stpc - stp)) < System.Math.Abs((stpq - stp))))
|
||
{
|
||
stpf = stpc;
|
||
}
|
||
else
|
||
{
|
||
stpf = stpq;
|
||
}
|
||
if ((stp > stx))
|
||
{
|
||
stpf = System.Math.Min((stp +
|
||
(0.6600000000000000310862446895043831318617 * ((sty - stp)))), stpf);
|
||
}
|
||
else
|
||
{
|
||
stpf = System.Math.Max((stp +
|
||
(0.6600000000000000310862446895043831318617 * ((sty - stp)))), stpf);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// c A minimizer has not been bracketed. If the cubic step is
|
||
// c farther from stp than the secant step, the cubic step is
|
||
// c taken, otherwise the secant step is taken.
|
||
//
|
||
if ((System.Math.Abs((stpc - stp)) > System.Math.Abs((stpq - stp))))
|
||
{
|
||
stpf = stpc;
|
||
}
|
||
else
|
||
{
|
||
stpf = stpq;
|
||
}
|
||
stpf = System.Math.Min(stpmax, stpf);
|
||
stpf = System.Math.Max(stpmin, stpf);
|
||
}
|
||
|
||
//
|
||
// c Fourth case: A lower function value, derivatives of the same sign,
|
||
// c and the magnitude of the derivative does not decrease. If the
|
||
// c minimum is not bracketed, the step is either stpmin or stpmax,
|
||
// c otherwise the cubic step is taken.
|
||
//
|
||
}
|
||
else
|
||
{
|
||
if (brackt)
|
||
{
|
||
theta = ((((3.0 * ((fp - fy))) / ((sty - stp))) + dy) + dp);
|
||
s = System.Math.Max(System.Math.Abs(theta), System.Math.Max(System.Math.Abs(dy), System.Math.Abs(dp)));
|
||
gamma = (s * System.Math.Sqrt(((System.Math.Pow(((theta / s)), 2)) - (((dy / s)) * ((dp / s))))));
|
||
|
||
if ((stp > sty))
|
||
{
|
||
gamma = (-(gamma));
|
||
}
|
||
|
||
p = (((gamma - dp)) + theta);
|
||
q = (((((gamma - dp)) + gamma)) + dy);
|
||
r = (p / q);
|
||
stpc = (stp + (r * ((sty - stp))));
|
||
stpf = stpc;
|
||
}
|
||
else if ((stp > stx))
|
||
{
|
||
stpf = stpmax;
|
||
}
|
||
else
|
||
{
|
||
stpf = stpmin;
|
||
}
|
||
}
|
||
|
||
//
|
||
// c Update the interval which contains a minimizer.
|
||
//
|
||
if ((fp > fx))
|
||
{
|
||
sty = stp;
|
||
fy = fp;
|
||
dy = dp;
|
||
}
|
||
else
|
||
{
|
||
if ((sgnd < 0.0))
|
||
{
|
||
sty = stx;
|
||
fy = fx;
|
||
dy = dx;
|
||
}
|
||
stx = stp;
|
||
fx = fp;
|
||
dx = dp;
|
||
}
|
||
|
||
//
|
||
// c Compute the new step.
|
||
//
|
||
stp = stpf;
|
||
}
|
||
|
||
//
|
||
// c======================= The end of cmprlb =============================
|
||
//
|
||
//
|
||
//
|
||
// c ************
|
||
// c
|
||
// c Subroutine errclb
|
||
// c
|
||
// c This subroutine checks the validity of the input data.
|
||
// c
|
||
// c
|
||
// c * * *
|
||
// c
|
||
// c NEOS, November 1994. (Latest revision June 1996.)
|
||
// c Optimization Technology Center.
|
||
// c Argonne National Laboratory and Northwestern University.
|
||
// c Written by
|
||
// c Ciyou Zhu
|
||
// c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
|
||
// c
|
||
// c
|
||
// c ************
|
||
//
|
||
//
|
||
// c Check the input arguments for errors.
|
||
//
|
||
private static void errclb(int n, int m, double factr,
|
||
double[] l, int _l_offset, double[] u, int _u_offset,
|
||
int[] nbd, int _nbd_offset, ref Task task, ref int info, ref int k)
|
||
{
|
||
|
||
int i = 0;
|
||
if ((n <= 0))
|
||
{
|
||
task = Task.Error;
|
||
}
|
||
if ((m <= 0))
|
||
{
|
||
task = Task.Error;
|
||
}
|
||
if ((factr < 0.0))
|
||
{
|
||
task = Task.Error;
|
||
}
|
||
|
||
//
|
||
// c Check the validity of the arrays nbd(i), u(i), and l(i).
|
||
//
|
||
{
|
||
for (i = 1; i <= n; i++)
|
||
{
|
||
if (((nbd[(i - (1)) + _nbd_offset] < 0) || (nbd[(i - (1)) + _nbd_offset] > 3)))
|
||
{
|
||
// c return
|
||
task = Task.Error;
|
||
info = -6;
|
||
k = i;
|
||
}
|
||
if ((nbd[(i - (1)) + _nbd_offset] == 2))
|
||
{
|
||
if ((l[(i - (1)) + _l_offset] > u[(i - (1)) + _u_offset]))
|
||
{
|
||
// c return
|
||
task = Task.Error;
|
||
info = -7;
|
||
k = i;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// c======================= The end of errclb =============================
|
||
//
|
||
//
|
||
//
|
||
// c ************
|
||
// c
|
||
// c Subroutine formk
|
||
// c
|
||
// c This subroutine forms the LEL^T factorization of the indefinite
|
||
// c
|
||
// c matrix K = [-D -Y'ZZ'Y/theta L_a'-R_z' ]
|
||
// c [L_a -R_z theta*S'AA'S ]
|
||
// c where E = [-I 0]
|
||
// c [ 0 I]
|
||
// c The matrix K can be shown to be equal to the matrix M^[-1]N
|
||
// c occurring in section 5.1 of [1], as well as to the matrix
|
||
// c Mbar^[-1] Nbar in section 5.3.
|
||
// c
|
||
// c n is an integer variable.
|
||
// c On entry n is the dimension of the problem.
|
||
// c On exit n is unchanged.
|
||
// c
|
||
// c nsub is an integer variable
|
||
// c On entry nsub is the number of subspace variables in free set.
|
||
// c On exit nsub is not changed.
|
||
// c
|
||
// c ind is an integer array of dimension nsub.
|
||
// c On entry ind specifies the indices of subspace variables.
|
||
// c On exit ind is unchanged.
|
||
// c
|
||
// c nenter is an integer variable.
|
||
// c On entry nenter is the number of variables entering the
|
||
// c free set.
|
||
// c On exit nenter is unchanged.
|
||
// c
|
||
// c ileave is an integer variable.
|
||
// c On entry indx2(ileave),...,indx2(n) are the variables leaving
|
||
// c the free set.
|
||
// c On exit ileave is unchanged.
|
||
// c
|
||
// c indx2 is an integer array of dimension n.
|
||
// c On entry indx2(1),...,indx2(nenter) are the variables entering
|
||
// c the free set, while indx2(ileave),...,indx2(n) are the
|
||
// c variables leaving the free set.
|
||
// c On exit indx2 is unchanged.
|
||
// c
|
||
// c iupdat is an integer variable.
|
||
// c On entry iupdat is the total number of BFGS updates made so far.
|
||
// c On exit iupdat is unchanged.
|
||
// c
|
||
// c updatd is a logical variable.
|
||
// c On entry 'updatd' is true if the L-BFGS matrix is updatd.
|
||
// c On exit 'updatd' is unchanged.
|
||
// c
|
||
// c wn is a double precision array of dimension 2m x 2m.
|
||
// c On entry wn is unspecified.
|
||
// c On exit the upper triangle of wn stores the LEL^T factorization
|
||
|
||
// c of the 2*col x 2*col indefinite matrix
|
||
// c [-D -Y'ZZ'Y/theta L_a'-R_z' ]
|
||
// c [L_a -R_z theta*S'AA'S ]
|
||
// c
|
||
// c wn1 is a double precision array of dimension 2m x 2m.
|
||
// c On entry wn1 stores the lower triangular part of
|
||
// c [Y' ZZ'Y L_a'+R_z']
|
||
// c [L_a+R_z S'AA'S ]
|
||
// c in the previous iteration.
|
||
// c On exit wn1 stores the corresponding updated matrices.
|
||
// c The purpose of wn1 is just to store these inner products
|
||
// c so they can be easily updated and inserted into wn.
|
||
// c
|
||
// c m is an integer variable.
|
||
// c On entry m is the maximum number of variable metric corrections
|
||
|
||
// c used to define the limited memory matrix.
|
||
// c On exit m is unchanged.
|
||
// c
|
||
// c ws, wy, sy, and wtyy are double precision arrays;
|
||
// c theta is a double precision variable;
|
||
// c col is an integer variable;
|
||
// c head is an integer variable.
|
||
// c On entry they store the information defining the
|
||
// c limited memory BFGS matrix:
|
||
// c ws(n,m) stores S, a set of s-vectors;
|
||
// c wy(n,m) stores Y, a set of y-vectors;
|
||
// c sy(m,m) stores S'Y;
|
||
// c wtyy(m,m) stores the Cholesky factorization
|
||
// c of (theta*S'S+LD^(-1)L')
|
||
// c theta is the scaling factor specifying B_0 = theta I;
|
||
// c col is the number of variable metric corrections stored;
|
||
// c head is the location of the 1st s- (or y-) vector in S (or Y).
|
||
// c On exit they are unchanged.
|
||
// c
|
||
// c info is an integer variable.
|
||
// c On entry info is unspecified.
|
||
// c On exit info = 0 for normal return;
|
||
// c = -1 when the 1st Cholesky factorization failed;
|
||
// c = -2 when the 2st Cholesky factorization failed.
|
||
// c
|
||
// c Subprograms called:
|
||
// c
|
||
// c Linpack ... dcopy, dpofa,
|
||
// c
|
||
// c
|
||
// c References:
|
||
// c [1] R. H. Byrd, P. Lu, J. Nocedal and C. Zhu, ``A limited
|
||
// c memory algorithm for bound constrained optimization'',
|
||
// c SIAM J. Scientific Computing 16 (1995), no. 5, pp. 1190--1208.
|
||
// c
|
||
// c [2] C. Zhu, R.H. Byrd, P. Lu, J. Nocedal, ``L-BFGS-B: a
|
||
// c limited memory FORTRAN code for solving bound constrained
|
||
// c optimization problems'', Tech. Report, NAM-11, EECS Department,
|
||
|
||
// c Northwestern University, 1994.
|
||
// c
|
||
// c (Postscript files of these papers are available via anonymous
|
||
// c ftp to eecs.nwu.edu in the directory pub/lbfgs/lbfgs_bcm.)
|
||
// c
|
||
// c * * *
|
||
// c
|
||
// c NEOS, November 1994. (Latest revision June 1996.)
|
||
// c Optimization Technology Center.
|
||
// c Argonne National Laboratory and Northwestern University.
|
||
// c Written by
|
||
// c Ciyou Zhu
|
||
// c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
|
||
// c
|
||
// c
|
||
// c ************
|
||
//
|
||
//
|
||
// c Form the lower triangular part of
|
||
// c WN1 = [Y' ZZ'Y L_a'+R_z']
|
||
// c [L_a+R_z S'AA'S ]
|
||
// c where L_a is the strictly lower triangular part of S'AA'Y
|
||
// c R_z is the upper triangular part of S'ZZ'Y.
|
||
//
|
||
private static void formk(int n, int nsub, int[] ind, int _ind_offset,
|
||
int nenter, int ileave, int[] indx2, int _indx2_offset,
|
||
int iupdat, bool updatd, double[] wn, int _wn_offset, double[] wn1, int _wn1_offset,
|
||
int m, double[] ws, int _ws_offset, double[] wy, int _wy_offset,
|
||
double[] sy, int _sy_offset, double theta, int col, int head,
|
||
ref int info)
|
||
{
|
||
|
||
int m2 = 0;
|
||
int ipntr = 0;
|
||
int jpntr = 0;
|
||
int iy = 0;
|
||
int is2 = 0;
|
||
int jy = 0;
|
||
int js = 0;
|
||
int is1 = 0;
|
||
int js1 = 0;
|
||
int k1 = 0;
|
||
int i = 0;
|
||
int k = 0;
|
||
int col2 = 0;
|
||
int pbegin = 0;
|
||
int pend = 0;
|
||
int dbegin = 0;
|
||
int dend = 0;
|
||
int upcl = 0;
|
||
double temp1 = 0.0d;
|
||
double temp2 = 0.0d;
|
||
double temp3 = 0.0d;
|
||
double temp4 = 0.0d;
|
||
|
||
if (updatd)
|
||
{
|
||
if ((iupdat > m))
|
||
{
|
||
// c shift old part of WN1.
|
||
{
|
||
for (jy = 1; jy <= (m - 1); jy++)
|
||
{
|
||
js = (m + jy);
|
||
dcopy((m - jy), wn1, ((jy + 1) - (1)) + ((jy + 1) - (1)) * ((2 * m))
|
||
+ _wn1_offset, 1, wn1, (jy - (1)) + (jy - (1)) * ((2 * m)) + _wn1_offset, 1);
|
||
dcopy((m - jy), wn1, ((js + 1) - (1)) + ((js + 1) - (1)) * ((2 * m))
|
||
+ _wn1_offset, 1, wn1, (js - (1)) + (js - (1)) * ((2 * m)) + _wn1_offset, 1);
|
||
dcopy((m - 1), wn1, ((m + 2) - (1)) + ((jy + 1) - (1)) * ((2 * m))
|
||
+ _wn1_offset, 1, wn1, ((m + 1) - (1)) + (jy - (1)) * ((2 * m)) + _wn1_offset, 1);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// c put new rows in blocks (1,1), (2,1) and (2,2).
|
||
pbegin = 1;
|
||
pend = nsub;
|
||
dbegin = (nsub + 1);
|
||
dend = n;
|
||
iy = col;
|
||
is2 = (m + col);
|
||
ipntr = ((head + col) - 1);
|
||
if ((ipntr > m))
|
||
{
|
||
ipntr = (ipntr - m);
|
||
}
|
||
jpntr = head;
|
||
{
|
||
for (jy = 1; jy <= col; jy++)
|
||
{
|
||
js = (m + jy);
|
||
temp1 = 0.0;
|
||
temp2 = 0.0;
|
||
temp3 = 0.0;
|
||
|
||
// c compute element jy of row 'col' of Y'ZZ'Y
|
||
{
|
||
for (k = pbegin; k <= pend; k++)
|
||
{
|
||
k1 = ind[(k - (1)) + _ind_offset];
|
||
temp1 = (temp1 + (wy[(k1 - (1)) + (ipntr - (1))
|
||
* (n) + _wy_offset] * wy[(k1 - (1)) + (jpntr - (1)) * (n) + _wy_offset]));
|
||
}
|
||
}
|
||
// c compute elements jy of row 'col' of L_a and S'AA'S
|
||
{
|
||
for (k = dbegin; k <= dend; k++)
|
||
{
|
||
k1 = ind[(k - (1)) + _ind_offset];
|
||
temp2 = (temp2 + (ws[(k1 - (1)) + (ipntr - (1))
|
||
* (n) + _ws_offset] * ws[(k1 - (1)) + (jpntr - (1)) * (n) + _ws_offset]));
|
||
temp3 = (temp3 + (ws[(k1 - (1)) + (ipntr - (1))
|
||
* (n) + _ws_offset] * wy[(k1 - (1)) + (jpntr - (1)) * (n) + _wy_offset]));
|
||
}
|
||
}
|
||
|
||
wn1[(iy - (1)) + (jy - (1)) * ((2 * m)) + _wn1_offset] = temp1;
|
||
wn1[(is2 - (1)) + (js - (1)) * ((2 * m)) + _wn1_offset] = temp2;
|
||
wn1[(is2 - (1)) + (jy - (1)) * ((2 * m)) + _wn1_offset] = temp3;
|
||
jpntr = ((jpntr) % (m) + 1);
|
||
}
|
||
}
|
||
|
||
//
|
||
// c put new column in block (2,1).
|
||
jy = col;
|
||
jpntr = ((head + col) - 1);
|
||
if ((jpntr > m))
|
||
{
|
||
jpntr = (jpntr - m);
|
||
}
|
||
ipntr = head;
|
||
{
|
||
for (i = 1; i <= col; i++)
|
||
{
|
||
is2 = (m + i);
|
||
temp3 = 0.0;
|
||
// c compute element i of column 'col' of R_z
|
||
{
|
||
for (k = pbegin; k <= pend; k++)
|
||
{
|
||
k1 = ind[(k - (1)) + _ind_offset];
|
||
temp3 = (temp3 + (ws[(k1 - (1)) + (ipntr - (1))
|
||
* (n) + _ws_offset] * wy[(k1 - (1)) + (jpntr - (1)) * (n) + _wy_offset]));
|
||
}
|
||
}
|
||
ipntr = ((ipntr) % (m) + 1);
|
||
wn1[(is2 - (1)) + (jy - (1)) * ((2 * m)) + _wn1_offset] = temp3;
|
||
}
|
||
}
|
||
upcl = (col - 1);
|
||
}
|
||
else
|
||
{
|
||
upcl = col;
|
||
}
|
||
|
||
//
|
||
// c modify the old parts in blocks (1,1) and (2,2) due to changes
|
||
// c in the set of free variables.
|
||
|
||
ipntr = head;
|
||
{
|
||
for (iy = 1; iy <= upcl; iy++)
|
||
{
|
||
is2 = (m + iy);
|
||
jpntr = head;
|
||
{
|
||
for (jy = 1; jy <= iy; jy++)
|
||
{
|
||
js = (m + jy);
|
||
temp1 = 0.0;
|
||
temp2 = 0.0;
|
||
temp3 = 0.0;
|
||
temp4 = 0.0;
|
||
{
|
||
for (k = 1; k <= nenter; k++)
|
||
{
|
||
k1 = indx2[(k - (1)) + _indx2_offset];
|
||
temp1 = (temp1 + (wy[(k1 - (1)) + (ipntr - (1))
|
||
* (n) + _wy_offset] * wy[(k1 - (1)) + (jpntr - (1)) * (n) + _wy_offset]));
|
||
temp2 = (temp2 + (ws[(k1 - (1)) + (ipntr - (1))
|
||
* (n) + _ws_offset] * ws[(k1 - (1)) + (jpntr - (1)) * (n) + _ws_offset]));
|
||
}
|
||
}
|
||
{
|
||
for (k = ileave; k <= n; k++)
|
||
{
|
||
k1 = indx2[(k - (1)) + _indx2_offset];
|
||
temp3 = (temp3 + (wy[(k1 - (1)) + (ipntr
|
||
- (1)) * (n) + _wy_offset] * wy[(k1 - (1)) + (jpntr - (1)) * (n) + _wy_offset]));
|
||
temp4 = (temp4 + (ws[(k1 - (1)) + (ipntr
|
||
- (1)) * (n) + _ws_offset] * ws[(k1 - (1)) + (jpntr - (1)) * (n) + _ws_offset]));
|
||
}
|
||
}
|
||
|
||
wn1[(iy - (1)) + (jy - (1)) * ((2 * m)) + _wn1_offset] =
|
||
((wn1[(iy - (1)) + (jy - (1)) * ((2 * m)) + _wn1_offset] + temp1) - temp3);
|
||
wn1[(is2 - (1)) + (js - (1)) * ((2 * m)) + _wn1_offset] =
|
||
((wn1[(is2 - (1)) + (js - (1)) * ((2 * m)) + _wn1_offset] - temp2) + temp4);
|
||
jpntr = ((jpntr) % (m) + 1);
|
||
}
|
||
}
|
||
|
||
ipntr = ((ipntr) % (m) + 1);
|
||
}
|
||
}
|
||
|
||
//
|
||
// c modify the old parts in block (2,1).
|
||
ipntr = head;
|
||
{
|
||
for (is2 = (m + 1); is2 <= (m + upcl); is2++)
|
||
{
|
||
jpntr = head;
|
||
{
|
||
for (jy = 1; jy <= upcl; jy++)
|
||
{
|
||
temp1 = 0.0;
|
||
temp3 = 0.0;
|
||
{
|
||
for (k = 1; k <= nenter; k++)
|
||
{
|
||
k1 = indx2[(k - (1)) + _indx2_offset];
|
||
temp1 = (temp1 + (ws[(k1 - (1)) + (ipntr
|
||
- (1)) * (n) + _ws_offset] * wy[(k1 - (1)) + (jpntr - (1)) * (n) + _wy_offset]));
|
||
}
|
||
}
|
||
{
|
||
for (k = ileave; k <= n; k++)
|
||
{
|
||
k1 = indx2[(k - (1)) + _indx2_offset];
|
||
temp3 = (temp3 + (ws[(k1 - (1)) + (ipntr - (1))
|
||
* (n) + _ws_offset] * wy[(k1 - (1)) + (jpntr - (1)) * (n) + _wy_offset]));
|
||
}
|
||
}
|
||
|
||
if ((is2 <= (jy + m)))
|
||
{
|
||
wn1[(is2 - (1)) + (jy - (1)) * ((2 * m)) + _wn1_offset] =
|
||
((wn1[(is2 - (1)) + (jy - (1)) * ((2 * m)) + _wn1_offset] + temp1) - temp3);
|
||
}
|
||
else
|
||
{
|
||
wn1[(is2 - (1)) + (jy - (1)) * ((2 * m)) + _wn1_offset] =
|
||
((wn1[(is2 - (1)) + (jy - (1)) * ((2 * m)) + _wn1_offset] - temp1) + temp3);
|
||
}
|
||
jpntr = ((jpntr) % (m) + 1);
|
||
}
|
||
}
|
||
ipntr = ((ipntr) % (m) + 1);
|
||
}
|
||
}
|
||
|
||
//
|
||
// c Form the upper triangle of WN = [D+Y' ZZ'Y/theta -L_a'+R_z' ]
|
||
// c [-L_a +R_z S'AA'S*theta]
|
||
//
|
||
m2 = (2 * m);
|
||
{
|
||
for (iy = 1; iy <= col; iy++)
|
||
{
|
||
is2 = (col + iy);
|
||
is1 = (m + iy);
|
||
{
|
||
for (jy = 1; jy <= iy; jy++)
|
||
{
|
||
js = (col + jy);
|
||
js1 = (m + jy);
|
||
wn[(jy - (1)) + (iy - (1)) * ((2 * m)) + _wn_offset] =
|
||
(wn1[(iy - (1)) + (jy - (1)) * ((2 * m)) + _wn1_offset] / theta);
|
||
wn[(js - (1)) + (is2 - (1)) * ((2 * m)) + _wn_offset] =
|
||
(wn1[(is1 - (1)) + (js1 - (1)) * ((2 * m)) + _wn1_offset] * theta);
|
||
}
|
||
}
|
||
{
|
||
for (jy = 1; jy <= (iy - 1); jy++)
|
||
{
|
||
wn[(jy - (1)) + (is2 - (1)) * ((2 * m)) + _wn_offset] =
|
||
(-(wn1[(is1 - (1)) + (jy - (1)) * ((2 * m)) + _wn1_offset]));
|
||
}
|
||
}
|
||
{
|
||
for (jy = iy; jy <= col; jy++)
|
||
{
|
||
wn[(jy - (1)) + (is2 - (1)) * ((2 * m)) + _wn_offset] =
|
||
wn1[(is1 - (1)) + (jy - (1)) * ((2 * m)) + _wn1_offset];
|
||
}
|
||
}
|
||
|
||
wn[(iy - (1)) + (iy - (1)) * ((2 * m)) + _wn_offset] = (wn[(iy - (1)) + (iy - (1)) * ((2 * m))
|
||
+ _wn_offset] + sy[(iy - (1)) + (iy - (1)) * (m) + _sy_offset]);
|
||
}
|
||
}
|
||
|
||
//
|
||
// c Form the upper triangle of WN= [ LL' L^-1(-L_a'+R_z')]
|
||
// c [(-L_a +R_z)L'^-1 S'AA'S*theta ]
|
||
//
|
||
// c first Cholesky factor (1,1) block of wn to get LL'
|
||
// c with L' stored in the upper triangle of wn.
|
||
dpofa(wn, _wn_offset, m2, col, ref info);
|
||
|
||
// c then form L^-1(-L_a'+R_z') in the (1,2) block.
|
||
col2 = (2 * col);
|
||
{
|
||
for (js = (col + 1); js <= col2; js++)
|
||
{
|
||
dtrsl(wn, _wn_offset, m2, col, wn, (1 - (1))
|
||
+ (js - (1)) * ((2 * m)) + _wn_offset, 11, ref info);
|
||
}
|
||
}
|
||
|
||
//
|
||
// c Form S'AA'S*theta + (L^-1(-L_a'+R_z'))'L^-1(-L_a'+R_z') in the
|
||
// c upper triangle of (2,2) block of wn.
|
||
//
|
||
//
|
||
{
|
||
for (is2 = (col + 1); is2 <= col2; is2++)
|
||
{
|
||
{
|
||
for (js = is2; js <= col2; js++)
|
||
{
|
||
wn[(is2 - (1)) + (js - (1)) * ((2 * m)) + _wn_offset] =
|
||
(wn[(is2 - (1)) + (js - (1)) * ((2 * m)) + _wn_offset]
|
||
+ ddot(col, wn, (1 - (1)) + (is2 - (1)) * ((2 * m))
|
||
+ _wn_offset, 1, wn, (1 - (1)) + (js - (1)) * ((2 * m)) + _wn_offset, 1));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// c Cholesky factorization of (2,2) block of wn.
|
||
//
|
||
dpofa(wn, ((col + 1) - (1)) + ((col + 1) - (1))
|
||
* ((2 * m)) + _wn_offset, m2, col, ref info);
|
||
}
|
||
|
||
//
|
||
// c======================= The end of formk ==============================
|
||
//
|
||
//
|
||
//
|
||
// c ************
|
||
// c
|
||
// c Subroutine formt
|
||
// c
|
||
// c This subroutine forms the upper half of the pos. def. and symm.
|
||
|
||
// c T = theta*SS + L*D^(-1)*L', stores T in the upper triangle
|
||
// c of the array wt, and performs the Cholesky factorization of T
|
||
|
||
// c to produce J*J', with J' stored in the upper triangle of wt.
|
||
// c
|
||
// c Subprograms called:
|
||
// c
|
||
// c Linpack ... dpofa.
|
||
// c
|
||
// c
|
||
// c * * *
|
||
// c
|
||
// c NEOS, November 1994. (Latest revision June 1996.)
|
||
// c Optimization Technology Center.
|
||
// c Argonne National Laboratory and Northwestern University.
|
||
// c Written by
|
||
// c Ciyou Zhu
|
||
// c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
|
||
// c
|
||
// c
|
||
// c ************
|
||
//
|
||
//
|
||
//
|
||
// c Form the upper half of T = theta*SS + L*D^(-1)*L',
|
||
// c store T in the upper triangle of the array wt.
|
||
//
|
||
private static void formt(int m,
|
||
double[] wt, int _wt_offset,
|
||
double[] sy, int _sy_offset,
|
||
double[] ss, int _ss_offset,
|
||
int col, double theta, ref int info)
|
||
{
|
||
|
||
int i = 0;
|
||
int j = 0;
|
||
int k = 0;
|
||
int k1 = 0;
|
||
|
||
double ddum = 0.0d;
|
||
{
|
||
for (j = 1; j <= col; j++)
|
||
{
|
||
wt[(1 - (1)) + (j - (1)) * (m) + _wt_offset] = (theta * ss[(1 - (1))
|
||
+ (j - (1)) * (m) + _ss_offset]);
|
||
}
|
||
}
|
||
|
||
{
|
||
for (i = 2; i <= col; i++)
|
||
{
|
||
{
|
||
for (j = i; j <= col; j++)
|
||
{
|
||
k1 = (System.Math.Min(i, j) - 1);
|
||
|
||
ddum = 0.0;
|
||
{
|
||
for (k = 1; k <= k1; k++)
|
||
{
|
||
ddum = (ddum + ((sy[(i - (1)) + (k - (1)) * (m)
|
||
+ _sy_offset] * sy[(j - (1)) + (k - (1)) * (m)
|
||
+ _sy_offset]) / sy[(k - (1)) + (k - (1)) * (m) + _sy_offset]));
|
||
}
|
||
}
|
||
|
||
wt[(i - (1)) + (j - (1)) * (m) + _wt_offset] = (ddum
|
||
+ (theta * ss[(i - (1)) + (j - (1)) * (m) + _ss_offset]));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// c Cholesky factorize T to J*J' with
|
||
// c J' stored in the upper triangle of wt.
|
||
//
|
||
dpofa(wt, _wt_offset, m, col, ref info);
|
||
}
|
||
|
||
//
|
||
// c======================= The end of formt ==============================
|
||
//
|
||
//
|
||
//
|
||
// c ************
|
||
// c
|
||
// c Subroutine freev
|
||
// c
|
||
// c This subroutine counts the entering and leaving variables when
|
||
// c iter > 0, and finds the index set of free and active variables
|
||
// c at the GCP.
|
||
// c
|
||
// c cnstnd is a logical variable indicating whether bounds are present
|
||
// c
|
||
// c index is an integer array of dimension n
|
||
// c for i=1,...,nfree, index(i) are the indices of free variables
|
||
// c for i=nfree+1,...,n, index(i) are the indices of bound variables
|
||
// c On entry after the first iteration, index gives
|
||
// c the free variables at the previous iteration.
|
||
// c On exit it gives the free variables based on the determination
|
||
// c in cauchy using the array iwhere.
|
||
// c
|
||
// c indx2 is an integer array of dimension n
|
||
// c On entry indx2 is unspecified.
|
||
// c On exit with iter>0, indx2 indicates which variables
|
||
// c have changed status since the previous iteration.
|
||
// c For i= 1,...,nenter, indx2(i) have changed from bound to free.
|
||
// c For i= ileave+1,...,n, indx2(i) have changed from free to bound.
|
||
// c
|
||
// c
|
||
// c * * *
|
||
// c
|
||
// c NEOS, November 1994. (Latest revision June 1996.)
|
||
// c Optimization Technology Center.
|
||
// c Argonne National Laboratory and Northwestern University.
|
||
// c Written by
|
||
// c Ciyou Zhu
|
||
// c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
|
||
// c
|
||
// c
|
||
// c ************
|
||
//
|
||
//
|
||
private static void freev(int n, ref int nfree,
|
||
int[] index, int _index_offset, ref int nenter, ref int ileave,
|
||
int[] indx2, int _indx2_offset, int[] iwhere, int _iwhere_offset,
|
||
ref bool wrk, bool updatd, bool cnstnd, int iprint, int iter)
|
||
{
|
||
|
||
int iact = 0;
|
||
int i = 0;
|
||
int k = 0;
|
||
|
||
nenter = 0;
|
||
ileave = (n + 1);
|
||
|
||
if (((iter > 0) && cnstnd))
|
||
{
|
||
// c count the entering and leaving variables.
|
||
{
|
||
for (i = 1; i <= nfree; i++)
|
||
{
|
||
k = index[(i - (1)) + _index_offset];
|
||
|
||
//
|
||
// c write(6,*) ' k = index(i) ', k
|
||
// c write(6,*) ' index = ', i
|
||
//
|
||
if ((iwhere[(k - (1)) + _iwhere_offset] > 0))
|
||
{
|
||
ileave = (ileave - 1);
|
||
indx2[(ileave - (1)) + _indx2_offset] = k;
|
||
|
||
if ((iprint >= 100))
|
||
{
|
||
// DISPLAY: "Variable " + k + " leaves the set of free variables"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
{
|
||
for (i = (1 + nfree); i <= n; i++)
|
||
{
|
||
k = index[(i - (1)) + _index_offset];
|
||
if ((iwhere[(k - (1)) + _iwhere_offset] <= 0))
|
||
{
|
||
nenter = (nenter + 1);
|
||
indx2[(nenter - (1)) + _indx2_offset] = k;
|
||
|
||
|
||
if ((iprint >= 100))
|
||
{
|
||
// DISPLAY: "Variable " + k + " enters the set of free variables"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if ((iprint >= 99))
|
||
{
|
||
// DISPLAY: ((n + 1) - ileave)) + " variables leave; "
|
||
// nenter + " variables enter"
|
||
}
|
||
}
|
||
|
||
wrk = ((((ileave < (n + 1))) || ((nenter > 0))) || updatd);
|
||
|
||
//
|
||
// c Find the index set of free and active variables at the GCP.
|
||
//
|
||
nfree = 0;
|
||
iact = (n + 1);
|
||
{
|
||
for (i = 1; i <= n; i++)
|
||
{
|
||
if ((iwhere[(i - (1)) + _iwhere_offset] <= 0))
|
||
{
|
||
nfree = (nfree + 1);
|
||
index[(nfree - (1)) + _index_offset] = i;
|
||
}
|
||
else
|
||
{
|
||
iact = (iact - 1);
|
||
index[(iact - (1)) + _index_offset] = i;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ((iprint >= 99))
|
||
{
|
||
// DISPLAY: nfree + " variables are free at GCP " + (iter + 1))
|
||
}
|
||
}
|
||
|
||
//
|
||
// c======================= The end of freev ==============================
|
||
//
|
||
//
|
||
// c ************
|
||
// c
|
||
// c Subroutine hpsolb
|
||
// c
|
||
// c This subroutine sorts out the least element of t, and puts the
|
||
// c remaining elements of t in a heap.
|
||
// c
|
||
// c n is an integer variable.
|
||
// c On entry n is the dimension of the arrays t and iorder.
|
||
// c On exit n is unchanged.
|
||
// c
|
||
// c t is a double precision array of dimension n.
|
||
// c On entry t stores the elements to be sorted,
|
||
// c On exit t(n) stores the least elements of t, and t(1) to t(n-1)
|
||
|
||
// c stores the remaining elements in the form of a heap.
|
||
// c
|
||
// c iorder is an integer array of dimension n.
|
||
// c On entry iorder(i) is the index of t(i).
|
||
// c On exit iorder(i) is still the index of t(i), but iorder may be
|
||
|
||
// c permuted in accordance with t.
|
||
// c
|
||
// c iheap is an integer variable specifying the task.
|
||
// c On entry iheap should be set as follows:
|
||
// c iheap .eq. 0 if t(1) to t(n) is not in the form of a heap,
|
||
// c iheap .ne. 0 if otherwise.
|
||
// c On exit iheap is unchanged.
|
||
// c
|
||
// c
|
||
// c References:
|
||
// c Algorithm 232 of CACM (J. W. J. Williams): HEAPSORT.
|
||
// c
|
||
// c * * *
|
||
// c
|
||
// c NEOS, November 1994. (Latest revision June 1996.)
|
||
// c Optimization Technology Center.
|
||
// c Argonne National Laboratory and Northwestern University.
|
||
// c Written by
|
||
// c Ciyou Zhu
|
||
// c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
|
||
// c
|
||
// c ************
|
||
//
|
||
//
|
||
private static void hpsolb(int n, double[] t, int _t_offset,
|
||
int[] iorder, int _iorder_offset, int iheap)
|
||
{
|
||
|
||
int i = 0;
|
||
int j = 0;
|
||
int k = 0;
|
||
int indxin = 0;
|
||
int indxou = 0;
|
||
double ddum = 0.0d;
|
||
double out2 = 0.0d;
|
||
|
||
if ((iheap == 0))
|
||
{
|
||
//
|
||
// c Rearrange the elements t(1) to t(n) to form a heap.
|
||
//
|
||
{
|
||
for (k = 2; k <= n; k++)
|
||
{
|
||
ddum = t[(k - (1)) + _t_offset];
|
||
indxin = iorder[(k - (1)) + _iorder_offset];
|
||
//
|
||
// c Add ddum to the heap.
|
||
i = k;
|
||
|
||
L10:
|
||
if ((i > 1))
|
||
{
|
||
j = (i / 2);
|
||
if ((ddum < t[(j - (1)) + _t_offset]))
|
||
{
|
||
t[(i - (1)) + _t_offset] = t[(j - (1)) + _t_offset];
|
||
iorder[(i - (1)) + _iorder_offset] = iorder[(j - (1)) + _iorder_offset];
|
||
i = j;
|
||
goto L10;
|
||
}
|
||
}
|
||
|
||
t[(i - (1)) + _t_offset] = ddum;
|
||
iorder[(i - (1)) + _iorder_offset] = indxin;
|
||
}
|
||
}
|
||
}
|
||
//
|
||
// c Assign to 'out' the value of t(1), the least member of the heap,
|
||
// c and rearrange the remaining members to form a heap as
|
||
// c elements 1 to n-1 of t.
|
||
//
|
||
if ((n > 1))
|
||
{
|
||
i = 1;
|
||
out2 = t[(1 - (1)) + _t_offset];
|
||
indxou = iorder[(1 - (1)) + _iorder_offset];
|
||
ddum = t[(n - (1)) + _t_offset];
|
||
indxin = iorder[(n - (1)) + _iorder_offset];
|
||
|
||
//
|
||
// c Restore the heap
|
||
L30:
|
||
j = (i + i);
|
||
if ((j <= (n - 1)))
|
||
{
|
||
if ((t[((j + 1) - (1)) + _t_offset] < t[(j - (1)) + _t_offset]))
|
||
{
|
||
j = (j + 1);
|
||
}
|
||
if ((t[(j - (1)) + _t_offset] < ddum))
|
||
{
|
||
t[(i - (1)) + _t_offset] = t[(j - (1)) + _t_offset];
|
||
iorder[(i - (1)) + _iorder_offset] = iorder[(j - (1)) + _iorder_offset];
|
||
i = j;
|
||
goto L30;
|
||
}
|
||
}
|
||
t[(i - (1)) + _t_offset] = ddum;
|
||
iorder[(i - (1)) + _iorder_offset] = indxin;
|
||
//
|
||
// c Put the least member in t(n).
|
||
//
|
||
t[(n - (1)) + _t_offset] = out2;
|
||
iorder[(n - (1)) + _iorder_offset] = indxou;
|
||
}
|
||
}
|
||
|
||
//
|
||
// c====================== The end of hpsolb ==============================
|
||
//
|
||
//
|
||
// c **********
|
||
// c
|
||
// c Subroutine lnsrlb
|
||
// c
|
||
// c This subroutine calls subroutine dcsrch from the Minpack2 library
|
||
|
||
// c to perform the line search. Subroutine dscrch is safeguarded so
|
||
// c that all trial points lie within the feasible region.
|
||
// c
|
||
// c Subprograms called:
|
||
// c
|
||
// c Minpack2 Library ... dcsrch.
|
||
// c
|
||
// c Linpack ... dtrsl,
|
||
// c
|
||
// c
|
||
// c * * *
|
||
// c
|
||
// c NEOS, November 1994. (Latest revision June 1996.)
|
||
// c Optimization Technology Center.
|
||
// c Argonne National Laboratory and Northwestern University.
|
||
// c Written by
|
||
// c Ciyou Zhu
|
||
// c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
|
||
// c
|
||
// c
|
||
// c **********
|
||
//
|
||
//
|
||
private static void lnsrlb(int n, double[] l, int _l_offset, double[] u, int _u_offset,
|
||
int[] nbd, int _nbd_offset, double[] x, int _x_offset, double f, ref double fold, ref double gd,
|
||
ref double gdold, double[] g, int _g_offset, double[] d, int _d_offset, double[] r, int _r_offset,
|
||
double[] t, int _t_offset, double[] z, int _z_offset, ref double stp,
|
||
ref double dnorm, ref double dtd, ref double xstep, ref double stpmx, int iter,
|
||
ref int ifun, ref int iback, ref int nfgv, ref int info, ref Task task,
|
||
bool boxed, bool cnstnd, ref Task csave, int[] isave, int _isave_offset,
|
||
double[] dsave, int _dsave_offset)
|
||
{
|
||
|
||
int i = 0;
|
||
double a1 = 0.0d;
|
||
double a2 = 0.0d;
|
||
|
||
if (task == Task.FG_LN)
|
||
{
|
||
goto L556;
|
||
}
|
||
|
||
//
|
||
dtd = ddot(n, d, _d_offset, 1, d, _d_offset, 1);
|
||
dnorm = System.Math.Sqrt(dtd);
|
||
//
|
||
// c Determine the maximum step length.
|
||
//
|
||
stpmx = 10000000000.0;
|
||
if (cnstnd)
|
||
{
|
||
if ((iter == 0))
|
||
{
|
||
stpmx = 1.0;
|
||
}
|
||
else
|
||
{
|
||
{
|
||
for (i = 1; i <= n; i++)
|
||
{
|
||
a1 = d[(i - (1)) + _d_offset];
|
||
if ((nbd[(i - (1)) + _nbd_offset] != 0))
|
||
{
|
||
if (((a1 < 0.0) && (nbd[(i - (1)) + _nbd_offset] <= 2)))
|
||
{
|
||
a2 = (l[(i - (1)) + _l_offset] - x[(i - (1)) + _x_offset]);
|
||
if ((a2 >= 0.0))
|
||
{
|
||
stpmx = 0.0;
|
||
}
|
||
else if (((a1 * stpmx) < a2))
|
||
{
|
||
stpmx = (a2 / a1);
|
||
}
|
||
}
|
||
else if (((a1 > 0.0) && (nbd[(i - (1)) + _nbd_offset] >= 2)))
|
||
{
|
||
a2 = (u[(i - (1)) + _u_offset] - x[(i - (1)) + _x_offset]);
|
||
if ((a2 <= 0.0))
|
||
{
|
||
stpmx = 0.0;
|
||
}
|
||
else if (((a1 * stpmx) > a2))
|
||
{
|
||
stpmx = (a2 / a1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
if (((iter == 0) && (!boxed)))
|
||
{
|
||
if (double.IsNaN(dnorm))
|
||
stp = stpmx;
|
||
else
|
||
stp = System.Math.Min((1.0 / dnorm), stpmx);
|
||
}
|
||
else
|
||
{
|
||
stp = 1.0;
|
||
}
|
||
|
||
//
|
||
dcopy(n, x, _x_offset, 1, t, _t_offset, 1);
|
||
dcopy(n, g, _g_offset, 1, r, _r_offset, 1);
|
||
|
||
fold = f;
|
||
ifun = 0;
|
||
iback = 0;
|
||
csave = Task.Start;
|
||
|
||
L556:
|
||
gd = BFGS.ddot(n, g, _g_offset, 1, d, _d_offset, 1);
|
||
|
||
if ((ifun == 0))
|
||
{
|
||
gdold = gd;
|
||
if ((gd >= 0.0))
|
||
{
|
||
// the directional derivative >=0.
|
||
// Line search is impossible.
|
||
|
||
// DISPLAY: " ascent direction in projection gd = " + gd
|
||
info = -4;
|
||
return;
|
||
}
|
||
}
|
||
|
||
dcsrch(f, gd, ref stp,
|
||
0.001000000000000000020816681711721685132943,
|
||
0.9000000000000000222044604925031308084726,
|
||
0.1000000000000000055511151231257827021182, 0.0,
|
||
stpmx, ref csave, isave, _isave_offset, dsave, _dsave_offset);
|
||
|
||
//
|
||
xstep = (stp * dnorm);
|
||
if (csave != Task.Convergence && csave != Task.Warning)
|
||
{
|
||
task = Task.FG_LN;
|
||
ifun = (ifun + 1);
|
||
nfgv = (nfgv + 1);
|
||
iback = (ifun - 1);
|
||
if ((stp == 1.0))
|
||
{
|
||
dcopy(n, z, _z_offset, 1, x, _x_offset, 1);
|
||
}
|
||
else
|
||
{
|
||
{
|
||
for (i = 1; i <= n; i++)
|
||
{
|
||
x[(i - (1)) + _x_offset] = ((stp * d[(i - (1)) + _d_offset]) + t[(i - (1)) + _t_offset]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
task = Task.New_X;
|
||
}
|
||
}
|
||
|
||
//
|
||
// c======================= The end of setulb =============================
|
||
//
|
||
// c-jlm-jn
|
||
//
|
||
//
|
||
// c ************
|
||
// c
|
||
// c Subroutine mainlb
|
||
// c
|
||
// c This subroutine solves bound constrained optimization problems by
|
||
|
||
// c using the compact formula of the limited memory BFGS updates.
|
||
// c
|
||
// c n is an integer variable.
|
||
// c On entry n is the number of variables.
|
||
// c On exit n is unchanged.
|
||
// c
|
||
// c m is an integer variable.
|
||
// c On entry m is the maximum number of variable metric
|
||
// c corrections allowed in the limited memory matrix.
|
||
// c On exit m is unchanged.
|
||
// c
|
||
// c x is a double precision array of dimension n.
|
||
// c On entry x is an approximation to the solution.
|
||
// c On exit x is the current approximation.
|
||
// c
|
||
// c l is a double precision array of dimension n.
|
||
// c On entry l is the lower bound of x.
|
||
// c On exit l is unchanged.
|
||
// c
|
||
// c u is a double precision array of dimension n.
|
||
// c On entry u is the upper bound of x.
|
||
// c On exit u is unchanged.
|
||
// c
|
||
// c nbd is an integer array of dimension n.
|
||
// c On entry nbd represents the type of bounds imposed on the
|
||
// c variables, and must be specified as follows:
|
||
// c nbd(i)=0 if x(i) is unbounded,
|
||
// c 1 if x(i) has only a lower bound,
|
||
// c 2 if x(i) has both lower and upper bounds,
|
||
// c 3 if x(i) has only an upper bound.
|
||
// c On exit nbd is unchanged.
|
||
// c
|
||
// c f is a double precision variable.
|
||
// c On first entry f is unspecified.
|
||
// c On final exit f is the value of the function at x.
|
||
// c
|
||
// c g is a double precision array of dimension n.
|
||
// c On first entry g is unspecified.
|
||
// c On final exit g is the value of the gradient at x.
|
||
// c
|
||
// c factr is a double precision variable.
|
||
// c On entry factr >= 0 is specified by the user. The iteration
|
||
// c will stop when
|
||
// c
|
||
// c (f^k - f^{k+1})/max{|f^k|,|f^{k+1}|,1} <= factr*epsmch
|
||
// c
|
||
// c where epsmch is the machine precision, which is automatically
|
||
|
||
// c generated by the code.
|
||
// c On exit factr is unchanged.
|
||
// c
|
||
// c pgtol is a double precision variable.
|
||
// c On entry pgtol >= 0 is specified by the user. The iteration
|
||
// c will stop when
|
||
// c
|
||
// c max{|proj g_i | i = 1, ..., n} <= pgtol
|
||
// c
|
||
// c where pg_i is the ith component of the projected gradient.
|
||
// c On exit pgtol is unchanged.
|
||
// c
|
||
// c ws, wy, sy, and wt are double precision working arrays used to
|
||
// c store the following information defining the limited memory
|
||
// c BFGS matrix:
|
||
// c ws, of dimension n x m, stores S, the matrix of s-vectors;
|
||
// c wy, of dimension n x m, stores Y, the matrix of y-vectors;
|
||
// c sy, of dimension m x m, stores S'Y;
|
||
// c ss, of dimension m x m, stores S'S;
|
||
// c yy, of dimension m x m, stores Y'Y;
|
||
// c wt, of dimension m x m, stores the Cholesky factorization
|
||
// c of (theta*S'S+LD^(-1)L'); see eq.
|
||
// c (2.26) in [3].
|
||
// c
|
||
// c wn is a double precision working array of dimension 2m x 2m
|
||
// c used to store the LEL^T factorization of the indefinite matrix
|
||
// c K = [-D -Y'ZZ'Y/theta L_a'-R_z' ]
|
||
// c [L_a -R_z theta*S'AA'S ]
|
||
// c
|
||
// c where E = [-I 0]
|
||
// c [ 0 I]
|
||
// c
|
||
// c snd is a double precision working array of dimension 2m x 2m
|
||
// c used to store the lower triangular part of
|
||
// c N = [Y' ZZ'Y L_a'+R_z']
|
||
// c [L_a +R_z S'AA'S ]
|
||
// c
|
||
// c z(n),r(n),d(n),t(n), xp(n),wa(8*m) are double precision working ar
|
||
// c z is used at different times to store the Cauchy point and
|
||
// c the Newton point.
|
||
// c xp is used to safeguard the projected Newton direction
|
||
// c
|
||
// c sg(m),sgo(m),yg(m),ygo(m) are double precision working arrays.
|
||
// c
|
||
// c index is an integer working array of dimension n.
|
||
// c In subroutine freev, index is used to store the free and fixed
|
||
// c variables at the Generalized Cauchy Point (GCP).
|
||
// c
|
||
// c iwhere is an integer working array of dimension n used to record
|
||
// c the status of the vector x for GCP computation.
|
||
// c iwhere(i)=0 or -3 if x(i) is free and has bounds,
|
||
// c 1 if x(i) is fixed at l(i), and l(i) .ne. u(i)
|
||
// c 2 if x(i) is fixed at u(i), and u(i) .ne. l(i)
|
||
// c 3 if x(i) is always fixed, i.e., u(i)=x(i)=l(i)
|
||
// c -1 if x(i) is always free, i.e., no bounds on it.
|
||
// c
|
||
// c indx2 is an integer working array of dimension n.
|
||
// c Within subroutine cauchy, indx2 corresponds to the array iorder.
|
||
// c In subroutine freev, a list of variables entering and leaving
|
||
// c the free set is stored in indx2, and it is passed on to
|
||
// c subroutine formk with this information.
|
||
// c
|
||
// c task is a working string of characters of length 60 indicating
|
||
// c the current job when entering and leaving this subroutine.
|
||
// c
|
||
// c iprint is an INTEGER variable that must be set by the user.
|
||
// c It controls the frequency and type of output generated:
|
||
// c iprint<0 no output is generated;
|
||
// c iprint=0 print only one line at the last iteration;
|
||
// c 0<iprint<99 print also f and |proj g| every iprint iterations;
|
||
|
||
// c iprint=99 print details of every iteration except n-vectors;
|
||
|
||
// c iprint=100 print also the changes of active set and final x;
|
||
// c iprint>100 print details of every iteration including x and g;
|
||
// c When iprint > 0, the file iterate.dat will be created to
|
||
// c summarize the iteration.
|
||
// c
|
||
// c csave is a working string of characters of length 60.
|
||
// c
|
||
// c lsave is a logical working array of dimension 4.
|
||
// c
|
||
// c isave is an integer working array of dimension 23.
|
||
// c
|
||
// c dsave is a double precision working array of dimension 29.
|
||
// c
|
||
// c
|
||
// c Subprograms called
|
||
// c
|
||
// c L-BFGS-B Library ... cauchy, subsm, lnsrlb, formk,
|
||
// c
|
||
// c errclb, prn1lb, prn2lb, prn3lb, active, projgr,
|
||
// c
|
||
// c freev, cmprlb, matupd, formt.
|
||
// c
|
||
// c Minpack2 Library ... timer
|
||
// c
|
||
// c Linpack Library ... dcopy,
|
||
// c
|
||
// c
|
||
// c References:
|
||
// c
|
||
// c [1] R. H. Byrd, P. Lu, J. Nocedal and C. Zhu, ``A limited
|
||
// c memory algorithm for bound constrained optimization'',
|
||
// c SIAM J. Scientific Computing 16 (1995), no. 5, pp. 1190--1208.
|
||
// c
|
||
// c [2] C. Zhu, R.H. Byrd, P. Lu, J. Nocedal, ``L-BFGS-B: FORTRAN
|
||
// c Subroutines for Large Scale Bound Constrained Optimization''
|
||
// c Tech. Report, NAM-11, EECS Department, Northwestern University,
|
||
|
||
// c 1994.
|
||
// c
|
||
// c [3] R. Byrd, J. Nocedal and R. Schnabel "Representations of
|
||
// c Quasi-Newton Matrices and their use in Limited Memory Methods'',
|
||
// c Mathematical Programming 63 (1994), no. 4, pp. 129-156.
|
||
// c
|
||
// c (Postscript files of these papers are available via anonymous
|
||
// c ftp to eecs.nwu.edu in the directory pub/lbfgs/lbfgs_bcm.)
|
||
// c
|
||
// c * * *
|
||
// c
|
||
// c NEOS, November 1994. (Latest revision June 1996.)
|
||
// c Optimization Technology Center.
|
||
// c Argonne National Laboratory and Northwestern University.
|
||
// c Written by
|
||
// c Ciyou Zhu
|
||
// c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
|
||
// c
|
||
// c
|
||
// c ************
|
||
//
|
||
//
|
||
private static void mainlb(int n,
|
||
int m,
|
||
double[] x, int _x_offset,
|
||
double[] l, int _l_offset,
|
||
double[] u, int _u_offset,
|
||
int[] nbd, int _nbd_offset,
|
||
ref double f,
|
||
double[] g, int _g_offset,
|
||
double factr,
|
||
double pgtol,
|
||
double[] ws, int _ws_offset,
|
||
double[] wy, int _wy_offset,
|
||
double[] sy, int _sy_offset,
|
||
double[] ss, int _ss_offset,
|
||
double[] wt, int _wt_offset,
|
||
double[] wn, int _wn_offset,
|
||
double[] snd, int _snd_offset,
|
||
double[] z, int _z_offset,
|
||
double[] r, int _r_offset,
|
||
double[] d, int _d_offset,
|
||
double[] t, int _t_offset,
|
||
double[] xp, int _xp_offset,
|
||
double[] wa, int _wa_offset,
|
||
int[] index, int _index_offset,
|
||
int[] iwhere, int _iwhere_offset,
|
||
int[] indx2, int _indx2_offset,
|
||
ref Task task,
|
||
int iprint,
|
||
ref Task csave,
|
||
bool[] lsave, int _lsave_offset,
|
||
int[] isave, int _isave_offset,
|
||
double[] dsave, int _dsave_offset)
|
||
{
|
||
|
||
bool prjctd = false;
|
||
bool cnstnd = false;
|
||
bool boxed = false;
|
||
bool updatd = false;
|
||
bool wrk = false;
|
||
int i = 0;
|
||
int k = 0;
|
||
int nintol = 0;
|
||
int itfile = 0;
|
||
int iback = 0;
|
||
int nskip = 0;
|
||
int head = 0;
|
||
int col = 0;
|
||
int iter = 0;
|
||
int itail = 0;
|
||
int iupdat = 0;
|
||
int nseg = 0;
|
||
int nfgv = 0;
|
||
int info = 0;
|
||
int ifun = 0;
|
||
int iword = 0;
|
||
int nfree = 0;
|
||
int nact = 0;
|
||
int ileave = 0;
|
||
int nenter = 0;
|
||
double theta = 0.0d;
|
||
double fold = 0.0d;
|
||
double dr = 0.0d;
|
||
double rr = 0.0d;
|
||
double tol = 0.0d;
|
||
double xstep = 0.0d;
|
||
double sbgnrm = 0.0d;
|
||
double ddum = 0.0d;
|
||
double dnorm = 0.0d;
|
||
double dtd = 0.0d;
|
||
double epsmch = 0.0d;
|
||
double cpu1 = 0.0d;
|
||
double cpu2 = 0.0d;
|
||
double cachyt = 0.0d;
|
||
double sbtime = 0.0d;
|
||
double lnscht = 0.0d;
|
||
double time1 = 0.0d;
|
||
// double time2 = 0.0d;
|
||
double gd = 0.0d;
|
||
double gdold = 0.0d;
|
||
double stp = 0.0d;
|
||
double stpmx = 0.0d;
|
||
// double time = 0.0d;
|
||
// float epsilon = 0.0f;
|
||
|
||
if (task == Task.Start)
|
||
{
|
||
//
|
||
// epsmch = (double)(Epsilon.epsilon(1.0));
|
||
epsmch = 1.11022302462516E-16;
|
||
|
||
//
|
||
//Timer.timer(time1);
|
||
//
|
||
// c Initialize counters and scalars when task='START'.
|
||
//
|
||
// c for the limited memory BFGS matrices:
|
||
col = 0;
|
||
head = 1;
|
||
theta = 1.0;
|
||
iupdat = 0;
|
||
updatd = false;
|
||
iback = 0;
|
||
itail = 0;
|
||
iword = 0;
|
||
nact = 0;
|
||
ileave = 0;
|
||
nenter = 0;
|
||
fold = 0.0;
|
||
dnorm = 0.0;
|
||
cpu1 = 0.0;
|
||
gd = 0.0;
|
||
stpmx = 0.0;
|
||
sbgnrm = 0.0;
|
||
stp = 0.0;
|
||
gdold = 0.0;
|
||
dtd = 0.0;
|
||
//
|
||
// c for operation counts:
|
||
iter = 0;
|
||
nfgv = 0;
|
||
nseg = 0;
|
||
nintol = 0;
|
||
nskip = 0;
|
||
nfree = n;
|
||
ifun = 0;
|
||
// c for stopping tolerance:
|
||
tol = (factr * epsmch);
|
||
//
|
||
// c for measuring running time:
|
||
cachyt = (double)(0);
|
||
sbtime = (double)(0);
|
||
lnscht = (double)(0);
|
||
|
||
//
|
||
// c 'info' records the termination information.
|
||
info = 0;
|
||
//
|
||
itfile = 8;
|
||
if ((iprint >= 1))
|
||
{
|
||
// c open a summary file 'iterate.dat'
|
||
; // WARNING: Unimplemented statement in Fortran source.
|
||
}
|
||
//
|
||
// c Check the input arguments for errors.
|
||
//
|
||
errclb(n, m, factr, l, _l_offset, u, _u_offset,
|
||
nbd, _nbd_offset, ref task, ref info, ref k);
|
||
|
||
if (task == Task.Error)
|
||
{
|
||
/*
|
||
Prn3lb.prn3lb(n, x, _x_offset, f, task, iprint,
|
||
info, itfile, iter, nfgv, nintol, nskip, nact, sbgnrm, 0.0, nseg, word,
|
||
iback, stp, xstep, k, cachyt, sbtime, lnscht);
|
||
*/
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Prn1lb.prn1lb(n, m, l, _l_offset, u, _u_offset, x, _x_offset, iprint, itfile, epsmch);
|
||
|
||
//
|
||
// c Initialize iwhere & project x onto the feasible set.
|
||
//
|
||
active(n, l, _l_offset, u, _u_offset, nbd, _nbd_offset, x,
|
||
_x_offset, iwhere, _iwhere_offset, iprint, ref prjctd, ref cnstnd, ref boxed);
|
||
//
|
||
// c The end of the initialization.
|
||
//
|
||
}
|
||
else
|
||
{
|
||
// c restore local variables.
|
||
//
|
||
prjctd = lsave[(1 - (1)) + _lsave_offset];
|
||
cnstnd = lsave[(2 - (1)) + _lsave_offset];
|
||
boxed = lsave[(3 - (1)) + _lsave_offset];
|
||
updatd = lsave[(4 - (1)) + _lsave_offset];
|
||
//
|
||
nintol = isave[(1 - (1)) + _isave_offset];
|
||
itfile = isave[(3 - (1)) + _isave_offset];
|
||
iback = isave[(4 - (1)) + _isave_offset];
|
||
nskip = isave[(5 - (1)) + _isave_offset];
|
||
head = isave[(6 - (1)) + _isave_offset];
|
||
col = isave[(7 - (1)) + _isave_offset];
|
||
itail = isave[(8 - (1)) + _isave_offset];
|
||
iter = isave[(9 - (1)) + _isave_offset];
|
||
iupdat = isave[(10 - (1)) + _isave_offset];
|
||
nseg = isave[(12 - (1)) + _isave_offset];
|
||
nfgv = isave[(13 - (1)) + _isave_offset];
|
||
info = isave[(14 - (1)) + _isave_offset];
|
||
ifun = isave[(15 - (1)) + _isave_offset];
|
||
iword = isave[(16 - (1)) + _isave_offset];
|
||
nfree = isave[(17 - (1)) + _isave_offset];
|
||
nact = isave[(18 - (1)) + _isave_offset];
|
||
ileave = isave[(19 - (1)) + _isave_offset];
|
||
nenter = isave[(20 - (1)) + _isave_offset];
|
||
//
|
||
theta = dsave[(1 - (1)) + _dsave_offset];
|
||
fold = dsave[(2 - (1)) + _dsave_offset];
|
||
tol = dsave[(3 - (1)) + _dsave_offset];
|
||
dnorm = dsave[(4 - (1)) + _dsave_offset];
|
||
epsmch = dsave[(5 - (1)) + _dsave_offset];
|
||
cpu1 = dsave[(6 - (1)) + _dsave_offset];
|
||
cachyt = dsave[(7 - (1)) + _dsave_offset];
|
||
sbtime = dsave[(8 - (1)) + _dsave_offset];
|
||
lnscht = dsave[(9 - (1)) + _dsave_offset];
|
||
time1 = dsave[(10 - (1)) + _dsave_offset];
|
||
gd = dsave[(11 - (1)) + _dsave_offset];
|
||
stpmx = dsave[(12 - (1)) + _dsave_offset];
|
||
sbgnrm = dsave[(13 - (1)) + _dsave_offset];
|
||
stp = dsave[(14 - (1)) + _dsave_offset];
|
||
gdold = dsave[(15 - (1)) + _dsave_offset];
|
||
dtd = dsave[(16 - (1)) + _dsave_offset];
|
||
//
|
||
// c After returning from the driver go to the point where execution
|
||
// c is to resume.
|
||
//
|
||
if (task == Task.FG_LN)
|
||
{
|
||
goto L666;
|
||
}
|
||
|
||
if (task == Task.New_X)
|
||
{
|
||
goto L777;
|
||
}
|
||
|
||
if (task == Task.FG_ST)
|
||
{
|
||
goto L111;
|
||
}
|
||
}
|
||
|
||
//
|
||
// c Compute f0 and g0.
|
||
//
|
||
task = Task.FG_ST;
|
||
|
||
// c return to the driver to calculate f and g; reenter at 111.
|
||
goto L1000;
|
||
|
||
L111:
|
||
|
||
nfgv = 1;
|
||
|
||
//
|
||
// c Compute the infinity norm of the (-) projected gradient.
|
||
//
|
||
projgr(n, l, _l_offset, u, _u_offset, nbd, _nbd_offset,
|
||
x, _x_offset, g, _g_offset, ref sbgnrm);
|
||
|
||
if ((sbgnrm <= pgtol))
|
||
{
|
||
// terminate the algorithm.
|
||
task = Task.Convergence;
|
||
goto L999;
|
||
}
|
||
//
|
||
// c ----------------- the beginning of the loop --------------------------
|
||
//
|
||
L222:
|
||
iword = -1;
|
||
//Compute the Generalized Cauchy Point (GCP).
|
||
cauchy(n, x, _x_offset, l, _l_offset, u, _u_offset, nbd, _nbd_offset,
|
||
g, _g_offset, indx2, _indx2_offset, iwhere, _iwhere_offset, t, _t_offset,
|
||
d, _d_offset, z, _z_offset, m, wy, _wy_offset, ws, _ws_offset, sy, _sy_offset,
|
||
wt, _wt_offset, theta, col, head, wa, (1 - (1)) + _wa_offset, wa,
|
||
(((2 * m) + 1) - (1)) + _wa_offset, wa, (((4 * m) + 1) - (1)) + _wa_offset, wa,
|
||
(((6 * m) + 1) - (1)) + _wa_offset, ref nseg, iprint, sbgnrm, ref info, epsmch);
|
||
|
||
cachyt = cachyt + cpu2 - cpu1;
|
||
nintol = nintol + nseg;
|
||
// Count the entering and leaving variables for iter > 0;
|
||
// find the index set of free and active variables at the GCP.
|
||
freev(n, ref nfree, index, _index_offset, ref nenter, ref ileave, indx2, _indx2_offset,
|
||
iwhere, _iwhere_offset, ref wrk, updatd, cnstnd, iprint, iter);
|
||
nact = (n - nfree);
|
||
// If there are no free variables or B=theta*I,
|
||
// then skip the subspace minimization.
|
||
//
|
||
if (nfree == 0 || col == 0) {
|
||
goto L555;
|
||
}
|
||
// c Subspace minimization.
|
||
// c Form the LEL^T factorization of the indefinite
|
||
// c matrix K = [-D -Y'ZZ'Y/theta L_a'-R_z' ]
|
||
// c [L_a -R_z theta*S'AA'S ]
|
||
// c where E = [-I 0]
|
||
// c [ 0 I]
|
||
if (wrk) {
|
||
formk(n, nfree, index, _index_offset, nenter,
|
||
ileave, indx2, _indx2_offset, iupdat, updatd, wn, _wn_offset,
|
||
snd, _snd_offset, m, ws, _ws_offset, wy, _wy_offset, sy, _sy_offset,
|
||
theta, col, head, ref info);
|
||
}
|
||
// compute r=-Z'B(xcp-xk)-Z'g (using wa(2m+1)=W'(xcp-x) from 'cauchy')
|
||
cmprlb(n, m, x, _x_offset, g, _g_offset, ws, _ws_offset, wy, _wy_offset,
|
||
sy, _sy_offset, wt, _wt_offset, z, _z_offset, r, _r_offset, wa, _wa_offset,
|
||
index, _index_offset, theta, col, head, nfree, cnstnd, ref info);
|
||
// c-jlm-jn call the direct method.
|
||
subsm(n, m, nfree, index, _index_offset, l, _l_offset, u, _u_offset,
|
||
nbd, _nbd_offset, z, _z_offset, r, _r_offset, xp, _xp_offset, ws, _ws_offset,
|
||
wy, _wy_offset, theta, x, _x_offset, g, _g_offset, col, head,
|
||
ref iword, wa, _wa_offset, wn, _wn_offset, iprint, ref info);
|
||
|
||
L555:
|
||
// c Line search and optimality tests.
|
||
// c Generate the search direction d:=z-x.
|
||
for (i = 1; i <= n; i++) {
|
||
d[(i - (1)) + _d_offset] = (z[(i - (1)) + _z_offset] - x[(i - (1)) + _x_offset]);
|
||
}
|
||
|
||
L666:
|
||
lnsrlb(n, l, _l_offset, u, _u_offset, nbd, _nbd_offset, x, _x_offset,
|
||
f, ref fold, ref gd, ref gdold, g, _g_offset, d, _d_offset, r, _r_offset, t, _t_offset,
|
||
z, _z_offset, ref stp, ref dnorm, ref dtd, ref xstep, ref stpmx, iter, ref ifun,
|
||
ref iback, ref nfgv, ref info, ref task, boxed, cnstnd, ref csave, isave,
|
||
(22 - (1)) + _isave_offset, dsave, (17 - (1)) + _dsave_offset);
|
||
|
||
if (iback >= 20)
|
||
{
|
||
// restore the previous iterate.
|
||
dcopy(n, t, _t_offset, 1, x, _x_offset, 1);
|
||
dcopy(n, r, _r_offset, 1, g, _g_offset, 1);
|
||
f = fold;
|
||
if ((col == 0))
|
||
{
|
||
info = -9;
|
||
// restore the actual number of f and g evaluations etc.
|
||
nfgv = (nfgv - 1);
|
||
ifun = (ifun - 1);
|
||
iback = (iback - 1);
|
||
task = Task.Abnormal;
|
||
iter = (iter + 1);
|
||
goto L999;
|
||
}
|
||
else
|
||
{
|
||
nfgv = (nfgv - 1);
|
||
info = 0;
|
||
col = 0;
|
||
head = 1;
|
||
theta = 1.0;
|
||
iupdat = 0;
|
||
updatd = false;
|
||
task = Task.Restart_LN;
|
||
goto L222;
|
||
}
|
||
}
|
||
else if (task == Task.FG_LN)
|
||
{
|
||
// return to the driver for calculating f and g; reenter at 666.
|
||
goto L1000;
|
||
}
|
||
else
|
||
{
|
||
// calculate and print out the quantities related to the new X.
|
||
iter = (iter + 1);
|
||
// Compute the infinity norm of the projected (-)gradient.
|
||
projgr(n, l, _l_offset, u, _u_offset, nbd, _nbd_offset, x, _x_offset, g, _g_offset, ref sbgnrm);
|
||
goto L1000;
|
||
}
|
||
|
||
L777:
|
||
// c Test for termination.
|
||
if ((sbgnrm <= pgtol))
|
||
{
|
||
// terminate the algorithm.
|
||
task = Task.Convergence;
|
||
goto L999;
|
||
}
|
||
|
||
ddum = System.Math.Max(System.Math.Abs(fold), System.Math.Max(System.Math.Abs(f), 1.0));
|
||
|
||
if ((((fold - f)) <= (tol * ddum)))
|
||
{
|
||
// terminate the algorithm.
|
||
task = Task.Convergence;
|
||
|
||
if ((iback >= 10))
|
||
{
|
||
info = -5;
|
||
}
|
||
|
||
// i.e., to issue a warning if iback>10 in the line search.
|
||
goto L999;
|
||
}
|
||
|
||
//
|
||
// Compute d=newx-oldx, r=newg-oldg, rr=y'y and dr=y's.
|
||
//
|
||
for (i = 1; i <= n; i++)
|
||
{
|
||
r[(i - (1)) + _r_offset] = (g[(i - (1)) + _g_offset] - r[(i - (1)) + _r_offset]);
|
||
}
|
||
|
||
rr = ddot(n, r, _r_offset, 1, r, _r_offset, 1);
|
||
|
||
if ((stp == 1.0))
|
||
{
|
||
dr = (gd - gdold);
|
||
ddum = (-(gdold));
|
||
}
|
||
else
|
||
{
|
||
dr = (((gd - gdold)) * stp);
|
||
dscal(n, stp, d, _d_offset, 1);
|
||
ddum = (-((gdold * stp)));
|
||
}
|
||
|
||
if ((dr <= (epsmch * ddum)))
|
||
{
|
||
// skip the L-BFGS update.
|
||
nskip = (nskip + 1);
|
||
updatd = false;
|
||
|
||
|
||
if ((iprint >= 1))
|
||
{
|
||
// DISPLAY: dr, ddum
|
||
// DISPLAY: ' ys=',1p,e10.3,' -gs=',1P,E10.3,' BFGS update SKIPPED'"
|
||
}
|
||
|
||
goto L888;
|
||
}
|
||
|
||
//
|
||
// cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
|
||
// c
|
||
// c Update the L-BFGS matrix.
|
||
// c
|
||
// cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
|
||
//
|
||
updatd = true;
|
||
iupdat = (iupdat + 1);
|
||
|
||
//
|
||
// c Update matrices WS and WY and form the middle matrix in B.
|
||
//
|
||
matupd(n, m, ws, _ws_offset, wy, _wy_offset, sy, _sy_offset,
|
||
ss, _ss_offset, d, _d_offset, r, _r_offset, ref itail, iupdat, ref col,
|
||
ref head, ref theta, rr, dr, stp, dtd);
|
||
|
||
//
|
||
// c Form the upper half of the pds T = theta*SS + L*D^(-1)*L';
|
||
// c Store T in the upper triangular of the array wt;
|
||
// c Cholesky factorize T to J*J' with
|
||
// c J' stored in the upper triangular of wt.
|
||
//
|
||
formt(m, wt, _wt_offset, sy, _sy_offset, ss,
|
||
_ss_offset, col, theta, ref info);
|
||
|
||
//
|
||
// Now the inverse of the middle matrix in B is
|
||
//
|
||
// [ D^(1/2) O ] [ -D^(1/2) D^(-1/2)*L' ]
|
||
// [ -L*D^(-1/2) J ] [ 0 J' ]
|
||
//
|
||
L888:
|
||
//
|
||
// c -------------------- the end of the loop -----------------------------
|
||
//
|
||
goto L222;
|
||
|
||
L999:
|
||
|
||
|
||
L1000:
|
||
//
|
||
// Save local variables.
|
||
//
|
||
lsave[(1 - (1)) + _lsave_offset] = prjctd;
|
||
lsave[(2 - (1)) + _lsave_offset] = cnstnd;
|
||
lsave[(3 - (1)) + _lsave_offset] = boxed;
|
||
lsave[(4 - (1)) + _lsave_offset] = updatd;
|
||
//
|
||
isave[(1 - (1)) + _isave_offset] = nintol;
|
||
isave[(3 - (1)) + _isave_offset] = itfile;
|
||
isave[(4 - (1)) + _isave_offset] = iback;
|
||
isave[(5 - (1)) + _isave_offset] = nskip;
|
||
isave[(6 - (1)) + _isave_offset] = head;
|
||
isave[(7 - (1)) + _isave_offset] = col;
|
||
isave[(8 - (1)) + _isave_offset] = itail;
|
||
isave[(9 - (1)) + _isave_offset] = iter;
|
||
isave[(10 - (1)) + _isave_offset] = iupdat;
|
||
isave[(12 - (1)) + _isave_offset] = nseg;
|
||
isave[(13 - (1)) + _isave_offset] = nfgv;
|
||
isave[(14 - (1)) + _isave_offset] = info;
|
||
isave[(15 - (1)) + _isave_offset] = ifun;
|
||
isave[(16 - (1)) + _isave_offset] = iword;
|
||
isave[(17 - (1)) + _isave_offset] = nfree;
|
||
isave[(18 - (1)) + _isave_offset] = nact;
|
||
isave[(19 - (1)) + _isave_offset] = ileave;
|
||
isave[(20 - (1)) + _isave_offset] = nenter;
|
||
//
|
||
dsave[(1 - (1)) + _dsave_offset] = theta;
|
||
dsave[(2 - (1)) + _dsave_offset] = fold;
|
||
dsave[(3 - (1)) + _dsave_offset] = tol;
|
||
dsave[(4 - (1)) + _dsave_offset] = dnorm;
|
||
dsave[(5 - (1)) + _dsave_offset] = epsmch;
|
||
dsave[(6 - (1)) + _dsave_offset] = cpu1;
|
||
dsave[(7 - (1)) + _dsave_offset] = cachyt;
|
||
dsave[(8 - (1)) + _dsave_offset] = sbtime;
|
||
dsave[(9 - (1)) + _dsave_offset] = lnscht;
|
||
dsave[(10 - (1)) + _dsave_offset] = time1;
|
||
dsave[(11 - (1)) + _dsave_offset] = gd;
|
||
dsave[(12 - (1)) + _dsave_offset] = stpmx;
|
||
dsave[(13 - (1)) + _dsave_offset] = sbgnrm;
|
||
dsave[(14 - (1)) + _dsave_offset] = stp;
|
||
dsave[(15 - (1)) + _dsave_offset] = gdold;
|
||
dsave[(16 - (1)) + _dsave_offset] = dtd;
|
||
|
||
return;
|
||
}
|
||
|
||
//
|
||
// c======================= The end of lnsrlb =============================
|
||
//
|
||
//
|
||
//
|
||
// c ************
|
||
// c
|
||
// c Subroutine matupd
|
||
// c
|
||
// c This subroutine updates matrices WS and WY, and forms the
|
||
// c middle matrix in B.
|
||
// c
|
||
// c Subprograms called:
|
||
// c
|
||
// c Linpack ... dcopy,
|
||
// c
|
||
// c
|
||
// c * * *
|
||
// c
|
||
// c NEOS, November 1994. (Latest revision June 1996.)
|
||
// c Optimization Technology Center.
|
||
// c Argonne National Laboratory and Northwestern University.
|
||
// c Written by
|
||
// c Ciyou Zhu
|
||
// c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
|
||
// c
|
||
// c
|
||
// c ************
|
||
//
|
||
//
|
||
// c Set pointers for matrices WS and WY.
|
||
//
|
||
internal static void matupd(int n,
|
||
int m, double[] ws, int _ws_offset, double[] wy, int _wy_offset,
|
||
double[] sy, int _sy_offset, double[] ss, int _ss_offset, double[] d, int _d_offset,
|
||
double[] r, int _r_offset, ref int itail, int iupdat, ref int col,
|
||
ref int head, ref double theta, double rr, double dr, double stp, double dtd)
|
||
{
|
||
|
||
int j = 0;
|
||
int pointr = 0;
|
||
|
||
if ((iupdat <= m))
|
||
{
|
||
col = iupdat;
|
||
itail = ((((head + iupdat) - 2)) % (m) + 1);
|
||
}
|
||
else
|
||
{
|
||
itail = ((itail) % (m) + 1);
|
||
head = ((head) % (m) + 1);
|
||
}
|
||
|
||
//
|
||
// c Update matrices WS and WY.
|
||
//
|
||
dcopy(n, d, _d_offset, 1, ws, (1 - (1)) + (itail - (1)) * (n) + _ws_offset, 1);
|
||
dcopy(n, r, _r_offset, 1, wy, (1 - (1)) + (itail - (1)) * (n) + _wy_offset, 1);
|
||
|
||
//
|
||
// c Set theta=yy/ys.
|
||
//
|
||
theta = (rr / dr);
|
||
//
|
||
// c Form the middle matrix in B.
|
||
//
|
||
// c update the upper triangle of SS,
|
||
// c and the lower triangle of SY:
|
||
|
||
if ((iupdat > m))
|
||
{
|
||
// c move old information
|
||
{
|
||
for (j = 1; j <= (col - 1); j++)
|
||
{
|
||
dcopy(j, ss, (2 - (1)) + ((j + 1) - (1)) * (m)
|
||
+ _ss_offset, 1, ss, (1 - (1)) + (j - (1)) * (m) + _ss_offset, 1);
|
||
dcopy((col - j), sy, ((j + 1) - (1)) + ((j + 1)
|
||
- (1)) * (m) + _sy_offset, 1, sy, (j - (1)) + (j - (1)) * (m) + _sy_offset, 1);
|
||
}
|
||
}
|
||
}
|
||
// c add new information: the last row of SY
|
||
// c and the last column of SS:
|
||
pointr = head;
|
||
{
|
||
for (j = 1; j <= (col - 1); j++)
|
||
{
|
||
sy[(col - (1)) + (j - (1)) * (m) + _sy_offset] =
|
||
ddot(n,
|
||
d, _d_offset, 1,
|
||
wy, (1 - (1)) + (pointr - (1)) * (n) + _wy_offset, 1);
|
||
|
||
ss[(j - (1)) + (col - (1)) * (m) + _ss_offset] =
|
||
ddot(n,
|
||
ws, (1 - (1)) + (pointr - (1)) * (n) + _ws_offset, 1,
|
||
d, _d_offset, 1);
|
||
|
||
pointr = ((pointr) % (m) + 1);
|
||
}
|
||
}
|
||
if ((stp == 1.0))
|
||
{
|
||
ss[(col - (1)) + (col - (1)) * (m) + _ss_offset] = dtd;
|
||
}
|
||
else
|
||
{
|
||
ss[(col - (1)) + (col - (1)) * (m) + _ss_offset] = ((stp * stp) * dtd);
|
||
}
|
||
|
||
sy[(col - (1)) + (col - (1)) * (m) + _sy_offset] = dr;
|
||
|
||
return;
|
||
}
|
||
|
||
//
|
||
// c======================= The end of prn3lb =============================
|
||
//
|
||
//
|
||
//
|
||
// c ************
|
||
// c
|
||
// c Subroutine projgr
|
||
// c
|
||
// c This subroutine computes the infinity norm of the projected
|
||
// c gradient.
|
||
// c
|
||
// c
|
||
// c * * *
|
||
// c
|
||
// c NEOS, November 1994. (Latest revision June 1996.)
|
||
// c Optimization Technology Center.
|
||
// c Argonne National Laboratory and Northwestern University.
|
||
// c Written by
|
||
// c Ciyou Zhu
|
||
// c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
|
||
// c
|
||
// c
|
||
// c ************
|
||
//
|
||
//
|
||
internal static void projgr(int n,
|
||
double[] l, int _l_offset,
|
||
double[] u, int _u_offset,
|
||
int[] nbd, int _nbd_offset,
|
||
double[] x, int _x_offset,
|
||
double[] g, int _g_offset,
|
||
ref double sbgnrm)
|
||
{
|
||
|
||
int i = 0;
|
||
double gi = 0.0d;
|
||
sbgnrm = 0.0;
|
||
{
|
||
for (i = 1; i <= n; i++)
|
||
{
|
||
gi = g[(i - (1)) + _g_offset];
|
||
if ((nbd[(i - (1)) + _nbd_offset] != 0))
|
||
{
|
||
if ((gi < 0.0))
|
||
{
|
||
if ((nbd[(i - (1)) + _nbd_offset] >= 2))
|
||
{
|
||
gi = System.Math.Max(((x[(i - (1)) + _x_offset] - u[(i - (1)) + _u_offset])), gi);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ((nbd[(i - (1)) + _nbd_offset] <= 2))
|
||
{
|
||
gi = System.Math.Min(((x[(i - (1)) + _x_offset] - l[(i - (1)) + _l_offset])), gi);
|
||
}
|
||
}
|
||
}
|
||
sbgnrm = System.Math.Max(sbgnrm, System.Math.Abs(gi));
|
||
}
|
||
}
|
||
}
|
||
|
||
// c
|
||
// c L-BFGS-B is released under the <20>New BSD License<73> (aka <20>Modified
|
||
// c or <20>3-clause license<73>)
|
||
// c Please read attached file License.txt
|
||
// c
|
||
// c=========== L-BFGS-B (version 3.0. April 25, 2011 =================
|
||
// c
|
||
// c This is a modified version of L-BFGS-B. Minor changes in the updat
|
||
// c code appear preceded by a line comment as follows
|
||
// c
|
||
// c c-jlm-jn
|
||
// c
|
||
// c Major changes are described in the accompanying paper:
|
||
// c
|
||
// c Jorge Nocedal and Jose Luis Morales, Remark on "Algorithm 778:
|
||
// c L-BFGS-B: Fortran Subroutines for Large-Scale Bound Constraine
|
||
// c Optimization" (2011). To appear in ACM Transactions on
|
||
// c Mathematical Software,
|
||
// c
|
||
// c The paper describes an improvement and a correction to Algorithm 7
|
||
// c It is shown that the performance of the algorithm can be improved
|
||
// c significantly by making a relatively simple modication to the subs
|
||
// c minimization phase. The correction concerns an error caused by the
|
||
// c of routine dpmeps to estimate machine precision.
|
||
// c
|
||
// c The total work space **wa** required by the new version is
|
||
// c
|
||
// c 2*m*n + 11m*m + 5*n + 8*m
|
||
// c
|
||
// c the old version required
|
||
// c
|
||
// c 2*m*n + 12m*m + 4*n + 12*m
|
||
// c
|
||
// c
|
||
// c J. Nocedal Department of Electrical Engineering and
|
||
// c Computer Science.
|
||
// c Northwestern University. Evanston, IL. USA
|
||
// c
|
||
// c
|
||
// c J.L Morales Departamento de Matematicas,
|
||
// c Instituto Tecnologico Autonomo de Mexico
|
||
// c Mexico D.F. Mexico.
|
||
// c
|
||
// c March 2011
|
||
// c
|
||
// c=======================================================================
|
||
//
|
||
// c
|
||
// c-jlm-jn
|
||
//
|
||
//
|
||
// c ************
|
||
// c
|
||
// c Subroutine setulb
|
||
// c
|
||
// c This subroutine partitions the working arrays wa and iwa, and
|
||
// c then uses the limited memory BFGS method to solve the bound
|
||
// c constrained optimization problem by calling mainlb.
|
||
// c (The direct method will be used in the subspace minimization.)
|
||
// c
|
||
// c n is an integer variable.
|
||
// c On entry n is the dimension of the problem.
|
||
// c On exit n is unchanged.
|
||
// c
|
||
// c m is an integer variable.
|
||
// c On entry m is the maximum number of variable metric corrections
|
||
// c
|
||
// c used to define the limited memory matrix.
|
||
// c On exit m is unchanged.
|
||
// c
|
||
// c x is a double precision array of dimension n.
|
||
// c On entry x is an approximation to the solution.
|
||
// c On exit x is the current approximation.
|
||
// c
|
||
// c l is a double precision array of dimension n.
|
||
// c On entry l is the lower bound on x.
|
||
// c On exit l is unchanged.
|
||
// c
|
||
// c u is a double precision array of dimension n.
|
||
// c On entry u is the upper bound on x.
|
||
// c On exit u is unchanged.
|
||
// c
|
||
// c nbd is an integer array of dimension n.
|
||
// c On entry nbd represents the type of bounds imposed on the
|
||
// c variables, and must be specified as follows:
|
||
// c nbd(i)=0 if x(i) is unbounded,
|
||
// c 1 if x(i) has only a lower bound,
|
||
// c 2 if x(i) has both lower and upper bounds, and
|
||
// c 3 if x(i) has only an upper bound.
|
||
// c On exit nbd is unchanged.
|
||
// c
|
||
// c f is a double precision variable.
|
||
// c On first entry f is unspecified.
|
||
// c On final exit f is the value of the function at x.
|
||
// c
|
||
// c g is a double precision array of dimension n.
|
||
// c On first entry g is unspecified.
|
||
// c On final exit g is the value of the gradient at x.
|
||
// c
|
||
// c factr is a double precision variable.
|
||
// c On entry factr >= 0 is specified by the user. The iteration
|
||
// c will stop when
|
||
// c
|
||
// c (f^k - f^{k+1})/max{|f^k|,|f^{k+1}|,1} <= factr*epsmch
|
||
// c
|
||
// c where epsmch is the machine precision, which is automatically
|
||
// c generated by the code. Typical values for factr: 1.d+12 for
|
||
// c low accuracy; 1.d+7 for moderate accuracy; 1.d+1 for extremely
|
||
// c high accuracy.
|
||
// c On exit factr is unchanged.
|
||
// c
|
||
// c pgtol is a double precision variable.
|
||
// c On entry pgtol >= 0 is specified by the user. The iteration
|
||
// c will stop when
|
||
// c
|
||
// c max{|proj g_i | i = 1, ..., n} <= pgtol
|
||
// c
|
||
// c where pg_i is the ith component of the projected gradient.
|
||
|
||
// c On exit pgtol is unchanged.
|
||
// c
|
||
// c wa is a double precision working array of length
|
||
// c (2mmax + 5)nmax + 12mmax^2 + 12mmax.
|
||
// c
|
||
// c iwa is an integer working array of length 3nmax.
|
||
// c
|
||
// c task is a working string of characters of length 60 indicating
|
||
// c the current job when entering and quitting this subroutine.
|
||
// c
|
||
// c iprint is an integer variable that must be set by the user.
|
||
// c It controls the frequency and type of output generated:
|
||
// c iprint<0 no output is generated;
|
||
// c iprint=0 print only one line at the last iteration;
|
||
// c 0<iprint<99 print also f and |proj g| every iprint iterations;
|
||
// c iprint=99 print details of every iteration except n-vectors;
|
||
// c iprint=100 print also the changes of active set and final x;
|
||
// c iprint>100 print details of every iteration including x and g;
|
||
// c When iprint > 0, the file iterate.dat will be created to
|
||
// c summarize the iteration.
|
||
// c
|
||
// c csave is a working string of characters of length 60.
|
||
// c
|
||
// c lsave is a logical working array of dimension 4.
|
||
// c On exit with 'task' = NEW_X, the following information is
|
||
// c available:
|
||
// c If lsave(1) = .true. then the initial X has been replaced by
|
||
// c its projection in the feasible set
|
||
// c If lsave(2) = .true. then the problem is constrained;
|
||
// c If lsave(3) = .true. then each variable has upper and lower
|
||
// c bounds;
|
||
// c
|
||
// c isave is an integer working array of dimension 44.
|
||
// c On exit with 'task' = NEW_X, the following information is
|
||
// c available:
|
||
// c isave(22) = the total number of intervals explored in the
|
||
// c search of Cauchy points;
|
||
// c isave(26) = the total number of skipped BFGS updates before
|
||
// c the current iteration;
|
||
// c isave(30) = the number of current iteration;
|
||
// c isave(31) = the total number of BFGS updates prior the current
|
||
// c iteration;
|
||
// c isave(33) = the number of intervals explored in the search of
|
||
// c Cauchy point in the current iteration;
|
||
// c isave(34) = the total number of function and gradient
|
||
// c evaluations;
|
||
// c isave(36) = the number of function value or gradient
|
||
// c evaluations in the current iteration;
|
||
// c if isave(37) = 0 then the subspace argmin is within the box;
|
||
// c if isave(37) = 1 then the subspace argmin is beyond the box;
|
||
// c isave(38) = the number of free variables in the current
|
||
// c iteration;
|
||
// c isave(39) = the number of active constraints in the current
|
||
// c iteration;
|
||
// c n + 1 - isave(40) = the number of variables leaving the set of
|
||
// c active constraints in the current iteration;
|
||
// c isave(41) = the number of variables entering the set of active
|
||
// c constraints in the current iteration.
|
||
// c
|
||
// c dsave is a double precision working array of dimension 29.
|
||
// c On exit with 'task' = NEW_X, the following information is
|
||
// c available:
|
||
// c dsave(1) = current 'theta' in the BFGS matrix;
|
||
// c dsave(2) = f(x) in the previous iteration;
|
||
// c dsave(3) = factr*epsmch;
|
||
// c dsave(4) = 2-norm of the line search direction vector;
|
||
// c dsave(5) = the machine precision epsmch generated by the code;
|
||
// c dsave(7) = the accumulated time spent on searching for
|
||
// c Cauchy points;
|
||
// c dsave(8) = the accumulated time spent on
|
||
// c subspace minimization;
|
||
// c dsave(9) = the accumulated time spent on line search;
|
||
// c dsave(11) = the slope of the line search function at
|
||
// c the current point of line search;
|
||
// c dsave(12) = the maximum relative step length imposed in
|
||
// c line search;
|
||
// c dsave(13) = the infinity norm of the projected gradient;
|
||
// c dsave(14) = the relative step length in the line search;
|
||
// c dsave(15) = the slope of the line search function at
|
||
// c the starting point of the line search;
|
||
// c dsave(16) = the square of the 2-norm of the line search
|
||
// c direction vector.
|
||
// c
|
||
// c Subprograms called:
|
||
// c
|
||
// c L-BFGS-B Library ... mainlb.
|
||
// c
|
||
// c
|
||
// c References:
|
||
// c
|
||
// c [1] R. H. Byrd, P. Lu, J. Nocedal and C. Zhu, ``A limited
|
||
// c memory algorithm for bound constrained optimization'',
|
||
// c SIAM J. Scientific Computing 16 (1995), no. 5, pp. 1190--1208.
|
||
// c
|
||
// c [2] C. Zhu, R.H. Byrd, P. Lu, J. Nocedal, ``L-BFGS-B: a
|
||
// c limited memory FORTRAN code for solving bound constrained
|
||
// c optimization problems'', Tech. Report, NAM-11, EECS Department,
|
||
// c Northwestern University, 1994.
|
||
// c
|
||
// c (Postscript files of these papers are available via anonymous
|
||
// c ftp to eecs.nwu.edu in the directory pub/lbfgs/lbfgs_bcm.)
|
||
// c
|
||
// c * * *
|
||
// c
|
||
// c NEOS, November 1994. (Latest revision June 1996.)
|
||
// c Optimization Technology Center.
|
||
// c Argonne National Laboratory and Northwestern University.
|
||
// c Written by
|
||
// c Ciyou Zhu
|
||
// c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
|
||
// c
|
||
// c
|
||
// c ************
|
||
//
|
||
internal static void setulb(int n,
|
||
int m,
|
||
double[] x, int _x_offset,
|
||
double[] l, int _l_offset,
|
||
double[] u, int _u_offset,
|
||
int[] nbd, int _nbd_offset,
|
||
ref double f,
|
||
double[] g, int _g_offset,
|
||
double factr,
|
||
double pgtol,
|
||
double[] wa, int _wa_offset,
|
||
int[] iwa, int _iwa_offset,
|
||
ref Task task,
|
||
int iprint,
|
||
ref Task csave,
|
||
bool[] lsave, int _lsave_offset,
|
||
int[] isave, int _isave_offset,
|
||
double[] dsave, int _dsave_offset)
|
||
{
|
||
|
||
int lws = 0;
|
||
int lr = 0;
|
||
int lz = 0;
|
||
int lt = 0;
|
||
int ld = 0;
|
||
int lxp = 0;
|
||
int lwa = 0;
|
||
int lwy = 0;
|
||
int lsy = 0;
|
||
int lss = 0;
|
||
int lwt = 0;
|
||
int lwn = 0;
|
||
int lsnd = 0;
|
||
|
||
if (task == Task.Start)
|
||
{
|
||
isave[(1 - (1)) + _isave_offset] = (m * n);
|
||
isave[(2 - (1)) + _isave_offset] = ((int)System.Math.Pow(m, 2));
|
||
isave[(3 - (1)) + _isave_offset] = (4 * ((int)System.Math.Pow(m, 2)));
|
||
isave[(4 - (1)) + _isave_offset] = 1;
|
||
isave[(5 - (1)) + _isave_offset] = (isave[(4 - (1)) + _isave_offset] + isave[(1 - (1)) + _isave_offset]);
|
||
isave[(6 - (1)) + _isave_offset] = (isave[(5 - (1)) + _isave_offset] + isave[(1 - (1)) + _isave_offset]);
|
||
isave[(7 - (1)) + _isave_offset] = (isave[(6 - (1)) + _isave_offset] + isave[(2 - (1)) + _isave_offset]);
|
||
isave[(8 - (1)) + _isave_offset] = (isave[(7 - (1)) + _isave_offset] + isave[(2 - (1)) + _isave_offset]);
|
||
isave[(9 - (1)) + _isave_offset] = (isave[(8 - (1)) + _isave_offset] + isave[(2 - (1)) + _isave_offset]);
|
||
isave[(10 - (1)) + _isave_offset] = (isave[(9 - (1)) + _isave_offset] + isave[(3 - (1)) + _isave_offset]);
|
||
isave[(11 - (1)) + _isave_offset] = (isave[(10 - (1)) + _isave_offset] + isave[(3 - (1)) + _isave_offset]);
|
||
isave[(12 - (1)) + _isave_offset] = (isave[(11 - (1)) + _isave_offset] + n);
|
||
isave[(13 - (1)) + _isave_offset] = (isave[(12 - (1)) + _isave_offset] + n);
|
||
isave[(14 - (1)) + _isave_offset] = (isave[(13 - (1)) + _isave_offset] + n);
|
||
isave[(15 - (1)) + _isave_offset] = (isave[(14 - (1)) + _isave_offset] + n);
|
||
isave[(16 - (1)) + _isave_offset] = (isave[(15 - (1)) + _isave_offset] + n);
|
||
}
|
||
lws = isave[(4 - (1)) + _isave_offset];
|
||
lwy = isave[(5 - (1)) + _isave_offset];
|
||
lsy = isave[(6 - (1)) + _isave_offset];
|
||
lss = isave[(7 - (1)) + _isave_offset];
|
||
lwt = isave[(8 - (1)) + _isave_offset];
|
||
lwn = isave[(9 - (1)) + _isave_offset];
|
||
lsnd = isave[(10 - (1)) + _isave_offset];
|
||
lz = isave[(11 - (1)) + _isave_offset];
|
||
lr = isave[(12 - (1)) + _isave_offset];
|
||
ld = isave[(13 - (1)) + _isave_offset];
|
||
lt = isave[(14 - (1)) + _isave_offset];
|
||
lxp = isave[(15 - (1)) + _isave_offset];
|
||
lwa = isave[(16 - (1)) + _isave_offset];
|
||
//
|
||
mainlb(n, m, x, _x_offset, l, _l_offset, u, _u_offset, nbd,
|
||
_nbd_offset, ref f, g, _g_offset, factr, pgtol, wa, (lws - (1)) + _wa_offset,
|
||
wa, (lwy - (1)) + _wa_offset, wa, (lsy - (1)) + _wa_offset, wa,
|
||
(lss - (1)) + _wa_offset, wa, (lwt - (1)) + _wa_offset, wa,
|
||
(lwn - (1)) + _wa_offset, wa, (lsnd - (1)) + _wa_offset, wa,
|
||
(lz - (1)) + _wa_offset, wa, (lr - (1)) + _wa_offset, wa,
|
||
(ld - (1)) + _wa_offset, wa, (lt - (1)) + _wa_offset, wa,
|
||
(lxp - (1)) + _wa_offset, wa, (lwa - (1)) + _wa_offset, iwa,
|
||
(1 - (1)) + _iwa_offset, iwa, ((n + 1) - (1)) + _iwa_offset,
|
||
iwa, (((2 * n) + 1) - (1)) + _iwa_offset, ref task, iprint, ref csave,
|
||
lsave, _lsave_offset, isave, (22 - (1)) + _isave_offset, dsave,
|
||
_dsave_offset);
|
||
}
|
||
|
||
//
|
||
// c======================= The end of projgr =============================
|
||
//
|
||
//
|
||
// c ******************************************************************
|
||
// c
|
||
// c This routine contains the major changes in the updated version.
|
||
// c The changes are described in the accompanying paper
|
||
// c
|
||
// c Jose Luis Morales, Jorge Nocedal
|
||
// c "Remark On Algorithm 788: L-BFGS-B: Fortran Subroutines for Large
|
||
// c Bound Constrained Optimization". Decemmber 27, 2010.
|
||
// c
|
||
// c J.L. Morales Departamento de Matematicas,
|
||
// c Instituto Tecnologico Autonomo de Mexico
|
||
// c Mexico D.F.
|
||
// c
|
||
// c J, Nocedal Department of Electrical Engineering and
|
||
// c Computer Science.
|
||
// c Northwestern University. Evanston, IL. USA
|
||
// c
|
||
// c January 17, 2011
|
||
// c
|
||
// c *****************************************************************
|
||
// c
|
||
// c
|
||
// c Subroutine subsm
|
||
// c
|
||
// c Given xcp, l, u, r, an index set that specifies
|
||
// c the active set at xcp, and an l-BFGS matrix B
|
||
// c (in terms of WY, WS, SY, WT, head, col, and theta),
|
||
// c this subroutine computes an approximate solution
|
||
// c of the subspace problem
|
||
// c
|
||
// c (P) min Q(x) = r'(x-xcp) + 1/2 (x-xcp)' B (x-xcp)
|
||
// c
|
||
// c subject to l<=x<=u
|
||
// c x_i=xcp_i for all i in A(xcp)
|
||
// c
|
||
// c along the subspace unconstrained Newton direction
|
||
// c
|
||
// c d = -(Z'BZ)^(-1) r.
|
||
// c
|
||
// c The formula for the Newton direction, given the L-BFGS matrix
|
||
// c and the Sherman-Morrison formula, is
|
||
// c
|
||
// c d = (1/theta)r + (1/theta*2) Z'WK^(-1)W'Z r.
|
||
// c
|
||
// c where
|
||
// c K = [-D -Y'ZZ'Y/theta L_a'-R_z' ]
|
||
// c [L_a -R_z theta*S'AA'S ]
|
||
// c
|
||
// c Note that this procedure for computing d differs
|
||
// c from that described in [1]. One can show that the matrix K is
|
||
// c equal to the matrix M^[-1]N in that paper.
|
||
// c
|
||
// c n is an integer variable.
|
||
// c On entry n is the dimension of the problem.
|
||
// c On exit n is unchanged.
|
||
// c
|
||
// c m is an integer variable.
|
||
// c On entry m is the maximum number of variable metric corrections
|
||
|
||
// c used to define the limited memory matrix.
|
||
// c On exit m is unchanged.
|
||
// c
|
||
// c nsub is an integer variable.
|
||
// c On entry nsub is the number of free variables.
|
||
// c On exit nsub is unchanged.
|
||
// c
|
||
// c ind is an integer array of dimension nsub.
|
||
// c On entry ind specifies the coordinate indices of free variables.
|
||
// c On exit ind is unchanged.
|
||
// c
|
||
// c l is a double precision array of dimension n.
|
||
// c On entry l is the lower bound of x.
|
||
// c On exit l is unchanged.
|
||
// c
|
||
// c u is a double precision array of dimension n.
|
||
// c On entry u is the upper bound of x.
|
||
// c On exit u is unchanged.
|
||
// c
|
||
// c nbd is a integer array of dimension n.
|
||
// c On entry nbd represents the type of bounds imposed on the
|
||
// c variables, and must be specified as follows:
|
||
// c nbd(i)=0 if x(i) is unbounded,
|
||
// c 1 if x(i) has only a lower bound,
|
||
// c 2 if x(i) has both lower and upper bounds, and
|
||
// c 3 if x(i) has only an upper bound.
|
||
// c On exit nbd is unchanged.
|
||
// c
|
||
// c x is a double precision array of dimension n.
|
||
// c On entry x specifies the Cauchy point xcp.
|
||
// c On exit x(i) is the minimizer of Q over the subspace of
|
||
// c free variables.
|
||
// c
|
||
// c d is a double precision array of dimension n.
|
||
// c On entry d is the reduced gradient of Q at xcp.
|
||
// c On exit d is the Newton direction of Q.
|
||
// c
|
||
// c xp is a double precision array of dimension n.
|
||
// c used to safeguard the projected Newton direction
|
||
// c
|
||
// c xx is a double precision array of dimension n
|
||
// c On entry it holds the current iterate
|
||
// c On output it is unchanged
|
||
//
|
||
// c gg is a double precision array of dimension n
|
||
// c On entry it holds the gradient at the current iterate
|
||
// c On output it is unchanged
|
||
// c
|
||
// c ws and wy are double precision arrays;
|
||
// c theta is a double precision variable;
|
||
// c col is an integer variable;
|
||
// c head is an integer variable.
|
||
// c On entry they store the information defining the
|
||
// c limited memory BFGS matrix:
|
||
// c ws(n,m) stores S, a set of s-vectors;
|
||
// c wy(n,m) stores Y, a set of y-vectors;
|
||
// c theta is the scaling factor specifying B_0 = theta I;
|
||
// c col is the number of variable metric corrections stored;
|
||
// c head is the location of the 1st s- (or y-) vector in S (or Y).
|
||
// c On exit they are unchanged.
|
||
// c
|
||
// c iword is an integer variable.
|
||
// c On entry iword is unspecified.
|
||
// c On exit iword specifies the status of the subspace solution.
|
||
// c iword = 0 if the solution is in the box,
|
||
// c 1 if some bound is encountered.
|
||
// c
|
||
// c wv is a double precision working array of dimension 2m.
|
||
// c
|
||
// c wn is a double precision array of dimension 2m x 2m.
|
||
// c On entry the upper triangle of wn stores the LEL^T factorization
|
||
// c of the indefinite matrix
|
||
// c
|
||
// c K = [-D -Y'ZZ'Y/theta L_a'-R_z' ]
|
||
// c [L_a -R_z theta*S'AA'S ]
|
||
// c where E = [-I 0]
|
||
// c [ 0 I]
|
||
// c On exit wn is unchanged.
|
||
// c
|
||
// c iprint is an INTEGER variable that must be set by the user.
|
||
// c It controls the frequency and type of output generated:
|
||
// c iprint<0 no output is generated;
|
||
// c iprint=0 print only one line at the last iteration;
|
||
// c 0<iprint<99 print also f and |proj g| every iprint iterations;
|
||
|
||
// c iprint=99 print details of every iteration except n-vectors;
|
||
|
||
// c iprint=100 print also the changes of active set and final x;
|
||
// c iprint>100 print details of every iteration including x and g;
|
||
// c When iprint > 0, the file iterate.dat will be created to
|
||
// c summarize the iteration.
|
||
// c
|
||
// c info is an integer variable.
|
||
// c On entry info is unspecified.
|
||
// c On exit info = 0 for normal return,
|
||
// c = nonzero for abnormal return
|
||
// c when the matrix K is ill-conditioned.
|
||
// c
|
||
// c Subprograms called:
|
||
// c
|
||
// c Linpack
|
||
// c
|
||
// c
|
||
// c References:
|
||
// c
|
||
// c [1] R. H. Byrd, P. Lu, J. Nocedal and C. Zhu, ``A limited
|
||
// c memory algorithm for bound constrained optimization'',
|
||
// c SIAM J. Scientific Computing 16 (1995), no. 5, pp. 1190--1208.
|
||
// c
|
||
// c
|
||
// c
|
||
// c * * *
|
||
// c
|
||
// c NEOS, November 1994. (Latest revision June 1996.)
|
||
// c Optimization Technology Center.
|
||
// c Argonne National Laboratory and Northwestern University.
|
||
// c Written by
|
||
// c Ciyou Zhu
|
||
// c in collaboration with R.H. Byrd, P. Lu-Chen and J. Nocedal.
|
||
// c
|
||
// c
|
||
// c ************
|
||
//
|
||
// c
|
||
//
|
||
internal static void subsm(int n,
|
||
int m, int nsub, int[] ind, int _ind_offset,
|
||
double[] l, int _l_offset, double[] u, int _u_offset,
|
||
int[] nbd, int _nbd_offset, double[] x, int _x_offset,
|
||
double[] d, int _d_offset, double[] xp, int _xp_offset,
|
||
double[] ws, int _ws_offset, double[] wy, int _wy_offset,
|
||
double theta, double[] xx, int _xx_offset, double[] gg, int _gg_offset,
|
||
int col, int head, ref int iword,
|
||
double[] wv, int _wv_offset, double[] wn, int _wn_offset, int iprint, ref int info)
|
||
{
|
||
int pointr = 0;
|
||
int m2 = 0;
|
||
int col2 = 0;
|
||
int ibd = 0;
|
||
int jy = 0;
|
||
int js = 0;
|
||
int i = 0;
|
||
int j = 0;
|
||
int k = 0;
|
||
double alpha = 0.0d;
|
||
double xk = 0.0d;
|
||
double dk = 0.0d;
|
||
double temp1 = 0.0d;
|
||
double temp2 = 0.0d;
|
||
double dd_p = 0.0d;
|
||
|
||
if ((nsub <= 0))
|
||
{
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Compute wv = W'Zd.
|
||
//
|
||
pointr = head;
|
||
{
|
||
for (i = 1; i <= col; i++)
|
||
{
|
||
temp1 = 0.0;
|
||
temp2 = 0.0;
|
||
{
|
||
for (j = 1; j <= nsub; j++)
|
||
{
|
||
k = ind[(j - (1)) + _ind_offset];
|
||
temp1 = (temp1 + (wy[(k - (1)) + (pointr - (1))
|
||
* (n) + _wy_offset] * d[(j - (1)) + _d_offset]));
|
||
temp2 = (temp2 + (ws[(k - (1)) + (pointr - (1))
|
||
* (n) + _ws_offset] * d[(j - (1)) + _d_offset]));
|
||
}
|
||
}
|
||
|
||
wv[(i - (1)) + _wv_offset] = temp1;
|
||
wv[((col + i) - (1)) + _wv_offset] = (theta * temp2);
|
||
pointr = ((pointr) % (m) + 1);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Compute wv:=K^(-1)wv.
|
||
//
|
||
m2 = (2 * m);
|
||
col2 = (2 * col);
|
||
|
||
dtrsl(wn, _wn_offset, m2, col2, wv, _wv_offset, 11, ref info);
|
||
|
||
{
|
||
for (i = 1; i <= col; i++)
|
||
{
|
||
wv[(i - (1)) + _wv_offset] = (-(wv[(i - (1)) + _wv_offset]));
|
||
}
|
||
}
|
||
|
||
dtrsl(wn, _wn_offset, m2, col2, wv, _wv_offset, 1, ref info);
|
||
|
||
//
|
||
// Compute d = (1/theta)d + (1/theta**2)Z'W wv.
|
||
//
|
||
pointr = head;
|
||
{
|
||
for (jy = 1; jy <= col; jy++)
|
||
{
|
||
js = (col + jy);
|
||
{
|
||
for (i = 1; i <= nsub; i++)
|
||
{
|
||
k = ind[(i - (1)) + _ind_offset];
|
||
d[(i - (1)) + _d_offset] = ((d[(i - (1)) + _d_offset]
|
||
+ ((wy[(k - (1)) + (pointr - (1)) * (n) + _wy_offset] * wv[(jy - (1))
|
||
+ _wv_offset]) / theta)) + (ws[(k - (1))
|
||
+ (pointr - (1)) * (n) + _ws_offset] * wv[(js - (1)) + _wv_offset]));
|
||
}
|
||
}
|
||
|
||
pointr = ((pointr) % (m) + 1);
|
||
}
|
||
}
|
||
|
||
|
||
dscal(nsub, (1.0 / theta), d, _d_offset, 1);
|
||
|
||
//
|
||
// ----------------------------------------------------
|
||
// Let us try the projection, d is the Newton direction
|
||
//
|
||
iword = 0;
|
||
|
||
dcopy(n, x, _x_offset, 1, xp, _xp_offset, 1);
|
||
|
||
// c
|
||
{
|
||
for (i = 1; i <= nsub; i++)
|
||
{
|
||
k = ind[(i - (1)) + _ind_offset];
|
||
dk = d[(i - (1)) + _d_offset];
|
||
xk = x[(k - (1)) + _x_offset];
|
||
if ((nbd[(k - (1)) + _nbd_offset] != 0))
|
||
{
|
||
if ((nbd[(k - (1)) + _nbd_offset] == 1))
|
||
{
|
||
x[(k - (1)) + _x_offset] = System.Math.Max(l[(k - (1)) + _l_offset], (xk + dk));
|
||
if ((x[(k - (1)) + _x_offset] == l[(k - (1)) + _l_offset]))
|
||
{
|
||
iword = 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ((nbd[(k - (1)) + _nbd_offset] == 2))
|
||
{
|
||
xk = System.Math.Max(l[(k - (1)) + _l_offset], (xk + dk));
|
||
x[(k - (1)) + _x_offset] = System.Math.Min(u[(k - (1)) + _u_offset], xk);
|
||
if (((x[(k - (1)) + _x_offset] == l[(k - (1))
|
||
+ _l_offset]) || (x[(k - (1)) + _x_offset] == u[(k - (1)) + _u_offset])))
|
||
{
|
||
iword = 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ((nbd[(k - (1)) + _nbd_offset] == 3))
|
||
{
|
||
x[(k - (1)) + _x_offset] = System.Math.Min(u[(k - (1)) + _u_offset], (xk + dk));
|
||
if ((x[(k - (1)) + _x_offset] == u[(k - (1)) + _u_offset]))
|
||
{
|
||
iword = 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
x[(k - (1)) + _x_offset] = (xk + dk);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
if ((iword == 0))
|
||
{
|
||
goto L911;
|
||
}
|
||
|
||
//
|
||
// check sign of the directional derivative
|
||
//
|
||
dd_p = 0.0;
|
||
{
|
||
for (i = 1; i <= n; i++)
|
||
{
|
||
dd_p = (dd_p + (((x[(i - (1)) + _x_offset]
|
||
- xx[(i - (1)) + _xx_offset])) * gg[(i - (1)) + _gg_offset]));
|
||
}
|
||
}
|
||
|
||
if ((dd_p > 0.0))
|
||
{
|
||
dcopy(n, xp, _xp_offset, 1, x, _x_offset, 1);
|
||
|
||
// DISPLAY: " Positive dir derivative in projection "
|
||
// DISPLAY: " Using the backtracking step "
|
||
}
|
||
else
|
||
{
|
||
goto L911;
|
||
}
|
||
|
||
//
|
||
// -----------------------------------------------------------------
|
||
//
|
||
alpha = 1.0;
|
||
temp1 = alpha;
|
||
ibd = 0;
|
||
{
|
||
for (i = 1; i <= nsub; i++)
|
||
{
|
||
k = ind[(i - (1)) + _ind_offset];
|
||
dk = d[(i - (1)) + _d_offset];
|
||
if ((nbd[(k - (1)) + _nbd_offset] != 0))
|
||
{
|
||
if (((dk < 0.0) && (nbd[(k - (1)) + _nbd_offset] <= 2)))
|
||
{
|
||
temp2 = (l[(k - (1)) + _l_offset] - x[(k - (1)) + _x_offset]);
|
||
if ((temp2 >= 0.0))
|
||
{
|
||
temp1 = 0.0;
|
||
}
|
||
else if (((dk * alpha) < temp2))
|
||
{
|
||
temp1 = (temp2 / dk);
|
||
}
|
||
}
|
||
else if (((dk > 0.0) && (nbd[(k - (1)) + _nbd_offset] >= 2)))
|
||
{
|
||
temp2 = (u[(k - (1)) + _u_offset] - x[(k - (1)) + _x_offset]);
|
||
if ((temp2 <= 0.0))
|
||
{
|
||
temp1 = 0.0;
|
||
}
|
||
else if (((dk * alpha) > temp2))
|
||
{
|
||
temp1 = (temp2 / dk);
|
||
}
|
||
}
|
||
|
||
if ((temp1 < alpha))
|
||
{
|
||
alpha = temp1;
|
||
ibd = i;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if ((alpha < 1.0))
|
||
{
|
||
dk = d[(ibd - (1)) + _d_offset];
|
||
k = ind[(ibd - (1)) + _ind_offset];
|
||
if ((dk > 0.0))
|
||
{
|
||
x[(k - (1)) + _x_offset] = u[(k - (1)) + _u_offset];
|
||
d[(ibd - (1)) + _d_offset] = 0.0;
|
||
}
|
||
else if ((dk < 0.0))
|
||
{
|
||
x[(k - (1)) + _x_offset] = l[(k - (1)) + _l_offset];
|
||
d[(ibd - (1)) + _d_offset] = 0.0;
|
||
}
|
||
}
|
||
{
|
||
for (i = 1; i <= nsub; i++)
|
||
{
|
||
k = ind[(i - (1)) + _ind_offset];
|
||
x[(k - (1)) + _x_offset] = (x[(k - (1)) + _x_offset] + (alpha * d[(i - (1)) + _d_offset]));
|
||
}
|
||
}
|
||
|
||
|
||
L911:
|
||
|
||
if ((iprint >= 99))
|
||
{
|
||
// DISPLAY: "----------------exit SUBSM --------------------"
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
// c
|
||
// c L-BFGS-B is released under the <20>New BSD License<73> (aka <20>Modified
|
||
// c or <20>3-clause license<73>)
|
||
// c Please read attached file License.txt
|
||
// c
|
||
// c
|
||
// c dpofa factors a double precision symmetric positive definite
|
||
// c matrix.
|
||
// c
|
||
// c dpofa is usually called by dpoco, but it can be called
|
||
// c directly with a saving in time if rcond is not needed.
|
||
// c (time for dpoco) = (1 + 18/n)*(time for dpofa) .
|
||
// c
|
||
// c on entry
|
||
// c
|
||
// c a double precision(lda, n)
|
||
// c the symmetric matrix to be factored. only the
|
||
// c diagonal and upper triangle are used.
|
||
// c
|
||
// c lda integer
|
||
// c the leading dimension of the array a .
|
||
// c
|
||
// c n integer
|
||
// c the order of the matrix a .
|
||
// c
|
||
// c on return
|
||
// c
|
||
// c a an upper triangular matrix r so that a = trans(r)*r
|
||
|
||
// c where trans(r) is the transpose.
|
||
// c the strict lower triangle is unaltered.
|
||
// c if info .ne. 0 , the factorization is not complete.
|
||
// c
|
||
// c info integer
|
||
// c = 0 for normal return.
|
||
// c = k signals an error condition. the leading minor
|
||
// c of order k is not positive definite.
|
||
// c
|
||
// c linpack. this version dated 08/14/78 .
|
||
// c cleve moler, university of new mexico, argonne national lab.
|
||
// c
|
||
// c subroutines and functions
|
||
// c
|
||
// c blas ddot
|
||
// c fortran sqrt
|
||
// c
|
||
// c internal variables
|
||
// c
|
||
// c begin block with ...exits to 40
|
||
// c
|
||
// c
|
||
private static void dpofa(double[] a, int _a_offset, int lda, int n, ref int info)
|
||
{
|
||
double t = 0.0d;
|
||
double s = 0.0d;
|
||
int j = 0;
|
||
int jm1 = 0;
|
||
int k = 0;
|
||
{
|
||
for (j = 1; j <= n; j++)
|
||
{
|
||
info = j;
|
||
s = 0.0e0;
|
||
jm1 = (j - 1);
|
||
if ((jm1 < 1))
|
||
{
|
||
goto L20;
|
||
}
|
||
|
||
{
|
||
for (k = 1; k <= jm1; k++)
|
||
{
|
||
t = (a[(k - (1)) + (j - (1)) * (lda) + _a_offset]
|
||
- ddot((k - 1), a, (1 - (1)) + (k - (1)) * (lda)
|
||
+ _a_offset, 1, a, (1 - (1)) + (j - (1)) * (lda) + _a_offset, 1));
|
||
|
||
t = (t / a[(k - (1)) + (k - (1)) * (lda) + _a_offset]);
|
||
a[(k - (1)) + (j - (1)) * (lda) + _a_offset] = t;
|
||
s = (s + (t * t));
|
||
}
|
||
}
|
||
|
||
L20:
|
||
s = (a[(j - (1)) + (j - (1)) * (lda) + _a_offset] - s);
|
||
// c ......exit
|
||
if ((s <= 0.0e0))
|
||
{
|
||
goto L40;
|
||
}
|
||
|
||
a[(j - (1)) + (j - (1)) * (lda) + _a_offset] = System.Math.Sqrt(s);
|
||
}
|
||
}
|
||
|
||
info = 0;
|
||
|
||
L40:
|
||
return;
|
||
}
|
||
|
||
// * .. Scalar Arguments ..
|
||
// * ..
|
||
// * .. Array Arguments ..
|
||
// * ..
|
||
// *
|
||
// * Purpose
|
||
// * =======
|
||
// **
|
||
// * scales a vector by a constant.
|
||
// * uses unrolled loops for increment equal to one.
|
||
// * jack dongarra, linpack, 3/11/78.
|
||
// * modified 3/93 to return if incx .le. 0.
|
||
// * modified 12/3/93, array(1) declarations changed to array(*)
|
||
// *
|
||
// *
|
||
// * .. Local Scalars ..
|
||
// * ..
|
||
// * .. Intrinsic Functions ..
|
||
// * ..
|
||
private static void dscal(int n, double da, double[] dx, int _dx_offset, int incx)
|
||
{
|
||
|
||
int i = 0;
|
||
int m = 0;
|
||
int mp1 = 0;
|
||
int nincx = 0;
|
||
|
||
if (((n <= 0) || (incx <= 0)))
|
||
{
|
||
return;
|
||
}
|
||
|
||
if ((incx == 1))
|
||
{
|
||
goto L20;
|
||
}
|
||
|
||
// *
|
||
// * code for increment not equal to 1
|
||
// *
|
||
nincx = (n * incx);
|
||
{
|
||
int _i_inc = incx;
|
||
for (i = 1; (_i_inc < 0) ? i >= nincx : i <= nincx; i += _i_inc)
|
||
{
|
||
dx[(i - (1)) + _dx_offset] = (da * dx[(i - (1)) + _dx_offset]);
|
||
}
|
||
}
|
||
return;
|
||
// *
|
||
// * code for increment equal to 1
|
||
// *
|
||
// *
|
||
// * clean-up loop
|
||
// *
|
||
L20:
|
||
m = (n) % (5);
|
||
|
||
if ((m == 0))
|
||
{
|
||
goto L40;
|
||
}
|
||
{
|
||
for (i = 1; i <= m; i++)
|
||
{
|
||
dx[(i - (1)) + _dx_offset] = (da * dx[(i - (1)) + _dx_offset]);
|
||
}
|
||
}
|
||
|
||
if ((n < 5))
|
||
{
|
||
return;
|
||
}
|
||
|
||
L40:
|
||
mp1 = (m + 1);
|
||
{
|
||
int _i_inc = 5;
|
||
for (i = mp1; i <= n; i += _i_inc)
|
||
{
|
||
dx[(i - (1)) + _dx_offset] = (da * dx[(i - (1)) + _dx_offset]);
|
||
dx[((i + 1) - (1)) + _dx_offset] = (da * dx[((i + 1) - (1)) + _dx_offset]);
|
||
dx[((i + 2) - (1)) + _dx_offset] = (da * dx[((i + 2) - (1)) + _dx_offset]);
|
||
dx[((i + 3) - (1)) + _dx_offset] = (da * dx[((i + 3) - (1)) + _dx_offset]);
|
||
dx[((i + 4) - (1)) + _dx_offset] = (da * dx[((i + 4) - (1)) + _dx_offset]);
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
// * .. Scalar Arguments ..
|
||
// * ..
|
||
// * .. Array Arguments ..
|
||
// * ..
|
||
// *
|
||
// * Purpose
|
||
// * =======
|
||
// *
|
||
// * forms the dot product of two vectors.
|
||
// * uses unrolled loops for increments equal to one.
|
||
// * jack dongarra, linpack, 3/11/78.
|
||
// * modified 12/3/93, array(1) declarations changed to array(*)
|
||
// *
|
||
// *
|
||
// * .. Local Scalars ..
|
||
// * ..
|
||
// * .. Intrinsic Functions ..
|
||
// * ..
|
||
private static double ddot(int n, double[] dx, int _dx_offset,
|
||
int incx, double[] dy, int _dy_offset, int incy)
|
||
{
|
||
double dtemp = 0.0d;
|
||
int i = 0;
|
||
int ix = 0;
|
||
int iy = 0;
|
||
int m = 0;
|
||
int mp1 = 0;
|
||
double ddot = 0.0d;
|
||
ddot = 0.0e0;
|
||
dtemp = 0.0e0;
|
||
if ((n <= 0))
|
||
{
|
||
return ddot;
|
||
}
|
||
|
||
if (((incx == 1) && (incy == 1)))
|
||
{
|
||
goto L20;
|
||
}
|
||
// *
|
||
// * code for unequal increments or equal increments
|
||
// * not equal to 1
|
||
// *
|
||
ix = 1;
|
||
iy = 1;
|
||
if ((incx < 0))
|
||
{
|
||
ix = (((((-(n)) + 1)) * incx) + 1);
|
||
}
|
||
if ((incy < 0))
|
||
{
|
||
iy = (((((-(n)) + 1)) * incy) + 1);
|
||
}
|
||
|
||
{
|
||
for (i = 1; i <= n; i++)
|
||
{
|
||
dtemp = (dtemp + (dx[(ix - (1)) + _dx_offset] * dy[(iy - (1)) + _dy_offset]));
|
||
ix = (ix + incx);
|
||
iy = (iy + incy);
|
||
}
|
||
}
|
||
ddot = dtemp;
|
||
return ddot;
|
||
|
||
// *
|
||
// * code for both increments equal to 1
|
||
// *
|
||
// *
|
||
// * clean-up loop
|
||
// *
|
||
L20:
|
||
m = (n) % (5);
|
||
|
||
if ((m == 0))
|
||
{
|
||
goto L40;
|
||
}
|
||
|
||
{
|
||
for (i = 1; i <= m; i++)
|
||
{
|
||
dtemp = (dtemp + (dx[(i - (1)) + _dx_offset] * dy[(i - (1)) + _dy_offset]));
|
||
}
|
||
}
|
||
|
||
if ((n < 5))
|
||
{
|
||
goto L60;
|
||
}
|
||
|
||
L40:
|
||
mp1 = (m + 1);
|
||
{
|
||
int _i_inc = 5;
|
||
for (i = mp1; i <= n; i += _i_inc)
|
||
{
|
||
dtemp = (((((dtemp + (dx[(i - (1)) + _dx_offset] * dy[(i - (1))
|
||
+ _dy_offset])) + (dx[((i + 1) - (1)) + _dx_offset] * dy[((i + 1) - (1))
|
||
+ _dy_offset])) + (dx[((i + 2) - (1)) + _dx_offset] * dy[((i + 2) - (1))
|
||
+ _dy_offset])) + (dx[((i + 3) - (1)) + _dx_offset] * dy[((i + 3) - (1))
|
||
+ _dy_offset])) + (dx[((i + 4) - (1)) + _dx_offset] * dy[((i + 4) - (1)) + _dy_offset]));
|
||
}
|
||
}
|
||
L60:
|
||
ddot = dtemp;
|
||
return ddot;
|
||
}
|
||
|
||
private static void dcopy(int n, double[] dx, int _dx_offset, int incx,
|
||
double[] dy, int _dy_offset, int incy)
|
||
{
|
||
|
||
int i = 0;
|
||
int ix = 0;
|
||
int iy = 0;
|
||
int m = 0;
|
||
int mp1 = 0;
|
||
if ((n <= 0))
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (((incx == 1) && (incy == 1)))
|
||
{
|
||
goto L20;
|
||
}
|
||
// c
|
||
// c code for unequal increments or equal increments
|
||
// c not equal to 1
|
||
// c
|
||
ix = 1;
|
||
iy = 1;
|
||
if ((incx < 0))
|
||
{
|
||
ix = (((((-(n)) + 1)) * incx) + 1);
|
||
}
|
||
if ((incy < 0))
|
||
{
|
||
iy = (((((-(n)) + 1)) * incy) + 1);
|
||
}
|
||
{
|
||
for (i = 1; i <= n; i++)
|
||
{
|
||
dy[(iy - (1)) + _dy_offset] = dx[(ix - (1)) + _dx_offset];
|
||
ix = (ix + incx);
|
||
iy = (iy + incy);
|
||
}
|
||
}
|
||
return;
|
||
// c
|
||
// c code for both increments equal to 1
|
||
// c
|
||
// c
|
||
// c clean-up loop
|
||
// c
|
||
L20:
|
||
m = (n) % (7);
|
||
if ((m == 0))
|
||
{
|
||
goto L40;
|
||
}
|
||
{
|
||
for (i = 1; i <= m; i++)
|
||
{
|
||
dy[(i - (1)) + _dy_offset] = dx[(i - (1)) + _dx_offset];
|
||
}
|
||
}
|
||
if ((n < 7))
|
||
{
|
||
return;
|
||
}
|
||
|
||
L40:
|
||
mp1 = (m + 1);
|
||
{
|
||
int _i_inc = 7;
|
||
for (i = mp1; i <= n; i += _i_inc)
|
||
{
|
||
dy[(i - (1)) + _dy_offset] = dx[(i - (1)) + _dx_offset];
|
||
dy[((i + 1) - (1)) + _dy_offset] = dx[((i + 1) - (1)) + _dx_offset];
|
||
dy[((i + 2) - (1)) + _dy_offset] = dx[((i + 2) - (1)) + _dx_offset];
|
||
dy[((i + 3) - (1)) + _dy_offset] = dx[((i + 3) - (1)) + _dx_offset];
|
||
dy[((i + 4) - (1)) + _dy_offset] = dx[((i + 4) - (1)) + _dx_offset];
|
||
dy[((i + 5) - (1)) + _dy_offset] = dx[((i + 5) - (1)) + _dx_offset];
|
||
dy[((i + 6) - (1)) + _dy_offset] = dx[((i + 6) - (1)) + _dx_offset];
|
||
}
|
||
}
|
||
}
|
||
|
||
// * .. Scalar Arguments ..
|
||
// * ..
|
||
// * .. Array Arguments ..
|
||
// * ..
|
||
// *
|
||
// * Purpose
|
||
// * =======
|
||
// *
|
||
// * DAXPY constant times a vector plus a vector.
|
||
// * uses unrolled loops for increments equal to one.
|
||
// *
|
||
// * Further Details
|
||
// * ===============
|
||
// *
|
||
// * jack dongarra, linpack, 3/11/78.
|
||
// * modified 12/3/93, array(1) declarations changed to array(*)
|
||
// *
|
||
// * =====================================================================
|
||
// *
|
||
// * .. Local Scalars ..
|
||
// * ..
|
||
// * .. Intrinsic Functions ..
|
||
// * ..
|
||
private static void daxpy(int n, double da,
|
||
double[] dx, int _dx_offset, int incx, double[] dy, int _dy_offset, int incy)
|
||
{
|
||
|
||
int i = 0;
|
||
int ix = 0;
|
||
int iy = 0;
|
||
int m = 0;
|
||
int mp1 = 0;
|
||
if ((n <= 0))
|
||
{
|
||
return;
|
||
}
|
||
|
||
if ((da == 0.0e0))
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (((incx == 1) && (incy == 1)))
|
||
{
|
||
// *
|
||
// * code for both increments equal to 1
|
||
// *
|
||
// *
|
||
// * clean-up loop
|
||
// *
|
||
m = (n) % (4);
|
||
if ((m != 0))
|
||
{
|
||
{
|
||
for (i = 1; i <= m; i++)
|
||
{
|
||
dy[(i - (1)) + _dy_offset] = (dy[(i - (1)) + _dy_offset]
|
||
+ (da * dx[(i - (1)) + _dx_offset]));
|
||
}
|
||
}
|
||
}
|
||
|
||
if ((n < 4))
|
||
{
|
||
return;
|
||
}
|
||
|
||
mp1 = (m + 1);
|
||
{
|
||
int _i_inc = 4;
|
||
for (i = mp1; i <= n; i += _i_inc)
|
||
{
|
||
dy[(i - (1)) + _dy_offset] = (dy[(i - (1)) + _dy_offset]
|
||
+ (da * dx[(i - (1)) + _dx_offset]));
|
||
dy[((i + 1) - (1)) + _dy_offset] = (dy[((i + 1) - (1)) + _dy_offset]
|
||
+ (da * dx[((i + 1) - (1)) + _dx_offset]));
|
||
dy[((i + 2) - (1)) + _dy_offset] = (dy[((i + 2) - (1)) + _dy_offset]
|
||
+ (da * dx[((i + 2) - (1)) + _dx_offset]));
|
||
dy[((i + 3) - (1)) + _dy_offset] = (dy[((i + 3) - (1)) + _dy_offset]
|
||
+ (da * dx[((i + 3) - (1)) + _dx_offset]));
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// *
|
||
// * code for unequal increments or equal increments
|
||
// * not equal to 1
|
||
// *
|
||
ix = 1;
|
||
iy = 1;
|
||
if ((incx < 0))
|
||
{
|
||
ix = (((((-(n)) + 1)) * incx) + 1);
|
||
}
|
||
if ((incy < 0))
|
||
{
|
||
iy = (((((-(n)) + 1)) * incy) + 1);
|
||
}
|
||
{
|
||
for (i = 1; i <= n; i++)
|
||
{
|
||
dy[(iy - (1)) + _dy_offset] = (dy[(iy - (1)) + _dy_offset]
|
||
+ (da * dx[(ix - (1)) + _dx_offset]));
|
||
ix = (ix + incx);
|
||
iy = (iy + incy);
|
||
}
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
}
|
||
|
||
} |