This file is indexed.

/usr/include/trilinos/IterationPack_Algorithm.hpp is in libtrilinos-dev 10.4.0.dfsg-1ubuntu2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
// @HEADER
// ***********************************************************************
// 
// Moocho: Multi-functional Object-Oriented arCHitecture for Optimization
//                  Copyright (2003) Sandia Corporation
// 
// Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
// license for use of this work by or on behalf of the U.S. Government.
// 
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//  
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//  
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
// Questions? Contact Roscoe A. Bartlett (rabartl@sandia.gov) 
// 
// ***********************************************************************
// @HEADER

#ifndef ALGORITHM_H
#define ALGORITHM_H

#include <assert.h>

#include <string>
#include <deque>
#include <list>
#include <vector>
#include <algorithm>

#include "IterationPack_AlgorithmState.hpp"
#include "IterationPack_AlgorithmTracker.hpp"
#include "IterationPack_AlgorithmStep.hpp"
#include "Teuchos_RCP.hpp"
#include "Teuchos_TestForException.hpp"
#include "Teuchos_StandardMemberCompositionMacros.hpp"

namespace IterationPack {

// ToDo: 7/31/98: Finish documentation.

/** \brief Acts as the central hub for an iterative algorithm.
  *
  * This class is the center for a framework for iterative algorithms.
  * These iterative algorithms are of the form:
  *
  \verbatim

  Step1------>Step2------>Step3------>Step4------>Step5
   /|\         /|\         /|\          |           |
    |           |           |_Minor L 1_|           |
    |           |                       |           |
    |           |_____Minor Loop 2______|           |
    |                                               |
    |_______________Major Loop (k = k+1)____________|
  \endverbatim
  *
  * For the typical iteration the steps are executed sequantially from Step1 to Step2
  * and then control loops around the Major Loop to Step1 again.
  * Durring some iterations however
  * Minor Loop 1 may be executed several times before control is continued alone the
  * major loop.  The same may also apply to Minor Loop 2.
  *
  * To allow for greater algorithmic control any step object can take over the role of
  * <tt>Algorithm</tt> and take over complete control the algorithm.  For examle, Step 4 may
  * need to Execute Step1->Step3->Step2->Step5 before returning algorithmic control to
  * <tt>Algorithm</tt>.
  *
  * <tt>Algorithm</tt> executes the steps of the algorithm through step objects of the
  * base type <tt>AlgorithmStep</tt>.  In addition to major step objects as shown above
  * there are also PreStep and PostStep objects.
  * These are steps that are intimatly associated with a major step object and
  * will always (well almost always) be exectuted alone with a major step.
  *
  * ToDo: Finish documentation.
  *
  * These functions provide information as to the number of major steps
  * , their possitions given their names and their names given their
  * possitions.
  *
  * In addition, access is given to the step objects themselves through
  * the RCP<...> objects that are used to manage thier memory.
  * Using this type of direct access allows clients to take over memory
  * management if needed and to call the step objects in any order
  * and thereby taking over control of the algorithm.
  *
  * These functions can be invoked in any state of the algorithm.
  *
  * Note that the currently running algorithm can always be interupted
  * by invoking the SIGINT signal (i.e. Ctrl-C) from the console.
  */
class Algorithm {
public:

  /** @name Public types */
  //@{

  /** \brief . */
  typedef Teuchos::RCP<AlgorithmState>      state_ptr_t;
  /** \brief . */
  typedef Teuchos::RCP<AlgorithmTracker>    track_ptr_t;
  /** \brief . */
  typedef Teuchos::RCP<AlgorithmStep>       step_ptr_t;
  /** \brief . */
  typedef size_t                                    poss_type;
  /** \brief . */
  enum { DOES_NOT_EXIST = 1000 };  // never be that many steps
  /** \brief . */
  enum ERunningState { NOT_RUNNING = 0, RUNNING = 1, RUNNING_BEING_CONFIGURED = 2 };

  /// Thrown if name or id does not exist
  class DoesNotExist : public std::logic_error
  {public: DoesNotExist(const std::string& what_arg) : std::logic_error(what_arg) {}};

  /// Thrown if name already exists
  class AlreadyExists : public std::logic_error
  {public: AlreadyExists(const std::string& what_arg) : std::logic_error(what_arg) {}};

  /// Thrown if an invalid control protocal is used.
  class InvalidControlProtocal : public std::logic_error
  {public: InvalidControlProtocal(const std::string& what_arg) : std::logic_error(what_arg) {}};

  /// Thrown if a member function is called while <tt>this</tt> is in an invalid running state..
  class InvalidRunningState : public std::logic_error
  {public: InvalidRunningState(const std::string& what_arg) : std::logic_error(what_arg) {}};

  /// Thrown if a member function is called while <tt>this</tt> is in an invalid running state..
  class InvalidConfigChange : public std::logic_error
  {public: InvalidConfigChange(const std::string& what_arg) : std::logic_error(what_arg) {}};

  /// Thrown if Algorithm was interrupted by the user
  class AlgorithmInterrupted : public std::runtime_error
  {public: AlgorithmInterrupted(const std::string& what_arg) : std::runtime_error(what_arg) {}};

  //@}

  /** @name Constructors & destructors */
  //@{

  /** \brief Constructs an algorithm with no steps and a default of max_iter() == 100.
    *
    */
  Algorithm();

  /** \brief . */
  virtual ~Algorithm();

  //@}

  /** \brief Name of an file that will cause the algorithm to terminate.
   *
   * If <tt>interrupt_file_name()!=""</tt> then the file <tt>interrupt_file_name()</tt>
   * will be looked for in the current directory and if it exists, it will be read
   * to determine how the algorithm should be terminated.  The format of this file
   * is as follows:
   *
   \verbatim
   
   abort_mode  terminate_bool

   \endverbatim
   *
   * Above, <tt>abort_mode</tt> can be:
   * <tt>a</tt> for "abort the program immediately",
   * <tt>s</tt> for "Gracefully terminate the algorithm at the end of this step",
   * <tt>i</tt> for "Gracefully terminate the algorithm at the end of this iteration"
   *
   * If the option <tt>abort_mode</tt> is set to <tt>s</tt> or <tt>i</tt> then the the
   * value of <tt>terminate_bool</tt> must be set to <tt>t</tt> for "true" or
   * <tt>f</tt> for "false".  If this <tt>abort_mode</tt> is set ot <tt>a</tt> then the
   * value of <tt>terminate_bool</tt> is not read.
   *
   * Note that the option values <tt>abort_mode</tt> and
   * <tt>terminate_bool</tt> are simple <tt>char</tt> data objects and
   * the only requirement is that they be seperated by whitespace.
   *
   * If the format of this file is not as described above, then an
   * exception will be thrown (which will have the affect of aborting
   * the process most likely).
   *
   * The default is <tt>interrupt_file_name()==""</tt> which means
   * that this file will not be looked for.
   */
  STANDARD_MEMBER_COMPOSITION_MEMBERS( std::string, interrupt_file_name );

  /** @name «std comp» members for state */
  //@{

  /** \brief . */
  void set_state(const state_ptr_t& state);
  /** \brief . */
  state_ptr_t& get_state();
  /** \brief . */
  const state_ptr_t& get_state() const;
  /** \brief . */
  AlgorithmState& state();
  /** \brief . */
  const AlgorithmState& state() const;

  //@}

  /** @name «std comp» members for track */
  //@{

  /** \brief . */
  void set_track(const track_ptr_t& track);
  /** \brief . */
  track_ptr_t& get_track();
  /** \brief . */
  const track_ptr_t& get_track() const;
  /** \brief . */
  AlgorithmTracker& track();
  /** \brief . */
  const AlgorithmTracker& track() const;

  //@}

  /** @name Maximum iterations */
  //@{
  
  /** \brief . */
  virtual void max_iter(size_t max_iter);
  /** \brief . */
  virtual size_t max_iter() const;

  //@}

  /** @name Maximum runtime (in minutes) */
  //@{
  
  /** \brief Set the maximum runtime (in minues)
    * The runtime is checked at the end of each iteration and if it exceeds
    * this value then the algorithm is terminated.
    */
  virtual void max_run_time(double max_iter);
  /** \brief . */
  virtual double max_run_time() const;

  //@}

  /** @name Step information & access */
  //@{

  /// Return the number of main steps
  virtual int num_steps() const;

  /** \brief Return the possition in the major loop of a named step.
    *
    * If a step with this name does not exist then the value
    * DOES_NOT_EXIST will be returned.
    */
  virtual poss_type get_step_poss(const std::string& step_name) const;

  /** \brief Return the name of a step given its possition.
    *
    * Preconditions:<ul>
    * <li> <tt>1 <= step_poss && step_poss <= num_steps()</tt> (throw <tt>DoesNotExist</tt>)
    * </ul>
    */
  virtual const std::string& get_step_name(poss_type step_poss) const;

  /** \brief Return the RCP<...> object for the step object at step_poss.
    *
    * Preconditions:<ul>
    * <li> <tt>1 <= step_poss && step_poss <= num_steps()</tt> (throw <tt>DoesNotExist</tt>)
    * </ul>
    */
  virtual step_ptr_t& get_step(poss_type step_poss);

  /** \brief . */
  virtual const step_ptr_t& get_step(poss_type step_poss) const;

  //@}

  /** @name Pre/post step information & access */
  //@{

  /** \brief Return the number of pre or post steps for the main step step_poss.
    *
    * Preconditions:<ul>
    * <li> <tt>1 <= step_poss && step_poss <= num_steps()</tt> (throw <tt>DoesNotExist</tt>)
    * </ul>
    */
  virtual int num_assoc_steps(poss_type step_poss, EAssocStepType type) const;

  /** \brief Return the possition of the pre or post step for the main step_poss.
    *
    * If a pre or post step does not exist with the name <tt>assoc_step_name</tt>
    * then a value of DOES_NOT_EXIST will be retruned.
    *
    * Preconditions:<ul>
    * <li> <tt>1 <= step_poss && step_poss <= num_steps()</tt> (throw <tt>DoesNotExist</tt>)
    * </ul>
    */
  virtual poss_type get_assoc_step_poss(poss_type step_poss, EAssocStepType type
    ,const std::string& assoc_step_name) const;

  /** \brief Return the name of the pre or post step at step_poss and at assoc_step_poss.
    *
    * Preconditions:<ul>
    * <li> <tt>1 <= step_poss && step_poss <= num_steps()</tt> (throw <tt>DoesNotExist</tt>)
    * <li> <tt>1 <= assoc_step_poss && assoc_step_poss <= num_assoc_steps(step_poss,type)</tt>
    *    (throw <tt>DoesNotExist</tt>)
    * </ul>
    */
  virtual const std::string& get_assoc_step_name(poss_type step_poss, EAssocStepType type
    , poss_type assoc_step_poss) const;

  /** \brief Return the RCP<...> object for the associated step object at step_poss
    * and assoc_step_poss.
    *
    * Preconditions:<ul>
    * <li> <tt>1 <= step_poss && step_poss <= num_steps()</tt> (throw <tt>DoesNotExist</tt>)
    * <li> <tt>1 <= assoc_step_poss && assoc_step_poss <= num_assoc_steps(step_poss,type)</tt>
    *    (throw <tt>DoesNotExist</tt>)
    * </ul>
    */
  virtual step_ptr_t& get_assoc_step(poss_type step_poss, EAssocStepType type
    , poss_type assoc_step_poss);

  /** \brief . */
  virtual const step_ptr_t& get_assoc_step(poss_type step_poss, EAssocStepType type
    , poss_type assoc_step_poss) const;

  //@}

  /** @name Step manipulation */
  //@{

  /** \brief Insert a step object with the name <tt>step_name</tt> into the possition <tt>step_poss</tt>.
    *
    * All the steps at and after <tt>step_poss</tt> are pushed back one possition unless
    * <tt>step_poss == num_steps() + 1</tt> in which case the new step is appended to the end.
    * Initiaily this step will have no pre or post steps associated with it.
    * 
    * Preconditions:<ul>
    * <li> <tt>running_state() != RUNNING]</tt> (throw <tt>InvalidRunningState</tt>)
    * <li> <tt>1 <= ste_poss && step_poss <= num_steps() + 1</tt> (throw <tt>DoesNotExist</tt>)
    * <li> <tt>step.get() != NULL</tt> (throw <tt>std::invalid_argument</tt>)
    * </ul>
    */
  virtual void insert_step(poss_type step_poss, const std::string& step_name, const step_ptr_t& step);

  /** \brief Change the name of an existing step.
    *
    * None of the pre or post steps for the existing step are changes.
    *
    * Preconditions:<ul>
    * <li> <tt>running_state() != RUNNING]</tt> (throw <tt>InvalidRunningState</tt>)
    * <li> <tt>1 <= poss && poss <= num_steps()</tt> (throw <tt>DoesNotExist</tt>)
    * </ul>
    */
  virtual void change_step_name(poss_type step_poss, const std::string& new_name);

  /** \brief Replace the step object of an existing step.
    *
    * None of the pre or post steps for the existing step are changes.
    *
    * Preconditions:<ul>
    * <li> <tt>running_state() != RUNNING]</tt> (throw <tt>InvalidRunningState</tt>)
    * <li> <tt>1 <= poss && poss <= num_steps()</tt> (throw <tt>DoesNotExist</tt>)
    * </ul>
    */
  virtual void replace_step(poss_type step_poss, const step_ptr_t& step);

  /** \brief Remove an existing step object and all of its pre and post steps.
    *
    * All of the steps after <tt>step_poss</tt> will have thier possitions
    * decreased by one.
    *
    * Preconditions:<ul>
    * <li> <tt>running_state() != RUNNING]</tt> (throw <tt>InvalidRunningState</tt>)
    * <li> <tt>1 <= poss && poss <= num_steps()</tt> (throw <tt>DoesNotExist</tt>)
    * </ul>
    */
  virtual void remove_step(poss_type step_poss);

  //@}

  /** @name Pre/post step manipulation */
  //@{

  /** \brief Insert an pre or post step into for the main step step_poss into the possition
    * assoc_step_poss.
    *
    * All of the pre or post steps at and after <tt>assoc_step_poss</tt> will be pushed back
    * one possition.
    *
    * Preconditions:<ul>
    * <li> <tt>running_state() != RUNNING]</tt> (throw <tt>InvalidRunningState</tt>)
    * <li> <tt>1 <= step_poss && step_poss <= num_steps() + 1</tt> (throw <tt>DoesNotExist</tt>)
    * <li> <tt>1 <= assoc_step_poss && assoc_step_poss <= num_assoc_steps(step_poss,type) + 1</tt>
    *    (throw <tt>DoesNotExist</tt>)
    * <li> <tt>assoc_step.get() != NULL</tt> (throw <tt>std::invalid_argument</tt>)
    * </ul>
    */
  virtual void insert_assoc_step(poss_type step_poss, EAssocStepType type, poss_type assoc_step_poss
    , const std::string& assoc_step_name, const step_ptr_t& assoc_step);

  /** \brief Remove an pre or post step for the main step step_poss in the possition
    * assoc_step_poss.
    *
    * All of the pre or post steps after <tt>assoc_step_poss</tt> will be pushed forward
    * one possition to fill in the hole.
    *
    * Preconditions:<ul>
    * <li> <tt>running_state() != RUNNING]</tt> (throw <tt>InvalidRunningState</tt>)
    * <li> <tt>1 <= step_poss && step_poss <= num_steps()</tt> (throw <tt>DoesNotExist</tt>)
    * <li> <tt>1 <= assoc_step_poss && assoc_step_poss <= num_assoc_steps(step_poss,type)</tt>
    *    (throw <tt>DoesNotExist</tt>)
    * </ul>
    */
  virtual void remove_assoc_step(poss_type step_poss, EAssocStepType type, poss_type assoc_step_poss);

  //@}

  /** @name Runtime configuration updating control */
  //@{

  /// Return the current running state of \c this algorithm object.
  ERunningState running_state() const;

  /** \brief Changes from running_state() == RUNNING to running_state() == RUNNING_BEING_CONFIGURED.
    *
    * Must be called before the algorithm's configuration can be changed while it is running.
    *
    * Preconditions:<ul>
    * <li> <tt>running_state() == RUNNING]</tt> (throw <tt>InvalidRunningState</tt>)
    * </ul>
    *
    * Postconditions:<ul>
    * <li> <tt>running_state() == RUNNING_BEING_CONFIGURED]</tt>
    * </ul>
    */
  virtual void begin_config_update();

  /** \brief Changes from running_state() == RUNNING_BEING_CONFIGURED to running_state() == RUNNING.
    *
    * Must be called after the algorithm's configuration can be changed while it is running.
    *
    * Preconditions:<ul>
    * <li> <tt>running_state() == RUNNING_BEING_CONFIGURED]</tt> (throw <tt>InvalidRunningState</tt>)
    * </ul>
    *
    * Postconditions:<ul>
    * <li> <tt>running_state() == RUNNING]</tt>
    * </ul>
    */
  virtual void end_config_update();

  //@}

  /** @name Algorithmic control */
  //@{

  /** \brief Called by step objects to set the step (given its name) that <tt>this</tt> will envoke the next time
    * <tt>this</tt> calls a step.
    *
    * Preconditions:<ul>
    * <li> <tt>running_state() == RUNNING<tt> (throw <tt>InvalidRunningState</tt>)
    * <li> <tt>get_step_poss(step_name) != DOES_NOT_EXIST</tt> (throw <tt>DoesNotExist</tt>)
    * </ul>
    */
  virtual void do_step_next(const std::string& step_name);

  /** \brief Called by step objects to set the step (given its possition) that <tt>this</tt> will envoke the next time
    * <tt>this</tt> calls a step.
    *
    * Preconditions:<ul>
    * <li> <tt>running_state() == RUNNING</tt> (throw <tt>InvalidRunningState</tt>)
    * <li> <tt>1 <= step_poss && step_poss <= num_steps()</tt> (throw <tt>DoesNotExist</tt>)
    * </ul>
    */
  virtual void do_step_next(poss_type step_poss);

  /** \brief Returns the name of the next step <tt>this</tt> will call the next time it calls a step.
    *
    * Preconditions:<ul>
    * <li> running_state() != NOT_RUNNING</tt> (throw <tt>InvalidRunningState</tt>)
    * </ul>
    */
  virtual const std::string& what_is_next_step_name() const;

  /** \brief Returns the possition of the next step <tt>this</tt> will call the next time it calls a step.
    *
    * Preconditions:<ul>
    * <li> running_state() != NOT_RUNNING</tt> (throw <tt>InvalidRunningState</tt>)
    * </ul>
    */
  virtual poss_type what_is_next_step_poss() const;

  /** \brief Calls <tt>do_step()</tt> on all of the pre step objects the step object and the post step objects
    * in order for the step named <tt>step_name</tt>.
    *
    * This operation is called by step objects that need to take over control of the algorithm
    * at some point.
    *
    * If any of the of the pre or post objects or the step object returns false, then this
    * operation immediatly returns false.  It is assumed that if any step object returns
    * false from its <tt>do_step()</tt> that it has either also called <tt>terminate()</tt>
    * or <tt>do_step_next()</tt>.
    *
    * Preconditions:<ul>
    * <li> <tt>running_state() == RUNNING</tt> (throw <tt>InvalidRunningState</tt>)
    * <li> <tt>get_step_poss(step_name) != DOES_NOT_EXIST</tt> (throw <tt>DoesNotExist</tt>)
    * </ul>
    */
  virtual bool do_step(const std::string& step_name);

  /** \brief Call <tt>do_step()</tt> on all of the pre step objects the step object and the post step objects
    * in order for the step in the possition <tt>step_poss</tt>.
    *
    * This operation is called by step objects that need to take over control of the algorithm
    * at some point.
    *
    * If any of the of the pre or post objects or the step object returns false, then this
    * operation immediatly returns false.  It is assumed that if any step object returns
    * false from do step that it has either also called <tt>terminate()</tt> or <tt>do_step_next()</tt>. 
    *
    * Preconditions:<ul>
    * <li> <tt>running_state() == RUNNING</tt> (throw <tt>InvalidRunningState</tt>)
    * <li> <tt>1 <= step_poss && step_poss <= num_steps()</tt> (throw <tt>DoesNotExist</tt>)
    * </ul>
    */
  virtual bool do_step(poss_type step_poss);

  /** \brief Called by step objects to terminate the algorithm.
    *
    * Calling with <tt>success == true</tt> cause <tt>do_algorithm()</tt> to completely return <tt>TERMINATE_TRUE</tt>
    * and with <tt>success == false</tt> return  <tt>TERMINATE_FALSE</tt>.
    *
    * Preconditions:<ul>
    * <li> <tt>running_state() == RUNNING</tt> (throw <tt>InvalidRunningState</tt>)
    * </ul>
    */
  virtual void terminate(bool success);

  //@}

  /** @name Start iterations */
  //@{

  /** \brief Called by clients to begin an algorithm.
    *
    * Preconditions:<ul>
    * <li> <tt>this->get_track() != NULL</tt> (throw <tt>???</tt>)
    * <li> <tt>running_state() == NOT_RUNNING</tt> (throw <tt>InvalidRunningState</tt>)
    * <li> <tt>1 <= step_poss && step_poss <= num_steps()</tt> (throw <tt>DoesNotExist</tt>)
    * </ul>
    *
    * This operation acts as the central hub for the algorithm.  It calls the <tt>do_step(i)</tt>
    * each <tt>i</tt> = 1,...,<tt>num_steps()</tt> and then loops around again for the major loop.  If
    * <tt>do_step(i)</tt> returns false then it goes executes the step specified by the 
    * <tt>do_step_next()</tt> operation which the step object supposivly called.  If a step
    * object returns false but does not call <tt>do_step_next()</tt> to specify a step to
    * jump to, then <tt>this</tt> will throw an <tt>InvalidControlProtocal</tt> exception.
    *
    * Before the algorithm is started, <tt>this</tt> calls <tt>track().initialize()</tt>.
    * At the end of each iteration <tt>this</tt> calls <tt>track().output_iteration(*this)</tt> and
    * <tt>state().next_iteration()</tt>.  It then checks if <tt>state.k() - k_start</tt> >= <tt>max_iter()</tt>.
    * If it is then the <tt>do_algorithm()</tt> immediatly terminates with a value of
    * <tt>MAX_ITER_EXCEEDED</tt> after it passes <tt>MAX_ITER_EXCEEDED</tt> to <tt>track().output_final()</tt>.
    * If the maxinum runtime <tt>this->max_run_time()</tt> is exceeded then <tt>MAX_RUN_TIME_EXCEEDED</tt>
    * will be passed to <tt>track().output_final()</tt> and this function will return
    * <tt>track().output_final()</tt>.  If the algorithm throws any exception then
    * <tt>track().output_final()</tt> will be called with the value <tt>TERMINATE_FALSE</tt>
    * and this exception will be rethrown clean out of here.
    *
    * Any step object can cause the algorithm to terminate by calling <tt>terminate(success)</tt>.
    * This operation will then immediatly return <tt>TERMINATE_TRUE</tt> if <tt>success == true</tt>
    * and <tt>TERMINATE_FALSE</tt>  if <tt>success == false</tt>.
    *
    * The algorithm starts on the step specified with <tt>step_poss</tt>.
    *
    */
  virtual EAlgoReturn do_algorithm(poss_type step_poss = 1);

  //@}

  /** @name Algorithm information output */
  //@{

  /** \brief Print out just a listing of the steps, their positions in the algorithm and the subclasses.
    */
  virtual void print_steps(std::ostream& out) const;

  /** \brief Print out the entire algorithm by calling <tt>print_step(...)</tt> on the step objects.
    */
  virtual void print_algorithm(std::ostream& out) const;

  //@}

  /** @name Algorithm Timing
    */
  //@{

  /** \brief Causes algorithm to be timed.
    *
    * Call with <tt>algo_timing == true</tt> before <tt>do_algorithm()</tt> to have the algorithm timed.
    *
    * Do not call when algorithm is running.
    */
  virtual void set_algo_timing( bool algo_timing );

  /** \brief . */
  virtual bool algo_timing() const;

  /** \brief Outputs table of times for each step, cummulative times and other
    * statistics.
    *
    * Call after <tt>do_algorithm()</tt> has executed to get a table
    * of times.
    *
    * Do not call when algorithm is running.
    */
  virtual void print_algorithm_times( std::ostream& out ) const;

  /** \brief Returns the step_times for iteration offset.
   *
   * @param  offset       [in] The interation offset to retrieve times for.
   * @param  step_times   [out] Array (size <tt>this->num_steps() + 1</tt>) with the
   *                      output step times (in seconds) for iteration <tt>k+offset</tt>.
   *                      The last entry <tt>step_times[this->num_steps()]</tt> gives
   *                      the total time for the entire iteration.
   *
   * Preconditions:<ul>
   * <li> <tt>offset <= 0</tt> (throw <tt>std::invalid_argument</tt>)
   * </ul>
   *
   * Note that <tt>offset</tt> must be a nonpositive number since we can only retreve
   * timings from the current or previous iterations.
   */  
  void get_step_times_k( int offset, double step_times[] ) const;

  /** \brief Returns the final statistics for a given step
    *  Do not call when algorithm is running
    */
  void get_final_step_stats( size_t step, double* total, double* average, double* min, double* max, double* percent) const;

  //@}

private:

  // /////////////////////////////////////////////////////
  // Private types

  /** \brief . */
  template<class T_Step_ptr>
  struct step_ptr_and_name {
    /** \brief . */
    step_ptr_and_name(const T_Step_ptr& _step_ptr
        , const std::string& _name )
      : step_ptr(_step_ptr), name(_name)
    {}
    /** \brief . */
    T_Step_ptr step_ptr;
    //
    std::string name;
  };  // end struct step_ptr_and_name

  /** \brief . */
  typedef step_ptr_and_name<step_ptr_t>           steps_ele_t;
  /** \brief . */
  typedef std::deque<steps_ele_t>                 steps_t;

  /** \brief . */
  typedef step_ptr_and_name<step_ptr_t>           assoc_steps_ele_list_ele_t;
  /** \brief . */
  typedef std::list<assoc_steps_ele_list_ele_t>   assoc_steps_ele_list_t;
  /** \brief . */
  struct assoc_steps_ele_t {
    /** \brief . */
    assoc_steps_ele_list_t& operator[](int i)
    { return assoc_steps_lists_[i]; }
    /** \brief . */
    const assoc_steps_ele_list_t& operator[](int i) const
    { return assoc_steps_lists_[i]; }
  private:
    assoc_steps_ele_list_t assoc_steps_lists_[2];
  };

  //typedef assoc_steps_ele_list_t[2]        assoc_steps_ele_t; // PRE_STEP, POST_STEP
  /** \brief . */
  typedef std::deque<assoc_steps_ele_t>      assoc_steps_t;
  
  /** \brief . */
  enum ETerminateStatus { STATUS_KEEP_RUNNING, STATUS_TERMINATE_TRUE, STATUS_TERMINATE_FALSE };

  /** \brief . */
  template<class T_ele>
  class name_comp {
  public:
    /** \brief . */
    name_comp(const std::string& name) : name_(name) {}
    /** \brief . */
    bool operator()(const T_ele& ele) { return ele.name == name_; }
  private:
    const std::string& name_;
  };  // end class name_comp

  typedef std::vector<double> step_times_t;
  
  /** \brief . */
  static const int
    TIME_STAT_TOTALS_OFFSET  = 0,
    TIME_STAT_AV_OFFSET    = 1,
    TIME_STAT_MIN_OFFSET    = 2,
    TIME_STAT_MAX_OFFSET    = 3,
    TIME_STAT_PERCENT_OFFSET  = 4;
  /** \brief . */
  enum { NUM_STEP_TIME_STATS = 5 };

  /** \brief . */
  typedef void (AlgorithmStep::*inform_func_ptr_t)(
    Algorithm&             algo
    ,poss_type             step_poss
    ,EDoStepType           type
    ,poss_type             assoc_step_poss
    );

  // /////////////////////////////////////////////////////
  // Private data members

  // aggregate members

#ifdef DOXYGEN_COMPILE
  AlgorithmState       *state;
  AlgorithmTracker     *track;
  AlgorithmStep        *steps;
#else
  state_ptr_t        state_;
  // RCP<...> object for the aggragate AlgorithmState object.

  track_ptr_t        track_;
  // RCP<...> object for the aggragate AlgorithmTracker object.
#endif

  // algorithm control etc.
  
  ERunningState      running_state_;
  // The state this Algorithm object is in:
  //
  // NOT_RUNNING    do_algorithm() is not active.
  // RUNNING        do_algorithm() has been called and is active.
  // RUNNING_BEING_CONFIGURED
  //                do_algorithm() is active and begin_config_update() has been called
  //                but end_config_update() has not.
  //
  // Note: Only change this variable through the private function change_running_state(...)
  // unless you are 100% sure that you know what you are doing!

  size_t          first_k_;
  // The first iteration from state().k().
  
  size_t          max_iter_;
  // The maximum number of iterations that <tt>this</tt> will execute.

  double          max_run_time_;
  // The maximum amount of time the algorithm is allowed to execute.

  ETerminateStatus    terminate_status_;
  // Flag for if it is time to terminate do_algorithm().

  poss_type        next_step_poss_;
  // The next step possition that <tt>this</tt> will execute when control is returned to do_algorithm().

  const std::string*    next_step_name_;
  // The name of the next step that <tt>this</tt> will execute when control is returned to do_algorithm().
  
  bool          do_step_next_called_;
  // Flag for if do_step_next() was called so that <tt>do_algorithm()</tt> can validate
  // that if a step object returned <tt>false</tt> from its <tt>do_step()</tt> operation that it
  // must also call <tt>do_step_next()</tt> to specify a step to jump to.

  poss_type        curr_step_poss_;
  // The current step being executed in do_algorithm().
  // If the current step being executed is changed during the imp_do_step() operation, then
  // imp_do_step() must adjust to this step.

  std::string        saved_curr_step_name_;
  // The name of the current step that is saved when begin_config_update() is called
  // so that curr_step_poss_ can be reset when end_config_update() is called.

  std::string        saved_next_step_name_;
  // The name of the next step to call so that when begin_config_update() is called
  // so that next_step_poss_ and next_step_name_ can be reset when end_config_update()
  // is called.

  bool          reconfigured_;
  // A flag that is set to true when a runtime configuration has been preformed.  It
  // is used to flag this event for imp_do_assoc_steps().

  // step and associated step object data structures

  steps_t          steps_;
  // Array of std::pair<RCP<step_ptr_t>,std::string> objects.
  //
  // *steps_[step_poss].first returns the step object for step_poss = 1...steps_.size().
  // steps_[step_poss].second returns the name of the step for step_poss = 1...steps_.size().

  assoc_steps_t      assoc_steps_;
  // Array of two lists of std::pair<step_ptr_t,std::string> objects
  //
  // *(assoc_steps_[step_poss][PRE_STEP].begin() + pre_step_poss).first gives the pre step object.
  // (assoc_steps_[step_poss][PRE_STEP].begin() + pre_step_poss).second gives the name of the pre step
  // *(assoc_steps_[step_poss][POST_STEP].begin() + post_step_poss).first gives the post step object.
  // (assoc_steps_[step_poss][POST_STEP].begin() + post_step_poss).second gives the name of the post step

  bool algo_timing_;
  // If true each step will be timed.

  mutable step_times_t step_times_;
  // Array of step times ( size (max_iter() + 1 + NUM_STEP_TIME_STATS) * (num_steps() + 1) ).
  //  The time in sec. for step step_i (one based)
  // for iteration iter_k (zero based) is:
  //   step_times_[ iter_k + (step_i - 1) * (max_iter() + 1 + NUM_STEP_TIME_STATS) ].
  // Therefore the times for each step are stored by column (consecutive elements)
  // so that statistics will be easy to compute at the end.
  // The last five elements after max_iter() for each step are reserved for:
  // * total time for the step
  // * average time for the step
  // * min step time
  // * max step time
  // * percentage for each step to the total.
  // The last column is for the total times for each iteration with the last five
  // elements being for the statistics for each iteration.   

  mutable bool time_stats_computed_;
  // A flag for if the timing statistics have already been computed or not.
  
  mutable double total_time_;
  // Records the total computed time for the algorithm.

  // /////////////////////////////////////////////////////
  // Private member functions

  /// Validate a step_poss and throw a DoesNotExist exception if it does not.
  poss_type validate(poss_type step_poss, int past_end = 0) const;

  /// Validate an assoc_step_poss and throw a DoesNotExist exception if it does not.
  poss_type validate(const assoc_steps_ele_list_t& assoc_list, poss_type assoc_step_poss, int past_end = 0) const;

  /// Change the running state
  void change_running_state(ERunningState running_state);

  /// Validate that <tt>this</tt> is in a specific running state.
  void validate_in_state(ERunningState running_state) const;

  /// Validate that <tt>this</tt> is not in a specific running state.
  void validate_not_in_state(ERunningState running_state) const;

  /// Validate that the step_poss in not the current step.
  void validate_not_curr_step(poss_type step_poss) const;

  /// Validate that the step_name in not the next step.
  void validate_not_next_step(const std::string& step_name) const;

  /** \brief Find a step given its name and throw a DoesNotExist exception if not found.
    */
  steps_t::iterator step_itr(const std::string& step_name);

  /** \brief . */
  steps_t::const_iterator step_itr(const std::string& step_name) const;

  /** \brief Find a step given its name and throw a DoesNotExist exception if not found.
    */
  steps_t::iterator step_itr_and_assert(const std::string& step_name);

  /** \brief . */
  steps_t::const_iterator step_itr_and_assert(const std::string& step_name) const;

  /** \brief Find a an associated step given its name and throw a DoesNotExist exception if not found.
    */
  static assoc_steps_ele_list_t::iterator assoc_step_itr(assoc_steps_ele_list_t& assoc_list
    , const std::string& assoc_step_name);

  /** \brief . */
  static assoc_steps_ele_list_t::const_iterator assoc_step_itr(const assoc_steps_ele_list_t& assoc_list
    , const std::string& assoc_step_name);

  /** \brief . */
  bool imp_do_step(poss_type step_poss);

  /** \brief . */
  bool imp_do_assoc_steps(EAssocStepType type);

  /** \brief . */
  void imp_inform_steps(inform_func_ptr_t inform_func_ptr);

  /** \brief . */
  void imp_print_algorithm(std::ostream& out, bool print_steps) const;

  /// EAssocStepType -> EDoStepType
  EDoStepType do_step_type(EAssocStepType assoc_step_type);

  /** \brief . */
  EAlgoReturn finalize_algorithm( EAlgoReturn algo_return );

  /** \brief . */
  void compute_final_time_stats() const;

  // Look for interrup
  void look_for_interrupt();

public:

  // This is put here out of need.  Not for any user to call!
  static void interrupt();

};  // end class Algorithm

// //////////////////////////////////////////////////////////////////////////////////////////////////
// Inline member function definitions for Algorithm

// «std comp» members for state 

inline
void Algorithm::set_state(const state_ptr_t& state)
{  state_ = state; }

inline
Algorithm::state_ptr_t& Algorithm::get_state()
{  return state_; }

inline
const Algorithm::state_ptr_t& Algorithm::get_state() const
{  return state_; }

inline
AlgorithmState& Algorithm::state()
{  TEST_FOR_EXCEPT( !( state_.get() ) ); return *state_; }

inline
const AlgorithmState& Algorithm::state() const
{  TEST_FOR_EXCEPT( !( state_.get() ) ); return *state_; }

// «std comp» members for track 

inline
void Algorithm::set_track(const track_ptr_t& track)
{  track_ = track; }

inline
Algorithm::track_ptr_t& Algorithm::get_track()
{  return track_; }

inline
const Algorithm::track_ptr_t& Algorithm::get_track() const
{  return track_; }

inline
AlgorithmTracker& Algorithm::track()
{  TEST_FOR_EXCEPT( !( track_.get() ) ); return *track_; }

inline
const AlgorithmTracker& Algorithm::track() const
{  TEST_FOR_EXCEPT( !( track_.get() ) ); return *track_; }

// running state

inline
Algorithm::ERunningState Algorithm::running_state() const
{  return running_state_; }

// lookup iterator given name

inline
Algorithm::steps_t::iterator Algorithm::step_itr(const std::string& step_name)
{
  return std::find_if( steps_.begin() , steps_.end()
    , name_comp<steps_ele_t>(step_name) );
}

inline
Algorithm::steps_t::const_iterator Algorithm::step_itr(const std::string& step_name) const
{
  return std::find_if( steps_.begin() , steps_.end()
    , name_comp<steps_ele_t>(step_name) );
}

inline
Algorithm::assoc_steps_ele_list_t::iterator Algorithm::assoc_step_itr(
  assoc_steps_ele_list_t& assoc_list, const std::string& assoc_step_name)
{
  return std::find_if( assoc_list.begin() , assoc_list.end()
    , name_comp<assoc_steps_ele_list_ele_t>(assoc_step_name) );
}

inline
Algorithm::assoc_steps_ele_list_t::const_iterator Algorithm::assoc_step_itr(
  const assoc_steps_ele_list_t& assoc_list, const std::string& assoc_step_name)
{
  return std::find_if( assoc_list.begin() , assoc_list.end()
    , name_comp<assoc_steps_ele_list_ele_t>(assoc_step_name) );
}

inline
EDoStepType Algorithm::do_step_type(EAssocStepType assoc_step_type) {
  switch(assoc_step_type) {
    case PRE_STEP  : return DO_PRE_STEP;
    case POST_STEP  : return DO_POST_STEP;
  }
  TEST_FOR_EXCEPT( !( true ) );
  return DO_PRE_STEP;  // will never execute.
}

}  // end namespace IterationPack 

#endif // ALGORITHM_H