From: Dariusz Murakowski Date: Mon, 6 Jul 2015 16:20:15 +0000 (-0400) Subject: Code for doing Potts Monte Carlo (optionally with fixed epitope), from John Barton... X-Git-Url: http://src.murakowski.org/?a=commitdiff_plain;h=5bf53deb3213dd88f38d11f8c7521770b7cd791e;p=VirEvoDyn.git Code for doing Potts Monte Carlo (optionally with fixed epitope), from John Barton 20150630. --- diff --git a/MC code.zip b/MC code.zip new file mode 100644 index 0000000..bfb9668 Binary files /dev/null and b/MC code.zip differ diff --git a/MC_code.txt b/MC_code.txt new file mode 100644 index 0000000..b75259f --- /dev/null +++ b/MC_code.txt @@ -0,0 +1,21 @@ +from: John P Barton +to: Dariusz Krzysztof Murakowski +date: Tue, Jun 30, 2015 at 6:21 PM +subject: MC Code + +Hi Dariusz, + +Here’s the MC code. The names are a little bit weird since I’ve been using it to evaluate epitope (or “epitope”) strengths. Example usage: + +g++ mainQEE.cpp io.cpp monteCarlo.cpp qEpitopeEval.cpp tools.cpp -O2 -march=native -o qee.out +./qee.out -i (input couplings) -o (place to send the output) -mcb (number of MC samples to take) + +mainQEE is basically just used to read in the command line options. qEpitopeEval contains the main routine, and as you might have guessed monteCarlo holds all the MC routines. If you need any help with running it, let me know! + +Thanks, +John + + +Attachments: +MC code.zip (26 KB) + diff --git a/dataStructures.h b/dataStructures.h new file mode 100755 index 0000000..3939481 --- /dev/null +++ b/dataStructures.h @@ -0,0 +1,87 @@ +#ifndef DATASTRUCTURES_H +#define DATASTRUCTURES_H + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tools.h" // Numerical tools + + + +// PROGRAM SETTINGS + +// This class holds the parameters needed for running the adaptive cluster algorithm + +class RunParameters { + +public: + + std::string directory; // Path to the directory where the inut file is located + // Output will also be sent to this directory + std::string infile; // Input file (prefix) + std::string ssinfile; // Input file for secondary structure (default selected clusters) + std::string outfile; // Output file (prefix) + + int kmin; // Minimum cluster size before computation is truncated + int kmax; // Maximum cluster size before computation is truncated + double sampleB; // Number of samples used to compute correlations from data + double gamma0; // Reference entropy regularization strength + double gamma2; // Cluster entropy regularization strength + double thetaMin; // The minimum cutoff value (loop starts here) + double thetaMax; // The maximum cutoff value (loop ends here) + double thetaStep; // Size of logarithmic steps when looping over theta + int b; // Number of data points to take in a single Monte Carlo run + int runs; // Number of times to run Monte Carlo dynamics + bool computeGamma; // If true, compute regularization strength based on number of samples + bool useLax; // If true, use a laxer cluster construction rule + bool useRef; // If false, do not use the reference entropy S0 (i.e. set S0, J0 to zero) + bool useSparse; // If true, use sparse L0-norm regularization, in addition to the default L2 + bool useSecStruct; // If true, select first pairs from the secondary structure list if it exists + bool useVerbose; // If true, print extra information while program is running + bool useVeryVerbose; // If true, use very verbose output + + + RunParameters() { + + directory="."; + infile="input"; + ssinfile="input"; + outfile="output"; + + kmin=0; + kmax=0; + sampleB=10000; + gamma0=1.0e-4; + gamma2=0.0; + thetaMin=1.0e-10; + thetaMax=1.0e+0; + thetaStep=1.05; + b=40000; + runs=1; + computeGamma=false; + useLax=false; + useRef=false; + useSparse=false; + useSecStruct=false; + useVerbose=false; + useVeryVerbose=false; + + } + std::string getCorrelationsInfile() { return (directory+"/"+infile+".p"); } + std::string getSecStructInfile() { return (directory+"/"+ssinfile+".wuss"); } + std::string getCouplingsOutfile() { return (directory+"/"+outfile+".j"); } + std::string getCorrelationsOutfile() { return (directory+"/"+outfile+".p"); } //#FLAG + std::string getSupplementaryOutfile() { return (directory+"/"+outfile+".sce"); } + ~RunParameters() {} + +}; + + +#endif diff --git a/io.cpp b/io.cpp new file mode 100755 index 0000000..53aad26 --- /dev/null +++ b/io.cpp @@ -0,0 +1,97 @@ +#include + +#include "io.h" // Data input and output +#include "tools.h" // Numerical tools + + +// Read correlations and number of sites in from a file + +void getCorrelations(FILE *input, Vector &p) { + + double c; + char o; + + while (fscanf(input,"%le",&c)==1) { + + p.push_back(std::vector()); + (p.back()).push_back(c); + + while (fscanf(input,"%c",&o)==1) { + + if (o=='\n' || o=='\r') break; + + fscanf(input,"%le",&c); + (p.back()).push_back(c); + + } + + } + +} + + +// Read couplings in from a file + +void getCouplings(FILE *input, Vector &p) { + + getCorrelations(input, p); + +} + + +// Read secondary structure from file + +void getSS(FILE *input, IntVector &p) { + + int c; + char o; + + while (fscanf(input,"%d",&c)==1) { + + p.push_back(std::vector()); + (p.back()).push_back(c); + + while (fscanf(input,"%c",&o)==1) { + + if (o=='\n' || o=='\r') break; + + fscanf(input,"%d",&c); + (p.back()).push_back(c); + + } + + } + +} + + +// Print final couplings out to file in a form understood by ising.cpp + +void printCouplings(FILE *output, const Vector &J) { + + for (int i=0;i &error, double finalS, int maxClusterSize, unsigned long numClusters, unsigned long numSignificantClusters) { + + fprintf(output,"%le",theta); + for (int i=0;i +#include +#include + +#include "tools.h" // Numerical tools + + +void getCorrelations(FILE *, Vector &); +void getCouplings(FILE *, Vector &); +void getSS(FILE *, IntVector &p); +void printCouplings(FILE *, const Vector &); +void printSupplementaryOutput(FILE *, double, const std::vector &, double, int, unsigned long, unsigned long); + + +#endif diff --git a/mainQEE.cpp b/mainQEE.cpp new file mode 100755 index 0000000..6b67dbe --- /dev/null +++ b/mainQEE.cpp @@ -0,0 +1,169 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qEpitopeEval.h" // Evaluate epitopes +#include "monteCarlo.h" // Monte Carlo +#include "tools.h" // Numerical tools +#include "io.h" // Data I/O + + +/********************************************************************* + + COMMAND LINE INPUT FORMAT + + Command line instructions tell the program where to look for input + files and where to send output, as well as the setting of various + parameters (gamma, theta, etc) and flags (useSparse, etc). + Note that numerical parameters may be entered in either scientific + (recommended) or standard decimal notation. True/false switches are + off by default - if entered in the command line, the corresponding + option is set to true. Defaults can be found in dataStructures.h. + The conventions are given below: + + -(flag name): (type of input expected) + + -d: string + Default: "." (current directory) + Path to the directory where the data file is located, and where + output will be written. + + -i: string + Default: "input" + The location of the file containing a set of couplings, the + starting values for the Monte Carlo learning algorithm. + + -o: string + Default: "output" + The location of the file where output is to be sent. Each + different type of output file will have a different file type, + e.g. .j for couplings. + + -c: string + Default: "input" + The location of the file containing the set of correlations to + reproduce (i.e. the correlations obtained from the data). + + -s: string + Default: none + Starting configuration for MC simulations. + + -g2: real number + Default: 0.0 + The L2 regularization strength. L2 regularization is enabled by setting the + regularization strength to a nonzero value using this flag, or by using the + -ag flag below. + + -ag: none + Attempt to set the L2 regularization strengths to its optimal value, + based on the number of samples (input) in the data. + + -b: real number + Default: 1.0e+4 + Number of samples used to compute the correlations. Used to + determine the inference error. + + -mcb: integer + Default: 8.0e+5 + Number of Monte Carlo samples to take to check inference error. + + -mcr: integer + Default: 1 + Number of independent Monte Carlo runs to perform. + + -e: real number + Default: 1.0 + Maximum tolerable error threshold. The MC learning algorithm will + continue to run until the error on the one- and two-point correlations + falls below this level. + + -v: none + Enable verbose output. + + *********************************************************************/ + + +// MAIN PROGRAM + +int main(int argc, char *argv[]) { + + RunParameters r; + + // Process command line input + + for (int i=1;i >()); + r.epitopeStartSite.push_back(std::vector()); } + else if (strcmp(argv[i],"-e")==0) { if (++i==argc) break; + else if (strcmp(argv[i],"[")==0) { + std::vector tempvec; + while (strcmp(argv[++i],"]")!=0) tempvec.push_back(strtoint(argv[i])); + (r.epitopeStates.back()).push_back(tempvec); + } } + else if (strcmp(argv[i],"-es")==0) { if (++i==argc) break; else (r.epitopeStartSite.back()).push_back(strtoint(argv[i])); } + + // Monte Carlo settings + + else if (strcmp(argv[i],"-mcb")==0) { if (++i==argc) break; else r.b=strtoint(argv[i]); } + else if (strcmp(argv[i],"-mcr")==0) { if (++i==argc) break; else r.runs=strtoint(argv[i]); } + + // Optional output + + else if (strcmp(argv[i],"-p2")==0) { r.saveP2=true; } + else if (strcmp(argv[i],"-p3")==0) { r.saveP3=true; } + else if (strcmp(argv[i],"-pk")==0) { r.savePk=true; } + else if (strcmp(argv[i],"-v")==0) { r.useVerbose=true; } + + else printf("Unrecognized command! '%s'\n",argv[i]); + + } + + if (r.epitopeStates.size()==0) { + + std::vector > eStates; + std::vector eStartSite; + + runEpitopeEval(r, eStates, eStartSite, -1); + + } + + else if (r.epitopeStates.size()==1) { + + std::vector > eStates(r.epitopeStates[0]); + std::vector eStartSite(r.epitopeStartSite[0]); + + runEpitopeEval(r, eStates, eStartSite, -1); + + } + + else { for (int i=0;i > eStates(r.epitopeStates[i]); + std::vector eStartSite(r.epitopeStartSite[i]); + + runEpitopeEval(r, eStates, eStartSite, r.on+i); + + } } + + return 0; + +} diff --git a/monteCarlo.cpp b/monteCarlo.cpp new file mode 100644 index 0000000..9b34b80 --- /dev/null +++ b/monteCarlo.cpp @@ -0,0 +1,1076 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tools.h" // Numerical tools +#include "monteCarlo.h" // MC declarations +#include "mtrnd.h" // Random number generator + + +// Compute epsilonP for two vectors of correlations + +double epsilonP(const Vector &q, const Vector &p, int N, double maxPrecision, const Vector &J, double gamma, double alpha) { + + double err = 0.0; + double Neff = 0.0; + + for (int i=0;imaxError) maxError=gradError; + + } } + + // Check nonzero pairs + + for (int n=0;nmaxError) maxError=gradError; + + } + + } + + return ( maxError / sqrt(2 * log(N*(N+1)/2) ) ); + +} + + +// Compute maximum error on the one- and two-point correlations (dense, including regularization) + +double getMaxError(const Vector &q, const Vector &p, double maxPrecision, const Vector &J, double gamma, double alpha) { + + int N = sizetolength(q.size()); + double maxError = 0; + + // Check all single sites + + for (int i=0;imaxError) maxError = gradError; + + } } + + // Check all pairs + + for (int i=0;imaxError) maxError=gradError; + + } } + + } } + + return ( maxError / sqrt(2 * log(N*(N+1)/2) ) ); + +} + + +// Set energies based on an initial configuration + +void setEnergies(const Vector &expJ, const IntVector &neighbor, const std::vector &lattice, const std::vector &nonzero, Vector &expH, std::vector &sumExpH) { + + // Get energy of each state at each site (modulo fields/couplings at other sites) + + for (int i=0;i &lattice, const std::vector &nonzero, int x, int prev, Vector &expH, std::vector &sumExpH) { + + // Initial state zero + + if (prev==expJ[x].size()) { + + for (int i=1;i &lattice, std::vector &nonzero, Vector &expH, std::vector &sumExpH) { + + // Check for spin flip, choose new state + + if ( y < ((sumExpH[x] - expH[x][lattice[x]]) / sumExpH[x]) ) { + + double tempSum=0; + int prev=lattice[x]; + + for (int i=0;i &lattice, const std::vector &nonzero, Vector &p) { + + for (int i=0;i &lattice, const std::vector &nonzero, Vector &p, std::vector > > > &p3) { + + for (int i=0;i &lattice, std::vector &nonzero, Vector &p, Vector &expH, std::vector &sumExpH) { + + for (int n=0;n &fixedSites, MT::MersenneTwist &mt, int N, int numSteps, int stepSize, std::vector &lattice, std::vector &nonzero, Vector &p, Vector &expH, std::vector &sumExpH) { + + for (int n=0;nmutCut) { + + for (int i=0;i &fixedSites, MT::MersenneTwist &mt, int N, int numSteps, int stepSize, std::vector &lattice, std::vector &nonzero, Vector &p, std::vector > > > &p3, std::vector &pk, Vector &expH, std::vector &sumExpH) { + + for (int n=0;nmutCut) { + + for (int i=0;i &fixedSites, MT::MersenneTwist &mt, int N, int numSteps, int stepSize, std::vector &lattice, std::vector &nonzero, Vector &p, Vector &expH, std::vector &sumExpH) { + + for (int n=0;nthreshold) { + + neighbor[i].push_back(j); + neighbor[j].push_back(i); + break; + + } + + } } + + } + +} + + +// Compute the inferrence error for a given set of couplings using rejection-free Monte Carlo (getError_RF) + +void getError(const Vector &q, const Vector &J, int N, double B, int numSteps, int numRuns, double gamma, double alpha, std::vector &error) { + + // Create and initialize Monte Carlo variables + + std::vector lastError(2,0); + Vector p(q.size(),std::vector()); + for (int i=0;i lattice(N,0); + std::vector nonzero(N,0); + + // Couplings and neighbors + + IntVector neighbor(N); + getNeighbors(J, N, 0, neighbor); + Vector expJ(J); + for (int i=0;i sumExpH; + + sumExpH.resize(lattice.size(),0); + expH.resize(lattice.size(),std::vector()); + for (int i=0;i 1.0) && (error[0] - 3 * deltaP > 1) ); + bool cBad = ( (error[1] > 1.0) && (error[1] - 3 * deltaC > 1) ); + bool pGood = ( (error[0] < 1.0) && (error[0] + 1 * deltaP < 1) ); + bool cGood = ( (error[1] < 1.0) && (error[1] + 1 * deltaC < 1) ); + + if ( pBad || cBad || (pGood && cGood) || multiplier==multMax ) runMC=false; + + else { + + for (int i=0;i &error, std::vector &latticeStart) { + + // Create and initialize Monte Carlo variables + + for (int i=0;i lattice(N,0); + std::vector nonzero(N,0); + + // Neighbors + + IntVector neighbor(N); + getNeighbors(J, N, 1.0e-5, neighbor); + + // Energies + + Vector expH; + std::vector sumExpH; + + sumExpH.resize(lattice.size(),0); + expH.resize(lattice.size(),std::vector()); + for (int i=0;i > &epitopeStates, const std::vector &epitopeStartSite, int numSteps, int numRuns, Vector &p, std::vector &latticeStart) { + + // Create and initialize Monte Carlo variables + + for (int i=0;i lattice(N,0); + std::vector nonzero(N,0); + std::vector fixedSites; + + for (int i=0;i sumExpH; + + sumExpH.resize(lattice.size(),0); + expH.resize(lattice.size(),std::vector()); + for (int i=0;i > &epitopeStates, const std::vector &epitopeStartSite, int numSteps, int numRuns, Vector &p, std::vector > > > &p3, std::vector &pk, std::vector &latticeStart) { + + // Create and initialize Monte Carlo variables + + for (int i=0;i lattice(N,0); + std::vector nonzero(N,0); + std::vector fixedSites; + + for (int i=0;i sumExpH; + + sumExpH.resize(lattice.size(),0); + expH.resize(lattice.size(),std::vector()); + for (int i=0;i > &epitopeStates, const std::vector &epitopeStartSite, int numSteps, int numRuns, Vector &p, std::vector &latticeStart) { + + // Create and initialize Monte Carlo variables + + for (int i=0;i lattice(N,0); + std::vector nonzero(N,0); + std::vector fixedSites; + + for (int i=0;i sumExpH; + + sumExpH.resize(lattice.size(),0); + expH.resize(lattice.size(),std::vector()); + for (int i=0;i + +#include "tools.h" // Numerical tools +#include "mtrnd.h" // Random number generator + + +// Error measures +double epsilonP(const Vector &, const Vector &, int, double, const Vector &, double, double); +double epsilonP2(const Vector &, const Vector &, int, double, const Vector &, double); +double epsilonC(const Vector &, const Vector &, int, double, const Vector &, double); +double getMaxError(const Vector &, const Vector &, const IntVector &, double); +double getMaxError(const Vector &, const Vector &, double, const Vector &, double, double); + +// MC functions +void setEnergies(const Vector &, const IntVector &, const std::vector &, const std::vector &, Vector &, std::vector &); +void updateEnergies(const Vector &, const IntVector &, const std::vector &, const std::vector &, int, int, Vector &, std::vector &); +void dynamicsRF(const Vector &, const IntVector &, int, double, std::vector &, std::vector &, Vector &, std::vector &); +void updateCorrelations(const std::vector &, const std::vector &, Vector &); +void updateCorrelationsP3(const std::vector &, const std::vector &, Vector &, std::vector > > > &); +void getSample(const Vector &, const IntVector &, MT::MersenneTwist &, int, int, int, std::vector &, std::vector &, Vector &, Vector &, std::vector &); +void getFixedSample(const Vector &, const IntVector &, const std::vector &, MT::MersenneTwist &, int, int, int, std::vector &, std::vector &, Vector &, Vector &, std::vector &); +void getFixedSampleP3Pk(const Vector &, const IntVector &, const std::vector &, MT::MersenneTwist &, int, int, int, std::vector &, std::vector &, Vector &, std::vector > > > &, std::vector &, Vector &, std::vector &); +void writeFixedSample(FILE *, const Vector &, const IntVector &, const std::vector &, MT::MersenneTwist &, int, int, int, std::vector &, std::vector &, Vector &, Vector &, std::vector &); + +// Auxiliary +void getNeff(const Vector &, int, int &, int &); +void getNeighbors(const Vector &, int, double, IntVector &); + +// Control functions +void getError(const Vector &, const Vector &, int, double, int, int, double, double, std::vector &); +void getErrorMCLearn(const Vector &, const Vector &, Vector &, double, int, int, double, double, Vector &, std::vector &, std::vector &); +void getEpitopeCorrelations(const Vector &, const Vector &, const std::vector > &, const std::vector &, int, int, Vector &, std::vector &); +void getEpitopeCorrelationsP3Pk(const Vector &, const Vector &, const std::vector > &, const std::vector &, int, int, Vector &, std::vector > > > &, std::vector &, std::vector &); +void getEpitopeStates(FILE *, const Vector &, const Vector &, const std::vector > &, const std::vector &, int, int, Vector &, std::vector &); + + +#endif diff --git a/mtrnd.h b/mtrnd.h new file mode 100644 index 0000000..62892c6 --- /dev/null +++ b/mtrnd.h @@ -0,0 +1,188 @@ +/* +A C-program for MT19937, with initialization improved 2002/1/26. +Coded by Takuji Nishimura and Makoto Matsumoto. + +Before using, initialize the state by using init_genrand(seed) +or init_by_array(init_key, key_length). + +Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. The names of its contributors may not be used to endorse or promote +products derived from this software without specific prior written +permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Any feedback is very welcome. +http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html +email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) + +Reference: M. Matsumoto and T. Nishimura, "Mersenne Twister: +A 623-Dimensionally Equidistributed Uniform Pseudo-Random Number Generator", +ACM Transactions on Modeling and Computer Simulation, Vol. 8, No. 1, +January 1998, pp 3--30. +*/ + +// C++ wrapped up by Changjiang Yang, more important: make it thread-safe. +#ifndef _MT_RND_H_ +#define _MT_RND_H_ + +namespace MT { +/* Period parameters */ +const int N = 624; +const int M = 397; +const unsigned long MATRIX_A = 0x9908b0dfUL; /* constant vector a */ +const unsigned long UPPER_MASK = 0x80000000UL; /* most significant w-r bits */ +const unsigned long LOWER_MASK = 0x7fffffffUL; /* least significant r bits */ + +class MersenneTwist { + unsigned long mt[N]; /* the array for the state vector */ + int mti; /* mti==N+1 means mt[N] is not initialized */ +public: + + MersenneTwist() : mti(N+1) {} + + /* initializes mt[N] with a seed */ + // Note: Initializing TWISTER to the scalar integer state 0 actually + // corresponds to the C call init_genrand(5489). + void init_genrand(unsigned long s) + { + mt[0]= s & 0xffffffffUL; + for (mti=1; mti> 30)) + mti); + /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ + /* In the previous versions, MSBs of the seed affect */ + /* only MSBs of the array mt[]. */ + /* 2002/01/09 modified by Makoto Matsumoto */ + mt[mti] &= 0xffffffffUL; + /* for >32 bit machines */ + } + } + + /* initialize by an array with array-length */ + /* init_key is the array for initializing keys */ + /* key_length is its length */ + /* slight change for C++, 2004/2/26 */ + void init_by_array(unsigned long init_key[], int key_length) + { + int i, j, k; + init_genrand(19650218UL); + i=1; j=0; + k = (N>key_length ? N : key_length); + for (; k; k--) { + mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + + init_key[j] + j; /* non linear */ + mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + i++; j++; + if (i>=N) { mt[0] = mt[N-1]; i=1; } + if (j>=key_length) j=0; + } + for (k=N-1; k; k--) { + mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) + - i; /* non linear */ + mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + i++; + if (i>=N) { mt[0] = mt[N-1]; i=1; } + } + + mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ + } + + /* generates a random number on [0,0xffffffff]-interval */ + unsigned long genrand_int32(void) + { + unsigned long y; + static unsigned long mag01[2]={0x0UL, MATRIX_A}; + /* mag01[x] = x * MATRIX_A for x=0,1 */ + + if (mti >= N) { /* generate N words at one time */ + int kk; + + if (mti == N+1) /* if init_genrand() has not been called, */ + init_genrand(5489UL); /* a default initial seed is used */ + + for (kk=0;kk> 1) ^ mag01[y & 0x1UL]; + } + for (;kk> 1) ^ mag01[y & 0x1UL]; + } + y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); + mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; + + mti = 0; + } + + y = mt[mti++]; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + return y; + } + + /* generates a random number on [0,0x7fffffff]-interval */ + long genrand_int31(void) + { + return (long)(genrand_int32()>>1); + } + + /* generates a random number on [0,1]-real-interval */ + double genrand_real1(void) + { + return genrand_int32()*(1.0/4294967295.0); + /* divided by 2^32-1 */ + } + + /* generates a random number on [0,1)-real-interval */ + double genrand_real2(void) + { + return genrand_int32()*(1.0/4294967296.0); + /* divided by 2^32 */ + } + + /* generates a random number on (0,1)-real-interval */ + double genrand_real3(void) + { + return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0); + /* divided by 2^32 */ + } + + /* generates a random number on [0,1) with 53-bit resolution*/ + double genrand_res53(void) + { + unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; + return(a*67108864.0+b)*(1.0/9007199254740992.0); + } +}; +} +#endif diff --git a/qEpitopeEval.cpp b/qEpitopeEval.cpp new file mode 100755 index 0000000..b0acecc --- /dev/null +++ b/qEpitopeEval.cpp @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qEpitopeEval.h" // Evaluate epitopes +#include "monteCarlo.h" // Monte Carlo +#include "tools.h" // Numerical tools +#include "io.h" // Data I/O +#include "mtrnd.h" // Random number generator + + +// Runs the main program + +void runEpitopeEval(RunParameters &r, std::vector > &eStates, std::vector &eStartSite, int nout) { + + // Define variables + + Vector p; + Vector J, expJ; + std::vector > > > p3; // 3-point correlations + std::vector pk; // mutation probability + + // Retrieve couplings from file + + FILE *dataIn=fopen(r.getInfile().c_str(),"r"); + + if (dataIn!=NULL) getCouplings(dataIn,J); + else { printf("Error reading input from file %s",r.getInfile().c_str()); exit(1); } + + // Resize correlations and expJ + + int N = sizetolength(J.size()); + + pk.resize(N+1, 0); + for (int i=0;i(J[i].size(),0)); expJ.push_back(std::vector(J[i].size(),0)); } + for (int i=0;i lattice(N); + + if (r.useStart) { + + FILE *startIn=fopen(r.getStartInfile().c_str(),"r"); + for (int i=0;i=0) dataOut=fopen(r.getCorrelationsOutfile(nout).c_str(),"w"); + else dataOut=fopen(r.getCorrelationsOutfile().c_str(), "w"); + + for (int i=0;i=0) p3Out=fopen(r.getP3Outfile(nout).c_str(),"w"); + else p3Out=fopen(r.getP3Outfile().c_str(), "w"); + + for (int i=0;i=0) pkOut=fopen(r.getPkOutfile(nout).c_str(),"w"); + else pkOut=fopen(r.getPkOutfile().c_str(), "w"); + + for (int i=0;i +#include + +#include "tools.h" // Numerical tools + + +// This class holds the parameters needed for running the ising program + +class RunParameters { + +public: + + std::string directory; // Path to the directory where the inut file is located + // Output will also be sent to this directory + std::string infile; // Input file from which couplings are to be read + std::string outfile; // Output file (prefix) where data is to be written + + double b; // Number of data points to take in a single run + double runs; // Number of times to run dynamics + + std::vector > > epitopeStates; // Configuration of sites in the targeted epitope + std::vector > epitopeStartSite; // Index of the first site in the epitope + + int on; // Start number for keeping track of all epitopes and epitope combinations + + bool useStart; // Use different starting sequence than all wild-type + std::string startfile; // File containing the starting sequence + + bool useVerbose; // If true, print extra information while program is running + bool saveP2; // If true, record pair correlations in additions to one-point correlations + bool saveP3; // If true, record three-point correlations + bool savePk; // If true, record P(k) mutations curve + + RunParameters() { + + directory="."; + infile="input"; + outfile="output"; + b=1000000; + runs=1; + on=0; + + useStart=false; + useVerbose=false; + saveP2=false; + saveP3=false; + savePk=false; + + } + std::string getInfile() { return (directory+"/"+infile+".j"); } + std::string getCorrelationsOutfile() { return (directory+"/"+outfile+".p"); } + std::string getCorrelationsOutfile(int i) { return (directory+"/"+outfile+"-"+tostring(i)+".p"); } + std::string getP3Outfile() { return (directory+"/"+outfile+".p3"); } + std::string getP3Outfile(int i) { return (directory+"/"+outfile+"-"+tostring(i)+".p3"); } + std::string getPkOutfile() { return (directory+"/"+outfile+".pk"); } + std::string getPkOutfile(int i) { return (directory+"/"+outfile+"-"+tostring(i)+".pk"); } + std::string getStartInfile() { return (directory+"/"+startfile+".dat"); } + ~RunParameters() {} + +}; + + +//void runEpitopeEval(RunParameters &); +void runEpitopeEval(RunParameters &, std::vector > &, std::vector &, int); + + +#endif diff --git a/tools.cpp b/tools.cpp new file mode 100755 index 0000000..68bfacd --- /dev/null +++ b/tools.cpp @@ -0,0 +1,1387 @@ +#include +#include + +#include "tools.h" // Numerical tools + + +// Calculates gamma from the data for the L0 norm regularization + +double computeGamma_L0(const Vector &p, double B) { return 1/B; } + + +// Calculates gamma from the data for the L2 norm regularization + +double computeGamma_L2(const Vector &p, double B) { return 1/B; } + + +// Returns the inner product of two arrays of doubles + +double innerProduct(double list1[], double list2[], size_t length) { + + double product=0; + + for (int i=0;i &list1, const std::vector &list2) { + + double product=0; + + for (int i=0;i &list) { + + double norm=0; + + for (int i=0;i &list) { + + double norm=0; + + for (int i=0;inorm) norm = fabs(list[i]); } + + return norm; + +} + + +// Computes the LInfinity norm of a vector of doubles + +double LInfinity(const std::vector &list) { + + double norm=0; + + for (int i=0;inorm) norm = fabs(list[i]); } + + return norm; + +} + + +// Computes the LInfinity norm of a vector of doubles + +double LInfinity(const Vector &list) { + + double norm=0; + + for (int i=0;inorm) norm = fabs(list[i][j]); + + } + + } + + return norm; + +} + + +// Computes the LInfinity norm of a vector of doubles (sparse) + +double LInfinity(const Vector &list, const IntVector &sparseSet) { + + double norm=0; + + for (int i=0;inorm) norm = fabs(list[i][sparseSet[i][j]]); + + } + + } + + return norm; + +} + + +// Insert an element into vector in order (smallest to largest) + +void insertInPlace(std::vector &list, int element) { + + if (list.empty()) list.push_back(element); + + else { + + bool insert=true; + int imin=-1; + int imax=(int)list.size(); + + while (imax-imin>1) { + + int imid = (imin+imax)/2; + + if (list[imid] < element) imin = imid; + else if (list[imid] > element) imax = imid; + else if (list[imid] == element) { insert=false; break; } + + } + + if (insert) list.insert(list.begin()+imax,element); + + } + +} + + +// Insert an element into vector in order (smallest to largest) + +void insertInPlace(int list[], int length, int element) { + + if (length==1) list[0]=element; + + else { + + bool insert=true; + int imin=-1; + int imax=length; + + while (imax-imin>1) { + + int imid = (imin+imax)/2; + + if (list[imid] < element) imin = imid; + else if (list[imid] > element) imax = imid; + else if (list[imid] == element) { insert=false; break; } + + } + + if (insert) { + + for (int i=length;i>imax;i--) list[i] = list[i-1]; + list[imax] = element; + + } + + } + +} + + +// Erase an element in a vector, maintaining order (smallest to largest) + +void eraseInPlace(std::vector &list, int element) { + + bool erase=true; + int imin=-1; + int imax=(int)list.size(); + int imid; + + while (imax-imin>1) { + + imid = (imin+imax)/2; + + if (list[imid] < element) imin = imid; + else if (list[imid] > element) imax = imid; + else if (list[imid] == element) { erase=true; break; } + + } + + if (erase) list.erase(list.begin()+imid); + + +} + + +// Erase an element in a vector, maintaining proper order + +void eraseInPlace(int list[], int length, int element) { + + bool erase=true; + int imin=-1; + int imax=length; + int imid; + + while (imax-imin>1) { + + imid = (imin+imax)/2; + + if (list[imid] < element) imin = imid; + else if (list[imid] > element) imax = imid; + else if (list[imid] == element) { erase=true; break; } + + } + + if (erase) { + + for (int i=imid;i pivot) i++; + while (a[j][0] < pivot) j--; + + if (i <= j) { + + temp0 = a[i][0]; + temp1 = a[i][1]; + + a[i][0] = a[j][0]; + a[i][1] = a[j][1]; + + a[j][0] = temp0; + a[j][1] = temp1; + + i++; + j--; + + } + + } + + // Recursion + + if (left < j) quickSort(a, left, j); + if (i < right) quickSort(a, i, right); + +} + + +// Sorts the list of doubles (with corresponding index also arranged properly) using the quickSort algorithm +// Sort order is FROM HIGH TO LOW + +void quickSort(double a[][3], int left, int right) { + + int i=left; + int j=right; + + double temp0, temp1, temp2; + double pivot = a[(left + right) / 2][0]; + + // Partition + + while (i <= j) { + + while (a[i][0] > pivot) i++; + while (a[j][0] < pivot) j--; + + if (i <= j) { + + temp0 = a[i][0]; + temp1 = a[i][1]; + temp2 = a[i][2]; + + a[i][0] = a[j][0]; + a[i][1] = a[j][1]; + a[i][2] = a[j][2]; + + a[j][0] = temp0; + a[j][1] = temp1; + a[j][2] = temp2; + + i++; + j--; + + } + + } + + // Recursion + + if (left < j) quickSort(a, left, j); + if (i < right) quickSort(a, i, right); + +} + + +// Sorts the vector of integers (with corresponding index also arranged properly) using the quickSort algorithm +// Sort order is FROM LOW TO HIGH + +void quickSort(std::vector &a, int left, int right) { + + int i=left; + int j=right; + + int temp; + int pivot = a[(left + right) / 2]; + + // Partition + + while (i <= j) { + + while (a[i] < pivot) i++; + while (a[j] > pivot) j--; + + if (i <= j) { + + temp = a[i]; + a[i] = a[j]; + a[j] = temp; + + i++; + j--; + + } + + } + + // Recursion + + if (left < j) quickSort(a, left, j); + if (i < right) quickSort(a, i, right); + +} + + +// Check to see if two sets of spins of size k have a superset of size k+1 + +bool checkSize(const Key &a, const Key &b) { + + int i=0,j=0,error=0; + + while (error<3) { + + if (i==(int)a.size()) { error += (int)b.size()-j; break; } + else if (j==(int)b.size()) { error += (int)a.size()-i; break; } + + else if (a[i]b[j]) { j++; error++; continue; } + else if (a[i]==b[j]) { i++; j++; continue; } + else break; + + } + + if (error!=2) return false; + else return true; + +} + + +// Returns the superset of two sets of spins + +void getSuperset(const Key &a, const Key &b, Key &superset) { + + int i=0,j=0,index=0; + + while (true) { + + if (i==a.size()) { for (int k=j;kb[j]) { superset[index]=b[j]; index++; j++; continue; } + else break; + + } + +} + + +// Take a Hessian matrix in Vector format and "unpack" it into the form of a list of upper triangular +// matrix entries in linearHess. The shape of the coupling Vector is used to help unpack the Hessian. + +void unpack(Vector &hess, std::vector &linearHess, const Vector &J) { + + int count=0; + + for (int i=0;i &linearHess, const Vector &J) { + + int count=0; + + for (int i=0;i &linearHess, const Vector &J, const IntVector &workingSet) { + + int count=0; + + for (int i=0;i &linearHess, const Vector &J, const IntVector &workingSet) { + + int count=0; + + for (int i=0;imax) max=fabs(c[i][j]); + + } + + max = pow(max/beta,2); + + if (fabs(c[i][i])>max) d[i] = fabs(c[i][i]); + else d[i] = max; + + for (int j=i;j &linearHess, int length, const Vector &J) { + + unpack(hess, linearHess, J); + modifiedCholeskyInverse(linearHess, length); + pack(hess, linearHess, J); + +} + + +// This function performs the modified Cholesky factorization on a positive-definite, but +// possibly near singular matrix and uses this to invert the matrix. The inversion is regularized +// to insure that the condition number of the matrix does not exceed a certain maximum value. +// Sparse version for L1 regularization. + +void modifiedCholeskyInverse_sparse(Vector &hess, std::vector &linearHess, std::vector &inverseC, std::vector &inverseN, std::vector &inverseD, const Vector &J, const IntVector &workingSet) { + + unpack_sparse(hess, linearHess, J, workingSet); + modifiedCholeskyInverse(linearHess, inverseC, inverseN, inverseD, inverseD.size()); + pack_sparse(hess, linearHess, J, workingSet); + +} + + +// This function performs the modified Cholesky factorization on a positive-definite, but +// possibly near singular matrix and uses this to invert the matrix. The inversion is regularized +// to insure that the condition number of the matrix does not exceed a certain maximum value. + +void modifiedCholeskyInverse(std::vector &m, std::vector &c, std::vector &n, std::vector &d, size_t length) { + + //double delta=pow(10.0,-10.0); + double beta =pow(10.0, 2.0); + // Note: comp should be = beta * sqrt(delta) + double comp =pow(10.0, -3.0); + + // First compute modified LDLT Cholesky factorization + + for (int i=0;imax) max = fabs(c[hindex(i,j,length)]); + + } + + max = pow(max/beta,2); + + if (fabs(c[hindex(i,i,length)])>max) d[i] = fabs(c[hindex(i,i,length)]); + else d[i] = max; + + for (int j=i;j &m, int length) { + + std::vector > c; + c.resize(length,std::vector(length,0)); + std::vector d(length,0); + + double beta =pow(10.0, 2.0); + // Note: comp should be = beta * sqrt(delta) + double comp =pow(10.0, -3.0); + + // First compute modified LDLT Cholesky factorization + + for (int i=0;imax) max=fabs(c[i][j]); + + } + + max = pow(max/beta,2); + + if (fabs(c[i][i])>max) d[i] = fabs(c[i][i]); + else d[i] = max; + + for (int j=i;j > n; + n.resize(length,std::vector(length,0)); + + // First get D^-1 and L^-1 + + for (int i=0;imax) max=fabs(c[i][j]); + + } + + max = pow(max/beta,2); + + if (fabs(c[i][i])>max) d[i] = fabs(c[i][i]); + else d[i] = max; + + for (int j=i;jmax) max=fabs(c[i][j]); + + } + + max = pow(max/beta,2); + + if (fabs(c[i][i])>max) d[i] = fabs(c[i][i]); + else d[i] = max; + + for (int j=i;j=0;i--) v[i] /= v[0]; + + } + +} + + +// Given a symmetric matrix A, this algorithm overwrites A with T = Q^T A Q, with T tridiagonal, +// and Q orthogonal. See Matrix Computations (Golub) for details. This algorithm assumes Q +// has already been initialized. + +void tridiagonalize(double A[], int length, std::vector > &Q) { + + for (int k=0;k > &Z) { + + double d = (T[hindex(length-2,length-2,length)] - T[hindex(length-1,length-1,length)]) / 2; + + double mu = T[hindex(length-1,length-1,length)] - pow(T[hindex(length-2,length-1,length)],2) + / (d * (1 + sqrt(pow(d,2) + pow(T[hindex(length-2,length-1,length)],2)) / fabs(d) ) ); + + double x = T[0] - mu; + double z = T[hindex(0,1,length)]; + + for (int k=0;k m=k-1 + + if (k>0) { + + for (int j=k-1;j m=k, k+1 + + for (int j=k;j m=k, k+1 + + for (int j=k+1;j0) { for (int j=k-1;j > &eigenvectors) { + + double eps = pow(10,-8); // error tolerance + + // Tridiagonalize the matrix + + tridiagonalize(A, length, eigenvectors); + + // Determine the unreduced subset + + int q=0; + + for (int i=length-2;i>=0 && fabs(A[hindex(i,i+1,length)])==0;i--) q++; + + int p=length-q-2; + + for (int i=p-1;i>=0 && fabs(A[hindex(i,i+1,length)])!=0;i--) p--; + + + // Loop until convergence + + //DEBUG + int loop=0; + + while (q0) { + + for (int j=k-1;j0) { for (int j=k-1;j=0 && fabs(A[hindex(i,i+1,length)]) <= eps * (fabs(A[hindex(i,i,length)]) + fabs(A[hindex(i,i+1,length)])); i--) { + + q++; + A[hindex(i,i+1,length)]=0; + + } + + p=length-q-2; + + for (int i=p-1;i>=0 && fabs(A[hindex(i,i+1,length)])!=0;i--) { + + p--; + + if (fabs(A[hindex(i,i+1,length)]) <= eps * (fabs(A[hindex(i,i,length)]) + fabs(A[hindex(i,i+1,length)]))) { + + A[hindex(i,i+1,length)]=0; + p++; + break; + + } + + } + + } + + for (int i=0;i +#include +#include +#include +#include +#include + + +// Typedefs +typedef std::vector Key; +typedef std::vector > Vector; +typedef std::vector > IntVector; + + +double computeGamma_L0(const Vector &, double); +double computeGamma_L2(const Vector &, double); + +double innerProduct(double[], double[], size_t); +double innerProduct(const std::vector &, const std::vector &); +double innerProduct(const Vector &, const Vector &); +double innerProduct(const Vector &, const Vector &, const IntVector &); +double L1(double[], size_t); +double L1(const std::vector &); +double L1(const Vector &); +double L2(double[], size_t); +double L2(const std::vector &); +double L2(const Vector &); +double L2(const Vector &, const IntVector &); +double LInfinity(double[], size_t); +double LInfinity(const std::vector &); +double LInfinity(const Vector &); +double LInfinity(const Vector &, const IntVector &); + +void insertInPlace(std::vector &, int); +void insertInPlace(int[], int, int); +void eraseInPlace(std::vector &, int); +void eraseInPlace(int[], int, int); +void quickSort(double[][2], int, int); +void quickSort(double[][3], int, int); +void quickSort(std::vector &, int, int); +bool checkSize(const Key &, const Key &); +void getSuperset(const Key &, const Key &, Key &); + +void unpack(Vector &, std::vector &, const Vector &); +void pack(Vector &, std::vector &, const Vector &); +void unpack_sparse(Vector &, std::vector &, const Vector &, const IntVector &); +void pack_sparse(Vector &, std::vector &, const Vector &, const IntVector &); + +void modifiedCholeskyInverse(double[], size_t); +void modifiedCholeskyInverse(Vector &, std::vector &, int, const Vector &); +void modifiedCholeskyInverse(std::vector &, std::vector &, std::vector &, std::vector &, size_t); +void modifiedCholeskyInverse_sparse(Vector &, std::vector &, int, const Vector &, const IntVector &); +void modifiedCholeskyInverse_sparse(Vector &, std::vector &, std::vector &, std::vector &, std::vector &, const Vector &, const IntVector &); +void modifiedCholeskyInverse(std::vector &, int); +double modifiedCholeskyInverseDet(double[], size_t); +double modifiedCholeskyInverseDet(Vector &, int, const Vector &); +double symmetricDet(double[], int); + +void givens(double, double, double &, double &); +void householder(double[], int, double[], double &); +void tridiagonalize(double[], int, std::vector > &); +void QRStep(double[], int, std::vector > &); +void symmetricQR(double[], int, double[], std::vector > &); + + + + + +// STRING MANIPULATION + +// Converts generic to string + +template + +inline std::string tostring (const T& t) { + + std::stringstream ss; + ss << t; + return ss.str(); + +} + + +// Converts a string to an integer + +inline int strtoint(const std::string &s) { + + std::istringstream i(s); + int x; + + if (!(i >> x)) printf("String to integer conversion failed!"); + return x; + +} + + +// Converts a string to a double + +inline double strtodouble(const std::string &s) { + + std::istringstream i(s); + double x; + + if (!(i >> x)) printf("String to double conversion failed!"); + return x; + +} + + +// MISC FUNCTIONS + +// Given the size of a coupling or correlation vector, return the corresponding number of spins + +inline int sizetolength(size_t size) { + + return (int) ((sqrt(1 + 8 * size) - 1) / 2); + +} + + +// Checks to see whether the ith bit of an integer in a key is occupied + +inline int checkBit(unsigned long &key, int i) { + + return (int) (key & 1<i, the pair {i,j} in the list {{0,1}, {0,2}, ... } is located at offset(i,length)+j + +inline int offset(int i, size_t length) { + + return (int) (length + i * (length - 2) - (i * (i - 1)) / 2 - 1); + +} + + +// For j>i, the pair {i,j} in the list {{0,0}, {0,1}, ... } is located at hindex(i,j,length) +// This routine is necessary when the diagonal term is also included + +inline int hindex(int i, int j, size_t length) { + + return (int) (i * length - (i * (i + 1)) / 2 + j); + +} + + +// Returns as above, but with a check to make sure that j>i + +inline int safeHindex(int i, int j, size_t length) { + + if (j>i) return (int) (i * length - (i * (i + 1)) / 2 + j); + else return (int) (j * length - (j * (j + 1)) / 2 + i); + +} + + +// Return the location of a pair of states in canonical order, {{0,0}, {0,1}, ..., {0,qj}, {1,0}, ...} + +inline int sindex(int i, int j, size_t qi, size_t qj) { + + return (int) (i * qj + j); + +} + + +// Return the location of a triple of states in canonical order + +inline int sindex3(int i, int j, int k, size_t qi, size_t qj, size_t qk) { + + return (int) (i * qj * qk + j * qk + k); + +} + + +// For j>i, the pair {i,j} in the list {{0},{1},...,{length-1},{0,1}, {0,2}, ... } is located at index(i,j,length) + +inline int index(int i, int j, size_t length) { + + return (int)(length + i * (length - 2) - (i * (i - 1)) / 2 - 1 + j); + +} + + +// For k>j>i, return the index of {i,j,k} in the full list + +inline int index(int i, int j, int k, int length) { + + return ( ( (i * (i + 1) * ( i + 2 )) / 3 + - (length-1) * (i * (i + 2) - 2 * j + 1) + + ((int) pow(length-1, 2)) * (i - 1) + - (j * (j + 1) - 2 * k) ) / 2 ); + +} + + +// For l>k>j>i, return the index of {i,j,k,l} in the full list + +inline int index(int i, int j, int k, int l, int length) { + + return ( (-i * (i + 1) * (i + 2) * (i + 3) + + 4 * (j * (1 + j) * (j + 2) - 3 * k * (k + 1) + 6 * l - 5 * (length-1)) + + 2 * (i * (11 + i * (9 + 2 * i)) - 6 * j * (j + 2) + 12 * k) * (length-1) + - 6 * (i * (i + 3) - 2 * j) * ((int) pow(length-1, 2)) + + 4 * (i - 1) * ((int) pow(length-1,3)) ) / 24 ); + +} + + +// Returns the sign of an integer x (and 0 if x==0) + +inline int sign(int x) { + + static const int lookup_table[] = { -1, 1, 0, 0 }; + return lookup_table[(x==0) * 2 + (x>0)]; + +} + + +// Returns the sign of a double x (and 0 if x==0) + +inline double sign(double x) { + + //double eps=pow(10.0,-20.0); + + static const double lookup_table[] = { -1, 1, 0, 0 }; + return lookup_table[(x==0) * 2 + (x>0)]; + +} + + +// Given components (a, b), this function computes parameters for a Givens rotation matrix G = ((c, s), (-s, c)), +// such that G^T (a, b) = (r, 0). See Matrix Computations (Golub) for details. + +inline void givens(double a, double b, double &c, double &s) { + + if (b==0) { c=1; s=0; } + + else { + + if (fabs(b) > fabs(a)) { s = 1 / sqrt(1 + pow(a,2) / pow(b,2)); c = -a * s / b; } + else { c = 1 / sqrt(1 + pow(b,2) / pow(a,2)); s = -b * c / a; } + + } + +} + + +#endif