Source Listing for project vqm2 - Ulrich Mutze · 136cpmzinterval.cpp 1688 137features.h 1694...

1956
Source Listing for project vqm2 Ulrich Mutze www.ulrichmutze.de July 1, 2020 Contents 1 Introduction, Draft 1 2 alloca.h 2 3 cpmalgorithms.h 3 4 cpmalgorithms.cpp 25 5 cpmangle.h 48 6 cpmangle.cpp 54 7 cpmapplication.h 62 8 cpmapplication.cpp 68 9 cpmbasicinterfaces.h 84 10 cpmbasictypes.h 86 11 cpmc.h 88 12 cpmc.cpp 96 13 cpmclinalg.h 103 14 cpmclinalg.cpp 122 15 cpmcmatrix.h 137

Transcript of Source Listing for project vqm2 - Ulrich Mutze · 136cpmzinterval.cpp 1688 137features.h 1694...

  • Source Listing for project vqm2

    Ulrich Mutze www.ulrichmutze.de

    July 1, 2020

    Contents

    1 Introduction, Draft 1

    2 alloca.h 2

    3 cpmalgorithms.h 3

    4 cpmalgorithms.cpp 25

    5 cpmangle.h 48

    6 cpmangle.cpp 54

    7 cpmapplication.h 62

    8 cpmapplication.cpp 68

    9 cpmbasicinterfaces.h 84

    10 cpmbasictypes.h 86

    11 cpmc.h 88

    12 cpmc.cpp 96

    13 cpmclinalg.h 103

    14 cpmclinalg.cpp 122

    15 cpmcmatrix.h 137

  • Contents

    16 cpmcmatrix.cpp 150

    17 cpmcompdef.h 169

    18 cpmconstphys.h 172

    19 cpmconstphys.cpp 175

    20 cpmcvector.h 176

    21 cpmcvector.cpp 188

    22 cpmdefinitions.h 198

    23 cpmdigraph.h 199

    24 cpmdimdef.h 214

    25 cpmdiscretespace.h 215

    26 cpmdistribution.h 218

    27 cpmdistribution.cpp 223

    28 cpmf.h 228

    29 cpmfa.h 238

    30 cpmfft.h 248

    31 cpmfft.cpp 252

    32 cpmfftmore.h 258

    33 cpmfieldoperator.h 263

    34 cpmfieldoperator.cpp 267

    35 cpmfieldstate.h 273

    36 cpmfieldstate.cpp 284

    37 cpmfile.h 306

    38 cpmfl.h 310

    2

  • Contents

    39 cpmfo.h 333

    40 cpmfontgeneration.h 337

    41 cpmfontgeneration.cpp 344

    42 cpmframe.h 361

    43 cpmframe.cpp 384

    44 cpmframes.h 408

    45 cpmframes.cpp 411

    46 cpmgraph.h 416

    47 cpmgraph.cpp 439

    48 cpmgreg.h 482

    49 cpmgreg.cpp 488

    50 cpmhistogr.h 496

    51 cpmimage.h 500

    52 cpmimagingtools.h 539

    53 cpmimagingtools.cpp 554

    54 cpmimg24.h 572

    55 cpmimg24.cpp 588

    56 cpminifilebasapp.h 615

    57 cpminifilebasapp.cpp 628

    58 cpminterfaces.h 646

    59 cpminterval.h 656

    60 cpminterval.cpp 667

    61 cpmlinalg.h 680

    3

  • Contents

    62 cpmlinalg.cpp 699

    63 cpmm.h 721

    64 cpmmacros.h 732

    65 cpmmaxw1d.h 735

    66 cpmmaxw1d.cpp 743

    67 cpmmini.h 747

    68 cpmmini.cpp 751

    69 cpmmpi.h 761

    70 cpmmultiimage.h 768

    71 cpmnumbers.h 809

    72 cpmnumbers.cpp 845

    73 cpmobservable.h 853

    74 cpmobservable.cpp 866

    75 cpmoperator.h 896

    76 cpmoperator.cpp 899

    77 cpmp.h 905

    78 cpmperm.h 913

    79 cpmperm.cpp 916

    80 cpmpsi.h 920

    81 cpmpsi.cpp 924

    82 cpmqm.h 930

    83 cpmqm.cpp 967

    84 cpmqmtemplates.h 1049

    4

  • Contents

    85 cpmqmx.h 1058

    86 cpmqmx.cpp 1069

    87 cpmr2func.h 1080

    88 cpmr2func.cpp 1084

    89 cpmrecord.h 1094

    90 cpmrecord.cpp 1108

    91 cpmrecordhandler.h 1135

    92 cpmrecordhandler.cpp 1140

    93 cpmrfunc.h 1149

    94 cpmrfunc.cpp 1164

    95 cpmrfuncrec.h 1205

    96 cpmrfuncrec.cpp 1209

    97 cpmrmateig.h 1212

    98 cpmrmateig.cpp 1216

    99 cpmrmatrix.h 1227

    100cpmrmatrix.cpp 1238

    101cpmroot.h 1259

    102cpmroot.cpp 1262

    103cpmrvector.h 1267

    104cpmrvector.cpp 1277

    105cpms.h 1287

    106cpmsmoothlocalinterpol.h 1302

    107cpmsmoothlocalinterpol.cpp 1305

    5

  • Contents

    108cpmstate.h 1318

    109cpmstate.cpp 1334

    110cpmstate2.h 1356

    111cpmstate2.cpp 1365

    112cpmsystem.h 1382

    113cpmsystem.cpp 1397

    114cpmsystemdependencies.h 1413

    115cpmtrj.h 1415

    116cpmtrj.cpp 1431

    117cpmtypes.h 1452

    118cpmtypes.cpp 1462

    119cpmuc.h 1472

    120cpmuc.cpp 1477

    121cpmv.h 1478

    122cpmv.cpp 1533

    123cpmva.h 1535

    124cpmvc.h 1548

    125cpmvc.cpp 1551

    126cpmvectormore.h 1554

    127cpmvectormore.cpp 1565

    128cpmviewport.h 1588

    129cpmviewport.cpp 1599

    130cpmvo.h 1612

    6

  • Contents

    131cpmvr.h 1627

    132cpmword.h 1631

    133cpmword.cpp 1646

    134cpmx.h 1657

    135cpmzinterval.h 1679

    136cpmzinterval.cpp 1688

    137features.h 1694

    138mpfr.h 1704

    139stdio.h 1727

    140stdlib.h 1745

    141time.h 1766

    142unistd.h 1773

    143vqm2.h 1797

    144vqm2.cpp 1799

    145vqm2app1.h 1801

    146vqm2app1.cpp 1804

    147vqm2app2.h 1882

    148vqm2app2.cpp 1884

    149vqm2app3.h 1907

    150vqm2app3.cpp 1909

    151survey.txt 1921

    152headerdependencies.txt 1941

    7

  • 1 Introduction, Draft

    1 Introduction, Draft

    This is a listing of the source files of the program VQM2 (Visual Quantum Mechanics).The program has a structure which allows it to grow without limitations. It containsnearly all of my experimentation concerning simulation of quantum processes. Some sub-applications are improvements of others, and the inferior old versions have not alwaysbeen purged. Documentation and explanation is mostly poor. One has to search forit as a comment to the doTheWork() member function of the various sub-applications.For instance

    void CpmVQM2::App6::doTheWork()

    // Initial state of particle 1 is a Gaussian and

    // initial state of particle 2 is eigenstate of

    // of the harmonic oscillator built into State2.

    // Aim is to see excitation or de-excitation of this

    // state as a result of interaction with particle 1.

    // This should be used for the image production for the publication.

    // 2006-11-03: visualization of the ’reduced’ states added.

    {

    Z mL=1;

    Word loc("CpmVQM2::App6::doTheWork()");

    CPM_MA

    ...

    from file vqm2app1.cpp. The first instance for running VQM2 is a selection n in filevqm2.ini which then passes control to file appn.ini. This file may be edited and savedbefore the run gets started; it will then be controlled by the data contained in this file.

    For general information consult the file cpmProject.pdf.

    8

  • 2 alloca.h

    2 alloca.h

    /* Copyright (C) 1992-2018 Free Software Foundation, Inc.

    This file is part of the GNU C Library.

    The GNU C 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.

    The GNU C 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 the GNU C Library; if not, see

    . */

    #ifndef _ALLOCA_H

    #define _ALLOCA_H 1

    #include

    #define __need_size_t

    #include

    __BEGIN_DECLS

    /* Remove any previous definitions. */

    #undef alloca

    /* Allocate a block that will be freed when the calling function exits. */

    extern void *alloca (size_t __size) __THROW;

    #ifdef __GNUC__

    # define alloca(size) __builtin_alloca (size)

    #endif /* GCC. */

    __END_DECLS

    #endif /* alloca.h */

    9

  • 3 cpmalgorithms.h

    3 cpmalgorithms.h

    //? cpmalgorithms.h

    //? C+- by Ulrich Mutze. Status of work 2020-07-01.

    //? Copyright (c) 2020 Ulrich Mutze

    //? contact: see contact-info at www.ulrichmutze.de

    //?

    //? This program is free software: you can redistribute it and/or

    //? modify it under the terms of the GNU General Public License as

    //? published by the Free Software Foundation, either version 3 of

    //? the License, or (at your option) any later version.

    //?

    //? This program is distributed in the hope that it will be useful,

    //? but WITHOUT ANY WARRANTY; without even the implied warranty of

    //? MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

    //? GNU General Public License for

    //? more details.

    #ifndef CPM_ALGORITHMS_H

    #define CPM_ALGORITHMS_H

    /*

    Description: This namespace will be populated by functions which

    express algorithms of general interest, which don’t fit well into

    one of the classes already introduced.

    */

    #include

    #include

    #include

    #include

    namespace CpmAlgorithms{

    using namespace CpmStd;

    using CpmRoot::R;

    using CpmRoot::Z;

    using CpmRoot::N;

    using CpmRoot::Word;

    using CpmRootX::B;

    using CpmArrays::V;

    using CpmArrays::VV;

    using CpmArrays::Vo;

    using CpmArrays::X2;

    using CpmArrays::X3;

    using CpmFunctions::FncObj;

    using CpmFunctions::F;

    #ifdef CPM_Fn

    using CpmFunctions::F2;

    10

  • 3 cpmalgorithms.h

    using CpmFunctions::F3;

    #endif

    using CpmGeo::Iv;

    using CpmLinAlg::Z2;

    //////////// functions gcd, lcm, lesDiv, prmFac, isPrm /////////////////

    // Division properties of natural numbers

    N gcd(N const& a, N const& b, bool verify=false);

    //! greatest common divisor

    // No assumption concerning the arguments. If a or b is 0,

    // we return 0, which never occurs for meaningful arguments.

    // If verify==true, it is tested whether the result actually

    // divides a and b; if not an error is issued.

    N lcm(N const& a, N const& b);

    //! least common multiple

    // Implementation based on a*b=gcd(a,b)*lcm(a,b) and

    // ise careful in avoiding temporaries that are larger

    // than the result. If any of the arguments is 0, we return 0.

    N lesDiv(N const& n);

    //: least divisor

    // returns the least (true, i.e. !=1) divisor of n.

    V prmFac(N const& n, bool verify=false);

    //: prime factors

    // Returns the prime factors of n as an array in

    // increasing order. If verify==true, it is tested whether the

    // components of the result actually multiply to n;

    // if not an error is issued.

    bool isPrm(N const& n);

    //: is prime

    // returns true iff n is prime. Although the algoritm is trivial

    // it takes less than 10 s to write a list of primes from 2

    // to 99991 (the range covered in Abramowitz, Stegun pp. 870-873)

    // to file.

    /////////// functions ZfromBits, bitsFromZ, next_1 ///////////////////////

    Z ZfromBits(const V& vb);

    // for n:=vb.dim() we return

    // sum(i=1,...n) vb[i]*2^(n-i)

    // i.e. the positive integer the binary expansion is given by

    // vb where vb[1] is the most significant bit

    // and vb[n] the least significant one

    V bitsFromZ(Z n, Z p);

    // we assume and test 0

  • 3 cpmalgorithms.h

    // Notice that the trailing ’_1’ says that the argument

    // gets changed by a function call.

    // After the call, v is the lexicographic successor of

    // the input v (order is false < true, and as successor

    // only lists are considered which have the same number

    // of components as v. If in v already all components

    // have the value true, there is no successsor and

    // the return value is false (i.e. no success in finding

    // a successor). Otherwise, the return value is true.

    // If v.size()==0 nothing is done on v and ’false’ is returned.

    // I use std::vector here since I need it in a context were

    // high efficiency is desirable. Since the template parameter

    // is a very light one, the reference counting advantage

    // of V does not exist here.

    ////////////////// class LatticeEnumerator /////////////////////////////

    class LatticeEnumerator{ // enumerating the points in cubic lattices

    // consider the lattice {1,2,...b[1]}x{1,2,...b[2]}x...x{1,2,...b[n]}.

    // the class provides a way to enumerate the points and to

    // construct a (i[1],...i[n]) from the enumerating integer.

    // indpendent data

    V b;

    // dependent data

    Z n; // n=b.dim()

    V c;

    // c.dim()=n

    // example n=4

    // c[1]=b[2]*b[3]*b[4]

    // c[2]= b[3]*b[4]

    // c[3]= b[4]

    // c[4]= 1

    Z nLattice; // c[1]*b[1]=b[1]*b[2]*...*b[n]

    void update();

    // initializes dependent data

    typedef LatticeEnumerator Type;

    public:

    CPM_IO

    LatticeEnumerator(const V& bounds):b(bounds){update();}

    // obvious

    LatticeEnumerator(){}

    Z operator()(const V& x)const;

    // We assume (and check) x.dim()==n

    // 1

  • 3 cpmalgorithms.h

    V operator()(Z k)const;

    // inverse mapping of the previous one

    };

    ////////////////// class LatticeBox //////////////////////////////////////

    class LatticeBox{

    // putting points into cells defined by a cartesian product of intervals

    V viv;

    V vz;

    Z n;

    Z np;

    V val;

    V< V > centers;

    LatticeEnumerator le;

    public:

    LatticeBox(const V& vivIn, const V& vzIn);

    V< V > points()const{ return centers;}

    V values()const{ return val;}

    void set(const V& pos, R valIn);

    Z dim()const{ return n;}

    Z nPoints()const{ return np;}

    VV matrix()const;

    // values of the 1-2-plane in matrix-indexed arrangement

    };

    ///////////// bracketing a root /////////////////////////////////////////

    X3 brack(const F& f, R xMin, R xMax, R dxMin, R dxMax);

    // let f(x) be defined for xMin

  • 3 cpmalgorithms.h

    // be done and a mere trend change will not cause further action.

    // Only sign changes will be considered.

    // Notice: We assume xMin

  • 3 cpmalgorithms.h

    // If f(xF)=false, f(xT)=true, xacc>0, we return a pair (xf,xt)

    // such that

    // f(xf)= false and f(xt)=true where xt-xf = (xT-xF)/(2^n)

    // for some natural number n and |xt-xf|

  • 3 cpmalgorithms.h

    }

    R fixedPoint(const F& f, const R& x0,

    R eps, Z iterMax);

    // Specialization of the template version; needed since R can’t

    // provide member functions (and the legal work-arround with a

    // non-member dis(X,X) does not work always with the MS

    // compiler.

    ////////////////////////// Place ////////////////////////////////////////

    template

    class Place{//creating X-valued lists, satisfying specified conditions

    F create; // generator for X’s

    F condition1; // condition which each x should satisfy

    // in order to be acceptable for a result list to be created

    // via opertor ()

    F< X2, bool> condition2;

    // condition which each pair x[i], x[j] should satisfy

    // in order to make x[i] and x[j] both be acceptable as

    // members of the result list to be created via opertor ()

    bool useCondition1;

    // If this is false, the loop for testing condition1

    // will be omitted (added 2009-02-28)

    bool useCondition2;

    // If this is false, the loop for testing condition2

    // will be omitted (added 2006-02-21)

    public:

    Word nameOf()const

    { return Word("Place< "&CpmRoot::Name()(X())&" >"); }

    Place(const F& cr,

    const F& cond1,

    const F< X2, bool>& cond2,

    bool useCon1=true, bool useCon2=true):

    create(cr),condition1(cond1),

    condition2(cond2),

    useCondition1(useCon1),

    useCondition2(useCon2){}

    // bringing the condition functions in place, that will be

    // utilized in a call to operator()

    Place(const F& cr,

    const F& cond1):

    create(cr),condition1(cond1),

    condition2(),

    useCondition2(true),

    useCondition2(false){}

    // Faster form of case in which condition2 is the ’always true

    // function’. Also more convenient since one has not to

    16

  • 3 cpmalgorithms.h

    // give a definition of the ’always true function’.

    V operator()(Z n, Z trialMax=1000 )const;

    // From the X-valued sequence create(1), create(2), create(3), ....

    // we select a finite sublist x[1],....x[n] such that

    // condition1(x[i])==true for all 1

  • 3 cpmalgorithms.h

    template

    class RandomIntegration{

    // Calculating expectation values based on a X-valued list.

    // A X-valued list is the algorithmic substitute for the notion of

    // a probability measure on X:

    // Let S be a subset of X and let x[i]:=create(i) be the sequence

    // of X’s resulting from the creation mechanism of the present

    // class. Then

    // card{i | 1

  • 3 cpmalgorithms.h

    Z d=f.dim();

    V res(d,0.);

    Z i=1;

    Z nDone=0;

    Z j;

    while (nDonetrialMax)

    cpmerror("Too many trials in RandomIntegration::operator()");

    X x=create(++i);

    bool isValid=chi(x);

    if (norMet_ || isValid){

    nDone++;

    }

    if (isValid){

    for (j=1;j0,loc);

    R nInv=1./nDone;

    for (j=1;j

  • 3 cpmalgorithms.h

    public:

    AveragingInterpolator(const V& x, const V& y, Z n=0);

    // default ns==0 guarantees a continuous interpolation

    // function. Be cautious when using a different value

    Y operator()(const X& x)const{ return avrIpl(x,vx,vy,ns);}

    };

    template

    Y AveragingInterpolator::avrIpl(const X& x,

    const V& vx, const V& vy, const Z& nn)

    {

    const R p=-1.75;

    // p==-2 and smaller (sic, not in absolute value) gives something

    // close to step function interpolation (flat terrasses connected

    // by steep ridges). Has to be negative in order to give near points

    // heavy weight.

    Z mL=4;

    Word loc("AveragingInterpolator::avrIpl(...)");

    CPM_MA

    Z i,n=vx.dim(),ny=vy.dim();

    cpmassert(n==ny,loc);

    if (n==0) return Y();

    R val,sum=0.;

    Y res=Y();

    if (nn==0 || nn>n){ // weighted mean over all points

    for (i=1;i

  • 3 cpmalgorithms.h

    R r2=vr2[j];

    if (r2==0) return vy[j];

    val=cpmpow(r2,p);

    sum+=val;

    res+=(vy[j]*val);

    }

    }

    cpmassert(sum>0.,loc);

    R sumInv=R(1.)/sum;

    res*=sumInv;

    CPM_MZ

    return res;

    }

    template

    AveragingInterpolator::AveragingInterpolator

    (const V& x, const V& y, Z n):vx(x),vy(y),ns(n)

    {

    Z mL=3;

    Word loc("AveragingInterpolator(...)");

    CPM_MA

    cpmassert(vx.dim()xU). The previous explanation describes the first

    // version of Quantizer considered. Meanwhile a second constructor,

    // taking as an argument a const V& v, provides more flexible

    // quantisation services. Consider the set X of R’s provided by the

    // components of v. (this may be void since v.dim() is allowed

    // to be 0. Notice card(X)

  • 3 cpmalgorithms.h

    // that every x is below every box and above every box.

    // This functionality of quantizing is here put into a class

    // (instead of a function) since this allows to separate the pre-

    // computations (which get done after constructor call) and the

    // actual quantization (which get done after call of operator()).

    // This could increase speed in a situation in which many numbers

    // have to be quantized with respect to one system of values xL,xU,n.

    class Quantizer: public F{ // Putting real numbers into boxes

    // this derivation defines Z operator()(const R&)const and makes

    // available all member functions of F and all functions that

    // take F& as arguments. Notice that the only data member is

    // an address of a memory area that stores an instance of a class

    // that is known to be derived from FncObj. It thus defines Z

    // operator()(const R&)const; the actual definition of this virtual

    // operator may utilize data of types that vary from one value of

    // the adress to the next. So, the class itself does not determine

    // the information layout of its internal state. Very advanced

    // construct, indeed. Notice that this is an immutable class that

    // satisfies the value interface.

    Quantizer(const F& f):F(f){}

    // private tool for defining public constructors

    public:

    Quantizer();

    // trivial round-Off, needs no data!

    Quantizer(R xL, R xU, Z n);

    // setting the limits of the interval and the number of boxes.

    // If n is

  • 3 cpmalgorithms.h

    // The integer interval [xL,xU] i.e. the set {xL,xL+1,...xU}

    // is divided into n approximately equally sized disjoint

    // subintervals (equally sized they can be only if xU-xL+1

    // is a multiple of n)

    // These are numbered from 1 to n in the order of increasing x.

    // If x belongs to one of the boxes, we return the number of it. If x

    // belongs to the interval [xL,xU] it always belongs to exactly one

    // box by the definition.

    // For xxU we return n.

    // The degenerate case is xL=xU. Here we return 1 always.

    // Here the class has its own data and a function among them.

    // This seems to be the most powerful type of implementation.

    // The main point is here that in defining the constructor

    // one may pre-process the constructor arguments before the

    // data member f has to be initialized. Initializing f is

    // simply by assignment. Notice that it would be contraproductive

    // to derive InQuant from FuObj to get operator()(Z).

    // This would make the result an immutable class wheras the

    // present definition gives a class that implements the strict

    // value interface.

    class IntQuant{ // Putting integer numbers into boxes

    Z zL;

    Z zU;

    Z nP;

    R spanInv;

    F f;

    public:

    IntQuant(Z xL=1, Z xU=1, Z n=1);

    // setting the limits of the interval and the number of boxes.

    // If n is

  • 3 cpmalgorithms.h

    // V a=...;

    // Percentilizer per(a);

    // R x=0.25;

    // R y=per(x);

    // y is a number such that 25% of all components of a have

    // values below y. An important application of Percentilizer is to

    // exclude from a set of numbers a ’few extreme values’ that may be

    // considered as irregular.

    class Percentilizer: public F{ // handling quartiles (hinges)

    // Notice that this is an immutable class that does not exactly

    // satisfies the value interface since it does not define a default

    // constructor. Such a constructor could not be of any value.

    Vo arr;

    // ordered list of numbers that define a statistical distribution;

    // In contrast to class Quantizer the basic data elements are not

    // held by the base class. So it is readily available for

    // efficient implementation of further methods needing it.

    public:

    Percentilizer(const V& );

    // setting the list of real values (no ordering implied) that

    // define the distribution, which in turns defines the quantiles

    F toBase()const{ return *this;}

    // evident

    R mean(const Iv& iv)const;

    // iv is a subinterval of Iv(0,1) (or Iv(0,1) itself).

    // This selects the components of arr which lie

    // between (*this)(iv[1]) and (*this)(iv[2]). The mean value

    // of these selected components is returned.

    R modulation( const Iv& ivL, const Iv& ivU)const

    // a flexible descriptor of the variability (deviation from

    // constancy) of the values in arr. Allows to ignore

    // extreme (potentially irregular) values in arr.

    // Details clear from code:

    { return (mean(ivU)-mean(ivL))*cpminv(mean(ivU|ivL));}

    V select(const Iv& iv)const;

    // returns the sub-list of arr over which function mean

    // performs the average

    };

    R gaussRandomValue(const R& mean, const R& sigma);

    // Returns normally distributed random numbers with mean and sigma

    // given by the respective arguments.

    24

  • 3 cpmalgorithms.h

    // Modified from gasdev(long*) of Press et al. by introducing another

    // basic random generator and by not specializing the arguments.

    // Notice that the involved method of generation will not easily enable

    // to define a random array (i.e. introduction of the argument j as in

    // ran(const R& x, Nd j) such that consequtive components are

    // independent.

    ///////////////// some counter-like data types //////////////////////////

    //////////////////////// PeriodicAlarm //////////////////////////////////

    // Let per be an instance of class PeriodicAlarm. Then for some t of type

    // R we may ask for the value of per(t) which is either true or false.

    // This boolean return value does not only depend on t but also on the

    // values of the t’s for which per was called earlier. The situation for

    // which PeriodicAlarm is designed and in which its functionality follows

    // an easy to describe pattern is that calls to per(t) come in order of

    // increasing t. This means that a code fragment

    //

    // PeriodicAlarm per(...);

    // R t1=...;

    // bool b1=per(t1);

    // ...

    // R t2=...;

    // bool b2=per(t2);

    // ...

    // should ensure that t2>=t1.

    // Let the tasks be ’write the state variables of a dynamical system to

    // disk’ be scheduled for instants of time which form an equidistant

    // lattice of width period (period>0) and let t be the time variable of

    // the dynamical system that changes from one computational step to the

    // next by varying amounts (adaptive time stepping) (normally small

    // compared to the fixed step ’period’ from task to task).

    // Then per(t)==true says that we should call writeState().

    class PeriodicAlarm{ // periodic counter

    bool active;

    // if false, the counter is deactivated so that calling operator()

    // gives always ’false’ and no further action is taken

    R period;

    // distance between points of alarm

    R lastAlarm;

    // t walue for which (*this)(t) was found ’true’ the last time

    Z counter;

    // counts the alarms

    R nextLatticePoint;

    // the time points for alarm form a equidistant lattice (chain)

    // of points on the t-axis. Thus the name

    R tol;

    25

  • 3 cpmalgorithms.h

    // tolerance as fraction of period, so that not

    // the condition t>=nextLatticePoint triggers

    // operator()(t)==true but already

    // t>=nextLatticePoint-tol. We always assume period>=0.

    // In the frequently occurring case that t grows in steps of

    // period between calls of operator() this makes the trigger

    // condition independent of numerical chance events.

    public:

    PeriodicAlarm(R period=0, R tIni=0, R phase=0.);

    // time for the first alarm is tIni+phase*period. Then the points

    // of alarm follow with a spacing given by period.

    // If period==0, the object is created in not active state.

    bool operator()(R t);

    // gives the alarm status for time t. Is ’true’ for

    // (t+tol) >= nextLatticePoint

    // updates nextLatticePoint by adding period the smallest integer

    // multiple of period such that t=alarmPoint

    // sets done=true

    };

    ////////////////////////// CyclicAlarm //////////////////////////////////

    // version of a perodic alarm with a discrete periodic counter. Each

    // call of the status (operator()) updates the counter

    class CyclicAlarm{ // periodic counter

    26

  • 3 cpmalgorithms.h

    // notice that all attributes are class typed and thus initialized

    B dormant;

    // if this is true, the object does not react on calls

    // to operator(), especially the value of ’alarm’

    // remains unchanged

    B done;

    // if ’true’ the one has alarm==false

    // and operator() always returns false

    Z cog{0}; // ’Zahn’,’Zahnrad’ in German

    // each call to operator() cyclically increases cog

    // cyclic structure given by period.

    // One should have available residue class Z/n at this place

    Z period{0};

    // after period increments of cog we set alarm==true

    Z counter{0};

    // each setting alarm==true increases counter

    Z counterMax{0};

    // after counter has reached the value counterMax

    // we have done==true

    // since counter>=0 always, a negative value for

    // counterMax let it never be done (which is considered

    // normal behavior: ’work is never done’).

    B alarm;

    // if this is true, alarm is set

    public:

    typedef CyclicAlarm Type;

    virtual Type* clone()const{ return new CyclicAlarm(*this);}

    CyclicAlarm(Z per=1, Z cogIni=0, Z maxAlarms=-1);

    // per=0 gives return value false for all calls of

    // operator().

    // Effectively cogIni

  • 3 cpmalgorithms.h

    // of function ’record’. Returns the status of alarm at present

    // state and moves *this to the next state

    Z count()const{ return counter;}

    void setAlarm(bool b){ alarm=B(b);}

    bool getAlarm()const{ return alarm;}

    void switchOff(){ dormant=true;}

    void switchOn(){ dormant=false;}

    bool ready()const{ return done;}

    void restart(){ done=B(false); cog=0, counter=0; alarm=B(true);}

    void restartWithNewPeriod(Z per){ period=per; done=false;

    cog=0, counter=0; alarm=true;}

    V record(Z n);

    Z per()const{ return period;}

    // returns the sequence resulting from n-fold application of

    // operator(). Means for testing.

    };

    ////////////////////// NonCyclicAlarm //////////////////////////////////

    // cog-based state machine that gives alarm iff

    // cog==points_[counter]. Each alarm increases not only

    // cog but also counter.

    //

    // The behavior is thus just the following:

    // V vz=...;

    // NonCyclicAlarm nca(vz);

    // bool b;

    // b=nca();

    // ...

    // b=nca();

    // ...

    // b=nca(); // n-th call of operator()() after constructor call

    // results in b==true iff there if a k \in {1,2,..., vz.dim()} such that

    // n==vz[k]

    class NonCyclicAlarm{ // cog-based state machine

    // notice that all attributes are class typed and thus initialized

    B done;

    // if ’true’ the one has alarm==false

    // and operator() always returns false

    Z cog{0}; // ’Zahn’,’Zahnrad’ in German

    // each call to operator() increases cog by 1

    Z counter{0};

    // each setting alarm==true increases counter

    V points_;

    28

  • 3 cpmalgorithms.h

    // list of values such that cog==points_[counter]

    // is the point to trigger

    Z counterMax{0};

    // after counter has reached the value counterMax

    // we have done==true

    B alarm;

    // if this is true, alarm is set

    public:

    typedef NonCyclicAlarm Type;

    virtual Type* clone()const{ return new NonCyclicAlarm(*this);}

    NonCyclicAlarm(const V& points=V(0));

    // condition for alarm==true is cog==points[counter]

    // alarm==true implies counter->counter+1

    // Der Bedeutung von ’points’ entsprechend sollte dieses

    // eine strict monoton wachsende Liste sein. points_

    // wird aus points durch umordnen und Weglassen von

    // Doubletten erhalten. Komponenten von points_, die

    // kleiner als 1 sind, werden nicht eliminiert, führen

    // aber dazu daß immer alarm==false gilt.

    virtual void step(void);

    // moves *this to the next state: cog->cog+1

    bool operator()(void){ bool alNow=alarm; step(); return alNow;}

    // most convenient usage of the class.

    // Returns the status of alarm at present

    // state and moves *this to the next state

    Z count()const{ return counter;}

    bool getAlarm()const{ return alarm;}

    bool ready()const{ return done;}

    void restart(){ done=false; cog=0, counter=1; alarm=false;}

    Z last()const{ return points_.last();}

    };

    ////////////////////////// BurstAlarm //////////////////////////////////

    // Similar to Cyclic alarm but opertor() gives true for if the

    // call number belongs to to a doubly periodic lattice

    // 2004-05-11: Triggers in some cases also if per=0. This is not

    // intended. Not completely understood!. Better don’t use it!

    class BurstAlarm: public CyclicAlarm{ // double periodic counter

    CyclicAlarm burst;

    public:

    typedef BurstAlarm Type;

    typedef CyclicAlarm Base;

    virtual CyclicAlarm* clone()const{ return new BurstAlarm(*this);}

    29

  • 3 cpmalgorithms.h

    BurstAlarm(Z per=1, Z burstPer=0, Z burstLen=0);

    // We exemplify the meaning of the data by considering the

    // sequence created by function record (1=true, 0=false)

    // e.g. for

    // per=10, burstPer=2, burstLen=3:

    // | 1 0 | 1 0 | 1 0 | 0 0 0 0 | 1 0 | 1 0 | 1 0 | 0 0 0 0

    // | 1 0 | 1 0 | 1 0 | 0 0 0 0 ...

    // one Burst is | 1 0 | 1 0 | 1 0 |. Period from burst beginning

    // to burst beginning is 10

    void step(void);

    // redefined

    };

    ////////////////////////////// enum Switch ////////////////////////////

    enum Switch{ // to be used as an argument type in cases where the values

    // ’true’ and ’false’ of a boolean argument would not suggest the

    // meaning with sufficient clarity

    ON,

    OFF

    };

    //////////////////////////// getNerFrc_1(...) ////////////////////////////

    Z getNerFrc_1(R& x, R xL);

    //: get nearest fraction

    // Notice that ’_1’ indicates that the first argument may be changed by

    // by a function call. Assumed is x=n, z2>=z1.

    // Among the infinite number of solutions of these inequalities

    // we choose one for which d1:=z1*z2-n and d2:=z2-z1 are both as small as

    30

  • 3 cpmalgorithms.h

    // they together can be. For instance, if n is a square number n=m*m, then

    // z1=z2=m are oviously what we want since then d1=d2=0.

    // For n=7 we have for z1=1, z2=7 the desirable property d1=0, but

    // d2=7-1=6 is not small. Here we could consider the pairs (2,4), (3,3).

    // In the first case we have d1=8-7=1, d2=4-2=2, and

    // in the second case d1=9-7=2, d2=3-3=0.

    // d1+d2 is smaller in the second case and so (3,3) will be selected.

    // See the implementation in cpmalgorithms.cpp for details.

    // Defining this function was suggested by a graphical problem. Given

    // n scalable figures; how to layout them on screen if only

    // matrix subdivisions of the screen are under consideration.

    } // namespace

    #endif

    31

  • 4 cpmalgorithms.cpp

    4 cpmalgorithms.cpp

    //? cpmalgorithms.cpp

    //? C+- by Ulrich Mutze. Status of work 2020-07-01.

    //? Copyright (c) 2020 Ulrich Mutze

    //? contact: see contact-info at www.ulrichmutze.de

    //?

    //? This program is free software: you can redistribute it and/or

    //? modify it under the terms of the GNU General Public License as

    //? published by the Free Software Foundation, either version 3 of

    //? the License, or (at your option) any later version.

    //?

    //? This program is distributed in the hope that it will be useful,

    //? but WITHOUT ANY WARRANTY; without even the implied warranty of

    //? MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

    //? GNU General Public License for

    //? more details.

    // notice that some algorithms are templates and are defined not here

    // but in cpmalgorithms.h !!!!!!!!!!!!!!!!!!!!

    #include

    #include

    #include

    // the names from CpmRootX will be used via using declarations in

    // function blocks.

    using namespace std;

    using CpmRoot::R;

    using CpmRoot::Z;

    using CpmRoot::N;

    using CpmRoot::Word;

    using CpmRootX::B;

    using CpmArrays::V;

    using CpmArrays::VV;

    using CpmArrays::Vo;

    using CpmArrays::Va;

    using CpmArrays::X2;

    using CpmArrays::X3;

    using CpmFunctions::F;

    #ifdef CPM_Fn

    using CpmFunctions::F1;

    using CpmFunctions::F2;

    using CpmFunctions::F3;

    using CpmFunctions::F4;

    #endif

    32

  • 4 cpmalgorithms.cpp

    using CpmFunctions::FncObj;

    using CpmGeo::Iv;

    using CpmAlgorithms::LatticeBox;

    using CpmLinAlg::Z2;

    // these using declarations are active till the end of this file, also

    // within the anonymus namespace to be defined later.

    // The directive #include brings also some using

    // declarations in action. These are only valid within the namespace

    // CpmAlgorithms and n o t in the anonymus namespace mentioned

    // above.

    // They are also not valid as return values of CpmAlgorithms member

    // functions (only in argument lists and definition blocks)

    N CpmAlgorithms::lesDiv(N const& n)

    {

    if (n

  • 4 cpmalgorithms.cpp

    N r=a%b;

    while(r){

    a=b;

    b=r;

    r=a%b;

    }

    if (verify){

    if (n1%b || n2%b){

    cpmerror("CpmAlgorithms::gcd("&cpm(n1)&","&cpm(n2)&") failed");

    }

    }

    return b;

    }

    N CpmAlgorithms::lcm(N const& a, N const& b)

    {

    N g=CpmAlgorithms::gcd(a,b);

    return g==0 ? 0 : ((a/g)*(b/g))*g;

    // avoids forming temporaries that are larger than the result

    }

    bool CpmAlgorithms::isPrm(N const& n)

    {

    if (n

  • 4 cpmalgorithms.cpp

    d/=2;

    }

    cpmmessage(mL,loc&" done");

    return res;

    }

    V CpmAlgorithms::bitsFromZ(Z n, Z p)

    // we assume and test 00,loc);

    cpmassert(p

  • 4 cpmalgorithms.cpp

    }

    // now v[i]==false

    v[i]=true; // so a change was made and return value

    // is rightfully ’true’

    for (size_t j=i+1; j0,loc);

    Z i,errorSum=0;

    for (i=1;i

  • 4 cpmalgorithms.cpp

    k--;

    V res(n);

    Z i=1;

    while (i

  • 4 cpmalgorithms.cpp

    V lei=le(i);

    V vali(n);

    for (j=1;j

  • 4 cpmalgorithms.cpp

    xf(R x, R f):x1(x),x2(x),x3(x),f1(f),f2(f),f3(f){}

    void shift(R x, R f){x1=x2;f1=f2;x2=x3;f2=f3;x3=x,f3=f;}

    Z eval()const;

    // the return value encodes the meaning of the data of *this

    // with respect to the aims of brack()

    };

    inline bool signChange(R x, R y)

    {

    return (x>=0 && y>=0)||(xfac*var) return 0; else return 4;

    }

    return 0; // no special event, no action triggered

    }

    } // anonymous namespace

    X3 CpmAlgorithms::brack(const F& f, R xMin,

    R xMax, R dxMin, R dxMax)

    {

    const Z mL=4;

    Z found;

    R x1=xMin;

    R length=xMax-xMin;

    R nh=cpmfloor(length/dxMax+0.5);

    R hStart=length/nh; // after doing some steps hStart one should

    // come very close to xMax

    R h=hStart;

    xLimit=xMax; // x1,h,xLimit are the iter ini data

    bool local=false;

    iter:

    R f1=f(x1); // x1 needed

    if (cpmverbose>mL) cpmdata

  • 4 cpmalgorithms.cpp

    while (res==0){

    R xn=state.x3+h; // h needed

    R fn=f(xn);

    state.shift(xn,fn);

    res=state.eval(); // xLimit needed (hidden)

    }

    // now res!=0

    if (res==1 ){

    if ((!local) || state.x3>=xMax){

    found=0;

    return X3(state.x2,state.x3,found);

    }

    else{

    x1=state.x3; // start where you ended, progress

    h=hStart;

    xLimit=xMax;

    local=false;

    goto iter;

    }

    }

    else if(res==2){

    found=1;

    return X3(state.x3,state.x3,found);

    }

    else if(res==3){

    found=2;

    return X3(state.x2,state.x3,found);

    }

    else{ // then res==4, we found a change in trend

    // which can be an indication that a local scan may find a

    // root between state.x1 and state.x3

    if (local){

    cpmmessage(mL,

    "CpmAlgorithms::brack(): trend change and no root");

    x1=state.x3; // start where you ended, progress

    h=hStart;

    xLimit=xMax;

    local=false;

    }

    else{

    cpmmessage(mL,

    "CpmAlgorithms::brack(): refinement on trend change");

    x1=state.x1; // start again at the same point, no progress

    xLimit=state.x3;

    h=dxMin; // have to take a closer look to a limited range at

    // higher resolution

    local=true;

    }

    // now we have new values for the iter ini data

    40

  • 4 cpmalgorithms.cpp

    goto iter;

    }

    }

    X2 CpmAlgorithms::root(const F& f, R xMin,

    R xMax, R dxMin, R dxMax, bool silent)

    {

    Z mL=3;

    Word loc("CpmAlgorithms::root(...)");

    cpmmessage(mL,loc&" started");

    const Z iterMax=40;

    const R redFac=0.05;

    X3 prr=brack(f,xMin,xMax,dxMin,dxMax);

    R x0=prr.c2();

    bool k=true;

    Z found=prr.c3();

    if (found==0){

    if (!silent) cpmwarning(loc&" could not bracket the root");

    k=false;

    }

    else if (found==1){

    ; // x0 and k are OK as already defined

    }

    else if (found==2){ // bisection

    R x1=prr.c1();

    R x2=prr.c2();

    x0=rootByBisection(f,x1,x2,dxMin*redFac,iterMax);

    }

    else{

    cpmerror("CpmAlgorithms::root() unvalid exit, found="

    &cpmwrite(found));

    }

    return X2(x0,k);

    }

    R CpmAlgorithms::solKepEqu(R M, R eps, R acc)

    {

    R xLast=M+1000, xNew=M;

    while ( cpmabs(xLast-xNew) > acc ){

    xLast=xNew;

    R x1=M+eps*cpmsin(xNew);

    R x2=M+eps*cpmsin(x1);

    xNew=(x1+x2)*0.5; // My standard provision against oscillations.

    // Works extremely well. Never seen this elsewhere.

    }

    return xNew;

    }

    R CpmAlgorithms::ssqe(R a, R b, R c, R xMin, R xMax)

    {

    41

  • 4 cpmalgorithms.cpp

    R x1,x2,w1,w2,n,xmin,xmax;

    if (a==0){ // linear equation

    if (b==0) return -1; else x1=-c/b;

    if (x1>=xMin && x10){ // two real solutions

    n=R(0.5)/a;

    w1=cpmsqrt(w2);

    x1=( b

  • 4 cpmalgorithms.cpp

    const Z iterMax=20;

    const Z mL=3;

    R range=xMax-xMin;

    if (range=mL)

    cpmmessage("rootFast(...): iterMax exhausted, count="&

    cpmwrite(count));

    43

  • 4 cpmalgorithms.cpp

    return X2(xRoot,false);

    }

    x1+=red*t;

    f1=f(x1);

    h=CpmRootX::inf(h,redComp*t);

    goto Iter;

    }

    X2 CpmAlgorithms::bisection(const F& f, R tF, R tT,

    R tacc, Z iterMax)

    {

    if (tacctacc && count++=iterMax)

    cpmwarning("CpmAlgorithms::bisection() exhausted iterMax");

    return X2(tF,tT);

    }

    R CpmAlgorithms::rootByBisection(const F& f, R x1, R x2,

    R xacc, Z iterMax)

    {

    Z mL=3;

    Word loc("CpmAlgorithms::rootByBisection(...)");

    CPM_MA

    R f1=f(x1);

    R f2=f(x2);

    R xM,fM;

    if (f1==0){

    cpmwarning(loc&" x1 found to be a root");

    CPM_MZ

    return x1;

    }

    if (f2==0){

    cpmwarning(loc&" x2 found to be a root");

    CPM_MZ

    return x2;

    }

    if (!signChange(f1,f2)){

    cpmerror(loc&": no sign change for initial values");

    return 0; // never get here

    }

    Z count=1;

    while( cpmabs(x1-x2)>xacc && count

  • 4 cpmalgorithms.cpp

    if (fM==0) return xM;

    if ( f1*fM=iterMax){

    cpmwarning(loc&": exhausted iterMax="&cpm(iterMax));

    cpmdebug(x1);

    cpmdebug(x2);

    }

    CPM_MZ

    return (x1+x2)*0.5;

    }

    R CpmAlgorithms::fixedPoint(const F& f, R const& x0,

    R eps, Z iterMax)

    {

    using CpmRoot::dis;

    R xOld=x0;

    R xNew=f(xOld);

    Z count=0;

    while(dis(xOld,xNew)>eps && count++ < iterMax ){

    xOld=xNew;

    R xAux=f(xOld);

    xNew=(f(xAux)+xAux)*0.5;

    }

    if (count>=iterMax)

    cpmwarning("CpmAlgorithms::fixedPoint() exhausted iterMax");

    return xNew;

    }

    //////////////////////// Quantizer /////////////////////////////////////

    // auxiliaries:

    namespace{

    Z qant0(R const& x){ return cpmrnd(x);}

    Z quantV(R const& x, const Vo& v)

    {

    return v.locate(x);

    45

  • 4 cpmalgorithms.cpp

    }

    Z quantIv(R const& x, const Iv& iv, const Z& n)

    {

    return iv.stair(x,n);

    }

    } // namespace

    // constructors

    CpmAlgorithms::Quantizer::Quantizer()

    {

    *this=F(qant0);

    }

    CpmAlgorithms::Quantizer::Quantizer(R xL, R xU, Z n)

    {

    Word loc("Quantizer::Quantizer(R xL, R xU, Z n)");

    cpmassert(n>0,loc);

    #ifdef CPM_Fn

    *this=F2(Iv(xL,xU),n)(quantIv);

    #else

    *this=F(bind(quantIv,_1,Iv(xL,xU),n));

    #endif

    }

    CpmAlgorithms::Quantizer::Quantizer(Iv iv, Z n)

    {

    Word loc("Quantizer::Quantizer(Iv iv, Z n)");

    cpmassert(n>0,loc);

    #ifdef CPM_Fn

    *this=F2(iv,n)(quantIv);

    #else

    *this=F(bind(quantIv,_1,iv,n));

    #endif

    // this stores the data iv, n that characterize the

    // instant of Quantizer constructed by the given constructor.

    // We could define another constructor of the class which stores a

    // completely different data structure; for example some complex

    // numbers. This shows that a class needs not to have a single data

    // member’layout’ if sufficiently flexible data structures are

    // available.

    }

    CpmAlgorithms::Quantizer::Quantizer(const V& x, bool ordered)

    {

    Z n=x.dim();

    if (n

  • 4 cpmalgorithms.cpp

    *this=F(constVal);

    }

    else{

    Vo y(x);

    if (!ordered) y=y.strictlyIncreasingVersion();

    #ifdef CPM_Fn

    *this=F1(y)(quantV);

    #else

    *this=F(bind(quantV,_1,y));

    #endif

    }

    }

    ////////////////////////// IntQuant ///////////////////////////////

    namespace{

    Z intQuant(const Z& i, const Z& zL, const Z& nP, R const& spanInv)

    {

    R p=R(i-zL)*spanInv;

    bool restrict=true;

    return Iv(0,1).quant(p,nP,restrict);

    }

    }

    CpmAlgorithms::IntQuant::IntQuant(Z xL, Z xU, Z n)

    {

    if (xL

  • 4 cpmalgorithms.cpp

    class quantil: public FncObj{

    Vo b;

    public:

    explicit quantil(const V& a):b(a){}

    R operator()(R const&)const;

    };

    R quantil::operator()(R const& p)const

    // notice: function quantil will only be called for b in ascendend order

    // quantil(0.5,b)=median(b);

    // quantil(0.25,b)=Hinge_1(b);

    // quantil(0,b)=minimum(b);

    // quantil(0.75,b)=Hinge_2(b);

    // quantil(1,b)=maximum(b);

    // see Weisstein: CRC Concise Encyclopedia of Mathematics p. 844 for

    // Hinge.

    // we use an obvious method to define this in cases where n is not of the

    // form

    // 4*m+5

    {

    R pp=p;

    if (pp1) pp=1;

    Z n=b.dim();

    if (n==0) return 0;

    R ir=R(n-1)*pp+1;

    if (ir==1.) return b[1];

    if (ir==n) return b[n];

    Z i=cpmtoz(ir);

    R frac=ir-i; // notice 0

    // notice that the initialization of u_ by the default constructor is

    // just right.

    // This structure of a constructor seems to be the most flexible one.

    }

    V CpmAlgorithms::Percentilizer::select(const Iv& iv)const

    {

    Z mL=4;

    48

  • 4 cpmalgorithms.cpp

    static Word loc("CpmAlgorithms::Percentilizer::select(Iv)");

    cpmmessage(mL,loc&" started");

    R iv1=iv[1];

    cpmassert(iv1>=0,loc);

    R iv2=iv[2];

    cpmassert(iv2

  • 4 cpmalgorithms.cpp

    return mean+v2*fac;

    }

    else{

    iset=0;

    return gset;

    }

    }

    ///////////////////// class PeriodicAlarm //////////////////////////////

    using CpmAlgorithms::PeriodicAlarm;

    PeriodicAlarm::PeriodicAlarm(R per, R tIni, R phase):

    active(true),

    period(per),

    counter(0),

    lastAlarm(tIni)

    {

    Z mL=3;

    static Word loc="PeriodicAlarm(R,R,R)";

    static R relTol=1e-8;

    CPM_MA

    if (period=0){

    Z fr=cpmtoz(tDiff/period); // starts with 0

    lastAlarm=t; // includes the case that t grows in steps larger

    // than period

    fr+=1;

    // fr should start with 1

    nextLatticePoint+=R(fr)*period;

    // nextLatticePoint+=period;

    counter+=fr;

    // counter++;

    return true;

    }

    50

  • 4 cpmalgorithms.cpp

    else{

    return false;

    }

    }

    //////////////////////// class SingleAlarm /////////////////////////////

    using CpmAlgorithms::SingleAlarm;

    bool SingleAlarm::operator()(R t)

    {

    if (done) return false;

    if (t>=alarmPoint){

    done=true;

    return true;

    }

    else{

    return false;

    }

    }

    //////////////////////// class CyclicAlarm /////////////////////////////

    using CpmAlgorithms::CyclicAlarm;

    CyclicAlarm::CyclicAlarm(Z per, Z cogIni, Z maxAlarms):

    period(per),cog(cogIni),counterMax(maxAlarms)

    {

    Z mL=3;

    static Word loc("CyclicAlarm(Z,Z,Z)");

    CPM_MA

    if (period=period) cog-=period;

    alarm=true;

    }

    CPM_MZ

    }

    void CyclicAlarm::step(void)

    {

    if (dormant){

    return;

    // don’t change state

    }

    else if (done){

    alarm=false;

    51

  • 4 cpmalgorithms.cpp

    }

    else{

    cog+=1;

    if (cog==period || cog==0){

    cog=0;

    alarm=true;

    counter+=1; // now this the number of alarms given

    if (counter==counterMax){

    done=true;

    alarm=false;

    }

    }

    else{

    alarm=false;

    }

    }

    }

    V CyclicAlarm::record(Z n)

    {

    V res(n);

    for (Z i=1;i

  • 4 cpmalgorithms.cpp

    void NonCyclicAlarm::step(void)

    {

    if (done){

    alarm=false;

    }

    else{

    cog+=1;

    if (cog==points_[counter]){

    alarm=true;

    counter+=1; // now this the number of alarms given

    if (counter>counterMax){

    // never call points_[counterMax+1]

    done=true;

    }

    }

    else{

    alarm=false;

    }

    }

    }

    //////////////////////// class BurstAlarm /////////////////////////////

    using CpmAlgorithms::BurstAlarm;

    BurstAlarm::BurstAlarm(Z per, Z burPer, Z burLen):

    Base(per,0,-1),burst(burPer,0,burLen)

    {

    Z mL=3;

    static Word loc("BurstAlarm(Z,Z,Z)");

    CPM_MA

    CPM_MZ

    }

    void BurstAlarm::step(void)

    {

    if (getAlarm() && burst.ready()) burst.restart();

    Base::step();

    burst.step();

    setAlarm(getAlarm()||burst.getAlarm());

    }

    ////////////////////////////////////////////////////////////////////////

    Z CpmAlgorithms::getNerFrc_1(R& x, R xL)

    {

    Z mL=4;

    Word loc("CpmAlgorithms::getNerFrc_1(R&,R)");

    CPM_MA

    Z res=0;

    53

  • 4 cpmalgorithms.cpp

    cpmassert(x

  • 5 cpmangle.h

    5 cpmangle.h

    //? cpmangle.h

    //? C+- by Ulrich Mutze. Status of work 2020-07-01.

    //? Copyright (c) 2020 Ulrich Mutze

    //? contact: see contact-info at www.ulrichmutze.de

    //?

    //? This program is free software: you can redistribute it and/or

    //? modify it under the terms of the GNU General Public License as

    //? published by the Free Software Foundation, either version 3 of

    //? the License, or (at your option) any later version.

    //?

    //? This program is distributed in the hope that it will be useful,

    //? but WITHOUT ANY WARRANTY; without even the implied warranty of

    //? MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

    //? GNU General Public License for

    //? more details.

    #ifndef CPM_ANGLE_H_

    #define CPM_ANGLE_H_

    //////////////////////////////////////////////////////////////////////////

    // Description: A class describing angles and the 1-dimensional

    // torus

    //////////////////////////////////////////////////////////////////////////

    #include

    #include

    #include

    namespace CpmGeo{

    using CpmRoot::R;

    using CpmRoot::Z;

    using CpmRoot::Word;

    using CpmRoot::C;

    using CpmArrays::V;

    enum AngleUnit { CYCLE, HOUR, DEG, RAD};

    // cycle (full angle), hour, degree, radian

    enum AngleRange { POS, NEG};

    // always positive, negative allowed

    enum AngleHex {DEC, MIN, SEC};

    // full decimal, minutes, minutes and seconds

    // friend functions need to be declared as belonging to the

    // present namespace

    class Angle;

    Angle mean(const CpmArrays::V& phi);

    Angle mean(const CpmArrays::V& angles,

    const CpmArrays::V& weights);

    55

  • 5 cpmangle.h

    Angle RealToAngle(R x, AngleUnit u, AngleHex h);

    Angle realToAngle(R c);

    class Angle{ // angles

    // An instance of Angle is an angle, the manifold of all angles is

    // a 1-dimensional torus. There are two interpretations.

    // (i) Angle as a coordinate on a circle (as a curve) and

    // (ii) angle as a descriptor of a rotation arround a given axis.

    // Both are closely related due to the fact, that the rotations act

    // transitively and effectively on a circle. For defining a proper set

    // of methods we have not to make a choice in favor of one of these

    // interpretations.

    // Interpretation (i) endows Angle most directly with the structure of

    // an oriented metric space, and (ii) with the structure of an

    // Abelian group.

    static void normalizeAngle(R& a0);

    // changes a0 into a value in the interval (-Pi,Pi] by adding

    // a multiples of 2*Pi

    R a_; // is read as alpha, is the measure of the angle as arc length

    // on the unit circle (for effective usage of built-in

    // trigonometric functions. The range is by definition (-Pi,Pi].

    void normalize(void){ normalizeAngle(a_);}

    public:

    typedef Angle Type;

    typedef R ScalarType;

    CPM_IO

    CPM_ORDER

    CPM_SUM_PLAIN

    CPM_DIFFERENCE_PLAIN

    // Addition and subtraction among angles as borrowed from the

    // mathematical model by residue classes in R ’modulo 2*Pi’.

    // A further mathematical model is given by

    // { z \in C : |z|=1 }. In this model addition of angles corresponds

    // to multiplication of complex numbers and subtraction of angles

    // corresponds to division of numbers. If we are simply given a

    // torus (e.g. as a thin ring of polished metal) then we need to mark

    // on it a point as origin and an arrow as direction in order map it

    // to any of the mathematical models considered here.

    // This implies that the algebraic structure of an abelian group

    // exhibited by both mathematical models is not inherent in the

    // geometry of the pure torus but depends on the selection of an

    // origin and a direction (orientation) as indicated above. Obviously

    // the selected origin plays the role of the neutral element of the

    // abelian group. Notice that the pure torus is a metric space

    56

  • 5 cpmangle.h

    // where the distance between two points is the length of the

    // curve along the torus (i.e. the shortest arc) which connects the

    // points.

    CPM_SCALAR_M

    // The meaning of multiplication with real numbers derives by

    // continuity from the meaning of multiplication by rational

    // numbers. Let us consider first multiplication by a natural

    // number n. The proper definition follows from the group

    // structure: alpha*n := alpha + ... + alpha (n terms).

    // Multiplication by 1/m for natural number:

    // alpha*(1/m) := smallest angle beta for which beta*m=Angle(),

    // where Angle() is the zero angle which is the unit element of

    // the group. Smallness, obviously, refers to the distance to

    // the unit element. Obviously, one may add (2*Pi)/m to beta

    // (let the result be called beta’) and one also has

    // beta’*m=Angle().

    CPM_CONJUGATION

    // An idempotent conjugation operation. If the angle is interpreted

    // as the phase angle of a complex number, this corresponds to

    // the complex conjugation of the number. This is a natural

    // geometric operations for angles, resulting from the distinction

    // of one angle as the zero-angle (origin on torus).

    Word nameOf()const{ return Word("Angle");}

    R operator /(const Angle&)const;

    // alpha/beta is the number r for which beta*r=alpha.

    // Notice the comment to ScalarType on multiplying

    // Angles by numbers. This is not defined in residue

    // classes modulo 2*Pi.

    // Products of angles don’t give angles; they are

    // omitted here.

    Angle operator+(R shift)const{ return Angle(a_+shift,false);}

    // Returning the angle which results from *this by adding an arc

    // which may be any length (e.g. much larger than 2*Pi) and sign.

    // This gives Angle the structure of an affine space.

    // constructors

    Angle(void):a_(0.){}

    // angle zero

    explicit Angle(R angle, bool deg=true);

    // Constructor for Angles out of real numbers. The first argument

    // is always interpreted as an angle in degrees, unless deg==0

    // Never enable automatic conversion. Would result in ambiguous

    // arithmetics. Input needs not to be normalized.

    57

  • 5 cpmangle.h

    Angle(R vAngle, AngleUnit au);

    // creates an angle which is vAngle*au

    explicit Angle(C const& z):a_(z.arg()){}

    // Constructs the phase angle (polar angle) of z

    C expi()const{ return C(1.,a_,"polar");}

    // Returns the complex number exp(i*a). Thus Angle now has a

    // bi-directional efficient interface to C.

    // automatic conversion in one direction Angle-->R is OK

    operator R(void)const{return a_;}

    // cast to R for making trigonometric functions defined for angles

    // No longer used in the implementation of Angle.

    R toR()const{ return a_;}

    // Explicit conversion in a standard manner. The implementation of

    // Angle now relies on this.

    R cut( R c)const;

    //: cut

    // Returns a value in the range (c*degree-2*Pi,c*degree] which from

    // a_ is derived by adding or subtracting a multiple of 2*Pi.

    // To have such a facility turned out to be very useful in

    // dealing with angular motion of stepper motors.

    void qun_(Z n);

    //: quantize

    // Changes angle *this into the nearest of n equi-spaced

    // angles which are equi-distributed over the whole range.

    // For n

  • 5 cpmangle.h

    friend Word AngleToWord(const Angle& alpha,

    AngleUnit u, AngleRange r, AngleHex h, Z digits=1)

    { return alpha.toWord(u,r,h,digits);}

    // modifying an angle

    void setArc(R alpha);

    // input is an arc (i.e. something like a, but need not be

    // normalized)

    // absolute value

    R abs(void)const{ return (a_>=0. ? a_ : -a_);}

    // absolute value: positive arc as a number (distance from zero

    // angle)

    R dis(const Angle& phi)const;

    //: distance

    // Lets angles form a metric space. Is symmetric in the arguments.

    // Implementation corrected 2016-03-25 (symmetry was not guaranteed

    // before)

    bool isPos()const{ return a_>=0;}

    // returns true if the angle is in quadrant 1 or 2 (by definition,

    // 0 belongs to quadrant 1, Pi to quadrant 2 ) and false else

    void pos(){ if (a_

  • 5 cpmangle.h

    static V smoothAngleList(const V& va);

    // Given a list va of Angles, we return a list res of corresponding

    // R’s such that

    // res[i]==va[i] mod(2*Pi)

    // where adding or subtracting of 2*Pi is done such that the

    // resulting list is as smooth as possible. More precisely we

    // assure that for each i

    // | res[i+i]-res[i]| < |res[i+1]+2*Pi-res[i]|

    // and

    // | res[i+i]-res[i]| < |res[i+1]-2*Pi-res[i]|

    // As a result of this the res[i] may grow to much larger values

    // than 2*Pi as in a list of successive angular positions of a

    // rotating wheel.

    static V smoothList(const V& vr);

    // Similar to previous function. The argument list is not a list

    // of angles but a list of their conversions to numbers (based

    // on the RAD unit).

    static Angle deg1, deg90, deg180, deg270, deg360;

    };

    } // namespace

    #endif

    60

  • 6 cpmangle.cpp

    6 cpmangle.cpp

    //? cpmangle.cpp

    //? C+- by Ulrich Mutze. Status of work 2020-07-01.

    //? Copyright (c) 2020 Ulrich Mutze

    //? contact: see contact-info at www.ulrichmutze.de

    //?

    //? This program is free software: you can redistribute it and/or

    //? modify it under the terms of the GNU General Public License as

    //? published by the Free Software Foundation, either version 3 of

    //? the License, or (at your option) any later version.

    //?

    //? This program is distributed in the hope that it will be useful,

    //? but WITHOUT ANY WARRANTY; without even the implied warranty of

    //? MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

    //? GNU General Public License for

    //? more details.

    //Description: see cpmangle.h

    #include

    using namespace CpmStd;

    using namespace CpmGeo;

    using CpmRoot::R;

    using CpmRoot::Z;

    using CpmRoot::C;

    using CpmRoot::Word;

    namespace{

    const R fullAngle=cpmpi*2;

    const R iFullAngle=R(1.)/fullAngle;

    const R hour=fullAngle/24;

    }

    Angle Angle::deg1(1,DEG);

    Angle Angle::deg90(90,DEG);

    Angle Angle::deg180(180,DEG);

    Angle Angle::deg270(270,DEG);

    Angle Angle::deg360(360,DEG);

    void Angle::normalizeAngle(R& a)

    {

    if (a>-cpmpi && a

  • 6 cpmangle.cpp

    a*=iFullAngle;

    a-=cpmfloor(a);

    if (a>0.5) a-=1;

    a*=fullAngle;

    }

    Angle::Angle(R angle, bool deg):a_(angle)

    {

    if (deg) a_*=cpmdeg;

    normalize();

    }

    Angle::Angle(R angle, AngleUnit au):a_(angle)

    {

    if (au==RAD){

    ;

    }

    else if (au==DEG){

    a_*=cpmdeg;

    }

    else if (au==CYCLE){

    a_*=fullAngle;

    }

    else if (au==HOUR){

    a_*=hour;

    }

    else{

    cpmerror("Angle(R, AngleUnit): unvalid AngleUnit");

    }

    normalize();

    }

    void Angle::setArc(R alpha)

    {

    a_=alpha;

    normalize();

    }

    namespace{

    void quantize(R& x, Z n)

    {

    R y=x*n;

    y=cpmfloor(y+0.5);

    x=y/n;

    }

    }

    Angle& Angle::operator +=(const R& s)

    {

    a_+=s;

    62

  • 6 cpmangle.cpp

    normalize();

    return *this;

    }

    Angle& Angle::operator *=(const R& s)

    {

    a_*=s;

    normalize();

    return *this;

    }

    Angle Angle::operator -(void)const

    {

    Angle res;

    res.a_=-a_;

    res.normalize();

    return res;

    }

    Angle& Angle::operator +=(const Angle& s )

    {

    a_+=(s.a_);

    normalize();

    return *this;

    }

    Angle& Angle::operator -=(const Angle& a1 )

    {

    a_-=a1.a_;

    normalize();

    return *this;

    }

    Angle Angle::operator +(const Angle& a1)const

    {

    return Angle(a_+a1.a_,RAD);

    }

    Angle Angle::operator -(const Angle& a1)const

    {

    return Angle(a_-a1.a_,RAD);

    }

    R Angle::operator /(const Angle& a1)const

    {

    R a1Inv=cpminv(a1.a_);

    return a_*a1Inv;

    }

    Angle Angle::con(void)const

    63

  • 6 cpmangle.cpp

    {

    if (a_==cpmpi) return *this;

    else return Angle(-a_,RAD);

    }

    R Angle::cut(R c)const

    {

    R lim=c*cpmdeg;

    R ar=a_+fullAngle;

    if (ar>lim) ar-=fullAngle;

    return ar;

    }

    bool Angle::prnOn(ostream& out)const

    {

    return CpmRoot::write(a_,out);

    }

    bool Angle::scanFrom(istream& in)

    {

    bool res=CpmRoot::read(a_,in);

    normalize();

    return res;

    }

    Angle CpmGeo::mean(const CpmArrays::V& angles)

    {

    Z i,n=angles.dim();

    Word loc("Angle CpmGeo::mean(const CpmArrays::V& angles)");

    cpmassert(n>0,loc);

    C z,sum(0,0);

    for (i=1;i0,loc);

    cpmassert(n1>=n,loc);

    C z,sum(0,0);

    for (i=1;i

  • 6 cpmangle.cpp

    sum+=z*weights[i];

    }

    R r,phi;

    sum.toPolar(r,phi);

    return Angle(phi,RAD);

    }

    Z Angle::com(const Angle& a1)const

    {

    if (a_a1.a_) return -1;

    else return 0;

    }

    R Angle::dis(const Angle& phi)const

    {

    Angle a1=*this - phi;

    Angle a2= phi - *this;

    R d1=cpmabs(a1.toR());

    R d2=cpmabs(a2.toR());

    return cpminf(d1,d2)*iFullAngle;

    }

    R Angle::toDeg(Z i)const // ’to degrees’

    {

    static R iDegree=R(180)/cpmpi;

    R b=a_*iDegree;

    if (i==1){

    if (b

  • 6 cpmangle.cpp

    if (digits==6) ff="%-#8.6f";

    if (y

  • 6 cpmangle.cpp

    Angle CpmGeo::RealToAngle(R x, AngleUnit u, AngleHex h)

    {

    const R i60=1./60.;

    Z sign;

    Angle res;

    if (h==DEC){

    if (u==CYCLE) x*=fullAngle;

    if (u==HOUR) x*=hour;

    if (u==DEG) x*=cpmdeg;

    Angle::normalizeAngle(x);

    res.a_=x;

    return res;

    }

    if (x

  • 6 cpmangle.cpp

    V res(n);

    for (i=1;i

  • 7 cpmapplication.h

    7 cpmapplication.h

    //? cpmapplication.h

    //? C+- by Ulrich Mutze. Status of work 2020-07-01.

    //? Copyright (c) 2020 Ulrich Mutze

    //? contact: see contact-info at www.ulrichmutze.de

    //?

    //? This program is free software: you can redistribute it and/or

    //? modify it under the terms of the GNU General Public License as

    //? published by the Free Software Foundation, either version 3 of

    //? the License, or (at your option) any later version.

    //?

    //? This program is distributed in the hope that it will be useful,

    //? but WITHOUT ANY WARRANTY; without even the implied warranty of

    //? MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

    //? GNU General Public License for

    //? more details.

    #ifndef CPM_APPLICATION_H

    #define CPM_APPLICATION_H

    ///////////////// Introductory section ///////////////////////////////////

    //

    // Description: Provides an application framework that makes

    // convenient graphical and messaging capabilities available.

    //

    // The user has to provide the definition of function

    // Z CpmApplication::main_(void).

    // The definition of the function

    // int main(int argc, char *argv[]),

    // which each C++ program has to define, is provided by having

    // cpmapplication.cpp among the source files of the C++ project.

    // The context in which main_() is called in cpmapplication.cpp

    // provides all C+- communication capabilities by having done all

    // necessary initializations.

    //

    // The following code gives a simple, though realistic example.

    // It is ment as content of a source file smallexperiments.cpp. In

    // reading this code, please ignore the leading comment indicators ’//’.

    // If we would switch here to the C comment style, my simple

    // documentation scripts are likely to get fooled.

    //

    //#include

    //#include

    //#include

    //#include

    //#include

    //#include

    69

  • 7 cpmapplication.h

    //#include

    // // not all needed for test3()

    //

    //using namespace CpmRoot;

    //using namespace CpmRootX;

    //using namespace CpmSystem;

    //using namespace CpmFunctions;

    //using namespace CpmArrays;

    //using namespace CpmGraphics;

    //using namespace CpmImaging;

    //using namespace CpmApplication;

    //using namespace CpmGeo;

    //

    //R tWait=0;

    // ...

    //void test3()

    //{

    // // test of composing several images into one

    // Word dr=Message::ext("images");

    // Word n11=glue(dr,"bussard.ppm");

    // Word n12=glue(dr,"gnom.ppm");

    // Word n21=glue(dr,"thomas_meier.ppm");

    // Word n22=glue(dr,"kohlmeise1.ppm");

    //

    // VV vv(2,2); // 2 by 2 matrix of images

    // vv[1][1]=Img24(n11);

    // vv[1][2]=Img24(n12);

    // vv[2][1]=Img24(n21);

    // vv[2][2]=Img24(n22);

    // Z m=750, n=1000; // height and width of combined

    // // image

    // ImgR ir(vv,m,n);

    // // combined image, auto-layout

    // Graph g;

    // ir.mark(g);

    // g.dis(true);

    // // shows the composed image and writes a ppm

    // cpmwait(tWait,2); // remaining wait time to be displayed

    // // on pane 2 of the status bar. There are 4 panes,

    // // the first one is for news from CpmSystem::Message.

    //}

    //// define functions test1(), test2()

    // ....

    //

    //Z CpmApplication::main_(void)

    //{

    // Z mL=1;

    // Z sel=args_[2].toZ();

    // Word loc("CpmApplication::main_(), sel="&cpm(sel));

    // // if sel is not given in the comand-line it will be read from

    70

  • 7 cpmapplication.h

    // // an inifile the name of which is shortNameOfExecutable.ini

    // // In the present example I name the executable

    // smallexperimentsMS.exe

    // // and the ini file is smallexperiments.ini. This is unrelated to

    // // title_ which only by chance is the same.

    // CPM_MA

    // title_="smallexperiments";

    // tWait=args_[6].toR();

    // if (sel==1) test1();

    // else if (sel==2) test2();

    // else if (sel==3) test3();

    // else test4();

    // CPM_MZ

    // return 0;

    //}

    //////////////////////////////////////////////////////////////////////////

    #include

    namespace CpmSystem{

    void updFromConfigFile();

    // update from file config.ini

    // Tries to access a file named cpmconfig.ini at directory positions

    // which are set in file systemdependencies.h. Most of the quantities

    // that are defined by define macros in systemdependencies.h can be

    // read from this file and thus redefined. This redefinition affects

    // static data of class Message and thus does not require recompilation

    // (which a changing a define in cpmsystemdependencies.h would).

    // The most important quantities to be set in cpmconfig.ini are the

    // size of the graphical application window, the directory locations

    // or application specific ini-files and the directory location for

    // output from the application.

    }

    namespace CpmApplication{

    void inspectCpmdefinitions();

    void inspectCpmsystemdependencies();

    // Provides a framework for defining c o n s o l e applications which

    // offer convenient graphical and messaging capabilities.

    //

    // Both capabilities can be eliminated at compile time by enabling or

    // disabling the lines

    // #define CPM_NOGRAPHICS

    // and

    // #define CPM_NOLOG

    // in file cpmsystemdependencies.h.

    71

  • 7 cpmapplication.h

    // If CPM_NOGRAPHICS is defined, no graphics or images can be shown on

    // screen. But they still can be created in memory and written to file

    // in the portable pix-map format (*.ppm). The size of these images is

    // not limited to screen size. With this setting of CPM_NOGRAPHICS,

    // the program needs not to be linked with its screen graphics enabling

    // library, which is OpenGL and (Open)GLUT. It then also needs no

    // access to to the gl and glut header files. Of course, this is only

    // possible since all graphical primitives, including fonts (greek

    // included) are implemented within C+-.

    // Disabling message streams to the console and to log-files (as done

    // by #define CPM_NOLOG) was essential in a large industrial program

    // where my C+- program translated the intended motions of a complex

    // wire bending tool into stepper motor control files.

    // To the IT-professional, who had finally to put all these control

    // files together and to download them to the the wire-O bending robot,

    // the messages from my program were disturbing and he was happy to

    // hear that there was no problem switching them off. During my

    // development and testing of many C+- programs, these messages played

    // such a vital role that I failed to anticipate that in a different

    // mode of usage, there are different priorities and needs.

    // Many of the design decisions in C+- are actually revisions of old

    // decisions which turned out to support adaption to new needs not

    // as efficiently as they should.

    // A C + - a p p l i c a t i o n (not just a C++ application which

    // uses some C+- classes) has cpmapplication.cpp among its source

    // files and defines the function

    // Z CpmApplication::main_(void)

    // in its highest-level source files. This highest level source file

    // (which typically has a name that characterizes the application,

    // and for which a ’cpm’ in the name would be misleading) has to

    // include the present file cpmapplication.h. The function

    // int main(int argc, char *arv[])

    // which a console application needs to define, is defined in

    // cpmapplication.cpp in a way which depends on CPM_NOGRAPHICS and

    // CPM_NOLOG as explained above.

    // See cpminifilebasapp.h for an extensions of the C+- application

    // framework in applications based on reading ini-files.

    // Presently the usability of the C+- application framework

    // for parallel computing is not yet clarified. The PaLa program

    // (which is a C+- application) compiles with defined(CPM_USE_MPI) but

    // fails during run.

    using CpmRoot::Word;

    using CpmRoot::Z;

    using CpmArrays::V;

    // data

    72

  • 7 cpmapplication.h

    extern Word title_;

    // Title of the whole program. Most conveniently to be defined

    // within function main_() as in the example of the Introductory

    // section.

    extern V args_;

    // An array that waits to get initialized by commandline arguments

    // and by additional arguments which may be provided by an ini-file.

    // In a C+- application (see definition above) args_[1] holds always

    // the full name (including directory location) of the program’s

    // executable.

    // In calling such a program from the command line, one may enter

    // additonal parametes, which main(...) transforms into components

    // of args_. Such additional parameters do not affect any function

    // defined in cpmapplication.cpp. They can be used however in

    // programming the following function Z main_(), see the

    // introductory section of the present file for an example.

    // Function main, as implemented in cpmapplication.cpp always

    // checks for a file cpmconfig.ini for getting additional data.

    // From data which are both given on the command line and in the

    // cpmconfig.ini, the command line always wins. In addition

    // to cpmconfig.ini a file, here symbolically named

    // ’shortNameOfExecutable’.ini is tried to read for further input.

    // See function

    // V CpmRootX::extComLine(int argc, char *argv[]);

    // in files cpmrecordhandler.(h,cpp).

    // The class IniFileBasedApplication introduces a particular form of

    // args_ as a list consisting of:

    // selection,

    // verbosity,

    // initial wait time,

    // relative path of further input data,

    // final wait time.

    // This structure and meaning needs, however, not be followed in an

    // implementation of of main_().

    // V is the most flexible among the lower-level data types

    // and it should not, at this place, be replaced by a more specific

    // one.

    extern Word iniFile_;

    // functions

    Z main_(void);

    // Defines the main work of the program.

    // The function has available data args_.

    // Defining code is allowed to rely on correct initialization of

    // graphical, font-related, and directory-related matters.

    73

  • 7 cpmapplication.h

    // The details of this initialization mechanism are described in

    // cpmapplications.cpp as comments to function

    // int main(int argc, char *argv[])

    } // namespace

    #endif

    74

  • 8 cpmapplication.cpp

    8 cpmapplication.cpp

    //? cpmapplication.cpp

    //? C+- by Ulrich Mutze. Status of work 2020-07-01.

    //? Copyright (c) 2020 Ulrich Mutze

    //? contact: see contact-info at www.ulrichmutze.de

    //?

    //? This program is free software: you can redistribute it and/or

    //? modify it under the terms of the GNU General Public License as

    //? published by the Free Software Foundation, either version 3 of

    //? the License, or (at your option) any later version.

    //?

    //? This program is distributed in the hope that it will be useful,

    //? but WITHOUT ANY WARRANTY; without even the implied warranty of

    //? MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

    //? GNU General Public License for

    //? more details.

    #include

    #include

    #include

    #include

    #include

    #include

    #if defined(CPM_USE_BOOST)

    #include

    #endif

    // see cpmsystemdependencies.h for this option

    using CpmRoot::Word;

    using CpmRoot::Z;

    using CpmRoot::R;

    using CpmRootX::RecordHandler;

    using CpmRootX::extComLine;

    using CpmRootX::sup;

    using CpmArrays::V;

    using CpmSystem::Message;

    using CpmSystem::updFromConfigFile;

    using namespace std;

    void CpmSystem::updFromConfigFile(void)

    // When this gets called, the file cpmcerr is yet working

    {

    Z mL=1;

    Word loc("CpmSystem::updFromConfigFile()");

    CPM_MA

    75

  • 8 cpmapplication.cpp

    Word fn0("cpmconfig.ini");

    Word fn1=CpmSystem::glue(Message::relPos1,fn0);

    Word fn2=CpmSystem::glue(Message::relPos2,fn0);

    Word fn3=CpmSystem::glue(Message::relPos3,fn0);

    Word fn4=CpmSystem::glue(Message::relPos4,fn0);

    V vc{fn1,fn2,fn3,fn4};

    RecordHandler rch(vc,"","call in updFromConfigFile()");

    if (!rch.isVal()){

    cpmmessage("file cpmconfig.ini not found");

    CPM_MZ

    return;

    }

    else cpmmessage("file cpmconfig.ini found");

    Z ped=1; // degree of pedantary

    // all data are initialized anyway, so 1 is OK

    bool suc=false; // success

    Word sec="input directory";

    suc=rch.read(sec,"dir",Message::inpDir,ped);

    if (suc) cpmmessage("input directory got from cpmconfig.ini as "

    &Message::inpDir);

    sec="output directory";

    suc=rch.read(sec,"dir",Message::outDir2,ped);

    if (suc) cpmmessage("output directory got from cpmconfig.ini as "

    &Message::outDir2);

    // Directory will be created if not yet exists. For this very convenient

    // functionality we need the boost_filesystem library

    #if defined(CPM_USE_BOOST)

    cpmmessage("CPM_USE_BOOST is defined");

    boost::filesystem::path outPath(Message::outDir2.str());

    bool b=boost::filesystem::exists(outPath);

    if (b){

    cpmmessage("output directory "&Message::outDir2&" already exists");

    }

    else{

    cpmmessage("output directory "&Message::outDir2&" does not yet\

    exist");

    bool b1=boost::filesystem::create_directory(outPath);

    if (b1) cpmmessage("output directory "&Message::outDir2&" created");

    cpmassert(b1,loc);

    cpmassert(boost::filesystem::exists(outPath),loc);

    }

    #endif

    sec="font directory";

    rch.read(sec,"dir",Message::fontDir,ped);

    cpmmessage("font directory got from cpmconfig.ini as "

    &Message::fontDir);

    76

  • 8 cpmapplication.cpp

    sec="size of viewport";

    rch.read(sec,"width",Message::vpw_,ped);

    rch.read(sec,"height",Message::vph_,ped);

    sec="size of frame store";

    rch.read(sec,"width",Message::fsw_,ped);

    rch.read(sec,"height",Message::fsh_,ped);

    sec="double buffering";

    rch.read(sec,"db",CpmGraphics::Rec::db,ped);

    sec="pane sizes";

    rch.read(sec,"pane1",Message::sttBarWid1,ped);

    rch.read(sec,"pane2",Message::sttBarWid2,ped);

    rch.read(sec,"pane3",Message::sttBarWid3,ped);

    rch.read(sec,"pane4",Message::sttBarWid4,ped);

    sec="write precision";

    rch.read(sec,"val",CpmRoot::wrtPrc,ped);

    #if defined(CPM_MP) // muliple precision

    #if defined(CPM_USE_MPREAL)

    Z val;

    sec="numerical precision";

    rch.read(sec,"val",val,ped);

    if (val > 0){

    CpmRoot::numPrc=val;

    cpmprec(CpmRoot::numPrc);

    cpmmessage(loc&": numerical precision changed to "&

    cpm(CpmRoot::numPrc));

    }

    else{

    CpmRoot::numPrc=CPM_MP;

    cpmprec(CpmRoot::numPrc);

    cpmmessage(loc&

    ": no change of numerical precision from cpmconfig.ini");

    };

    #else // then we have no input from cpmconfig.ini

    cpmmessage(loc&": numerical precision is "&cpm(Z(CPM_MP)));

    #endif

    #else // no multiple precision

    #if defined(CPM_LONG)

    cpmmessage("numerical precision is that of type long double");

    #else

    cpmmessage("numerical precision is that of type double");

    #endif

    #endif

    sec="write title";

    77

  • 8 cpmapplication.cpp

    rch.read(sec,"val",CpmRoot::wrtTit,ped);

    sec="append run id";

    rch.read(sec,"val",Message::appRunId,ped);

    // CpmApplication::doc_= Message::appRunId;

    // If doc_ is true, a copy of cpmcerr.txt and cpmdata.txt will be

    // made at the end of program execution with runId appended.

    sec="run id length ";

    rch.read(sec,"val",Message::runIdLength,ped);

    CpmTime::Greg date;

    date.now();

    Message::runId=date.getCode().tail(Message::runIdLength);

    // re-setting runId with proper length. Since the old Id needs to be

    // changed anyway it is not useful to take the old one and cut or

    // extend it

    #if !defined(CPM_NOLOG)

    sec="suppress messages";

    rch.read(sec,"val",Message::silent,ped);

    #endif

    sec="stereo colors";

    V left, right;

    rch.read(sec,"left",left,ped);

    rch.read(sec,"right",right,ped);

    if (left.dim()==3){

    CpmImaging::stereoLeftR=left[1];

    CpmImaging::stereoLeftG=left[2];

    CpmImaging::stereoLeftB=left[3];

    }

    if (right.dim()==3){

    CpmImaging::stereoRightR=right[1];

    CpmImaging::stereoRightG=right[2];

    CpmImaging::stereoRightB=right[3];

    }

    CPM_MZ

    }

    Word CpmApplication::title_("defaulttitle");

    V CpmApplication::args_=V(0);

    #include

    using CpmGraphics::Frame;

    using CpmApplication::main_;

    using CpmApplication::title_;

    using CpmApplication::args_;

    78

  • 8 cpmapplication.cpp

    namespace{

    // variables common to functions main and idleFunc

    Word loc_;

    Word argv_;

    }

    namespace CpmApplication{

    void inspectCpmdefinitions()

    {

    V definitions;

    #if defined(CPM_NAMEOF)

    definitions&="CPM_NAMEOF";

    #endif

    #if defined(CPM_LONG)

    definitions&="CPM_LONG";

    #endif

    #if defined(CPM_USECOUNT)

    definitions&="CPM_USECOUNT";

    #endif

    #if defined(CPM_RANGE_CHECK)

    definitions&="CPM_RANGE_CHECK";

    #endif

    #if defined(CPM_USE_MPI)

    definitions&="CPM_USE_MPI";

    #endif

    #if defined(CPM_MP)

    Z val=CPM_MP;

    definitions&=("CPM_MP = "&cpm(val));

    #endif

    #if defined(CPM_USE_MPREAL)

    definitions&="CPM_USE_MPREAL";

    #endif

    #if defined(CPM_FIGURE_FOR_PUBLICATION_1)

    definitions&="CPM_FIGURE_FOR_PUBLICATION_1";

    #endif

    #if defined(CPM_USE_MPI)&&defined(CPM_MP)

    mes="parallel execution presently not compatible ";

    mes&="with multiple precision";

    cpmerror(mes);

    #endif

    cpmcerr

  • 8 cpmapplication.cpp

    #if defined(CPM_REL_POS1)

    val=CPM_REL_POS1;

    dependencies&=("CPM_REL_POS1 = "&val);

    #endif

    #if defined(CPM_REL_POS2)

    val=CPM_REL_POS2;

    dependencies&=("CPM_REL_POS2 = "&val);

    #endif

    #if defined(CPM_REL_POS3)

    val=CPM_REL_POS3;

    dependencies&=("CPM_REL_POS3 = "&val);

    #endif

    #if defined(CPM_REL_POS4)

    val=CPM_REL_POS4;

    dependencies&=("CPM_REL_POS4 = "&val);

    #endif

    #if defined(CPM_INP_DIR)

    val=CPM_INP_DIR;

    dependencies&=("CPM_INP_DIR = "&val);

    #endif

    #if defined(CPM_OUT_DIR)

    val=CPM_OUT_DIR;

    dependencies&=("CPM_OUT_DIR = "&val);

    #endif

    #if defined(CPM_FONT_DIR)

    val=CPM_FONT_DIR;

    dependencies&=("CPM_FONT_DIR = "&val);

    #endif

    #if defined(CPM_HEIGHT)

    i=CPM_HEIGHT;

    dependencies&=("CPM_HEIGHT = "&cpm(i));

    #endif

    #if defined(CPM_WIDTH)

    i=CPM_WIDTH;

    dependencies&=("CPM_WIDTH = "&cpm(i));

    #endif

    #if defined(CPM_PANE1)

    i=CPM_PANE1;

    dependencies&=("CPM_PANE1 = "&cpm(i));

    #endif

    #if defined(CPM_PANE2)

    i=CPM_PANE2;

    dependencies&=("CPM_PANE2 = "&cpm(i));

    #endif

    #if defined(CPM_PANE3)

    i=CPM_PANE3;

    dependencies&=("CPM_PANE3 = "&cpm(i));

    #endif

    #if defined(CPM_PANE4)

    i=CPM_PANE4;

    80

  • 8 cpmapplication.cpp

    dependencies&=("CPM_PANE4 = "&cpm(i));

    #endif

    #if defined(CPM_STEREOLEFT_R)

    i=CPM_STEREOLEFT_R;

    dependencies&=("CPM_STEREOLEFT_R = "&cpm(i));

    #endif

    #if defined(CPM_STEREOLEFT_G)

    i=CPM_STEREOLEFT_G;

    dependencies&=("CPM_STEREOLEFT_G = "&cpm(i));

    #endif

    #if defined(CPM_STEREOLEFT_B)

    i=CPM_STEREOLEFT_B;

    dependencies&=("CPM_STEREOLEFT_B = "&cpm(i));

    #endif

    #if defined(CPM_STEREORIGHT_R)

    i=CPM_STEREORIGHT_R;

    dependencies&=("CPM_STEREORIGHT_R = "&cpm(i));

    #endif

    #if defined(CPM_STEREORIGHT_G)

    i=CPM_STEREORIGHT_G;

    dependencies&=("CPM_STEREORIGHT_G = "&cpm(i));

    #endif

    #if defined(CPM_STEREORIGHT_B)

    i=CPM_STEREORIGHT_B;

    dependencies&=("CPM_STEREORIGHT_B = "&cpm(i));

    #endif

    #if defined(CPM_RUN_ID_LENGTH)

    i=CPM_RUN_ID_LENGTH;

    dependencies&=("CPM_RUN_ID_LENGTH = "&cpm(i));

    #endif

    #if defined(CPM_WRITE_PRECISION)

    i=CPM_WRITE_PRECISION;

    dependencies&=("CPM_WRITE_PRECISION = "&cpm(i));

    #endif

    #if defined(CPM_WRITE_TITLE)

    dependencies&="CPM_WRITE_TITLE";

    #endif

    #if defined(CPM_NOLOG)

    dependencies&="CPM_NOLOG";

    #endif

    #if defined(CPM_NOGRAPHICS)

    dependencies&="CPM_NOGRAPHICS";

    #endif

    #if defined(CPM_USE_BOOST)

    dependencies&="CPM_USE_BOOST";

    #endif

    #if defined(CPM_USE_EIGEN)

    dependencies&="CPM_USE_EIGEN";

    81

  • 8 cpmapplication.cpp

    #endif

    #if defined(CPM_DIMDEF2)

    dependencies&="CPM_DIMDEF2";

    #endif

    #if defined(CPM_DIMDEF3)

    dependencies&="CPM_DIMDEF3";

    #endif

    #if defined(CPM_POINT_PARTICLES)

    dependencies&="CPM_POINT_PARTICLES";

    #endif

    #if defined(CPM_M)

    dependencies&="CPM_M";

    #endif

    cpmcerr

  • 8 cpmapplication.cpp

    image edges safely away from the centers of pixels, while moving line

    vertices close enough to the pixel