how to include svdcmp
florian101
12-10-2009, 11:34 PM
Hello everyone
I have a problem with including svdcmp.cpp. The file uses nr.h but I include it in the svdcmp file and in the main file itself. Compiling the code gives me the following error (g++ comiler)
g++ -o fit fit.cpp -lm
/tmp/ccj8AceD.o: In function `NR::svdcmp(NRMat<double>&, NRVec<double>&, NRMat<double>&)':
fit.cpp:(.text+0x10ad): undefined reference to `NR::pythag(double, double)'
fit.cpp:(.text+0x147b): undefined reference to `NR::pythag(double, double)'
fit.cpp:(.text+0x1588): undefined reference to `NR::pythag(double, double)'
fit.cpp:(.text+0x1735): undefined reference to `NR::pythag(double, double)'
collect2: ld returned 1 exit status
make: *** [fit] Error 1
but pythag is a function which is defined in nr.h??
If I put the whole svdcmp file into
#ifndef _NR_H_
#define _NR_H_
#endif /* _NR_H_ */
(I don't know what it means...)
it compiles without any problem, but I don't know how to call the function. Normally I call it with NR::svdcmp(...) but this gives now the following error
g++ -o fit fit.cpp -lm
/tmp/ccEbIvDn.o: In function `main':
fit.cpp:(.text+0x3741): undefined reference to `NR::svdcmp(NRMat<double>&, NRVec<double>&, NRMat<double>&)'
collect2: ld returned 1 exit status
make: *** [fit] Error 1
So I think my change in svdcmp is rubbish... but what am I doing wrong?
My header in my main program looks like that
#include <iostream>
#include <iomanip>
#include <cmath>
#include "arraylib.h"
#include "cor_const.h"
#include "global.h"
#include "matrix_h"
#include "nr.h"
#include "svdcmp.cpp"
#include "amoeba.cpp"
#include "amotry.cpp"
#include "model.cpp"
#include "inversion.cpp"
#include "arraylib.c"
and some compiler infos
florian@florian-laptop:~/6df/beta_fit$ g++ -v
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.4.1-4ubuntu8' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --program-suffix=-4.4 --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --disable-werror --with-arch-32=i486 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.4.1 (Ubuntu 4.4.1-4ubuntu8)
thankful for any help
best regards
florian
MPD78
12-11-2009, 07:15 AM
Hello,
g++ -o fit fit.cpp -lm
/tmp/ccj8AceD.o: In function `NR::svdcmp(NRMat<double>&, NRVec<double>&, NRMat<double>&)':
fit.cpp.text+0x10ad): undefined reference to `NR:ythag(double, double)'
fit.cpp.text+0x147b): undefined reference to `NR:ythag(double, double)'
fit.cpp.text+0x1588): undefined reference to `NR:ythag(double, double)'
fit.cpp.text+0x1735): undefined reference to `NR:ythag(double, double)'
collect2: ld returned 1 exit status
make: *** [fit] Error 1
but pythag is a function which is defined in nr.h??
An undefined reference is telling you that the compiler cannot locate the function that you are referencing in your main program.
pythag() is located on page 4 of Webnote 2 Rev 1, "SVD Implementation".
Although, looking at your error, you called the function ythag(). Perhaps you have a typo in your code?
The #includes that you need for svd.h are;
#include "nr3.h"
#include "svd.h"
Here is a link to the dependencies tool.
http://www.nrbook.com/nr3/
Your list of #include(s) is redundant. Once you have #included "nr3.h" you don't need to include <iostream>, <iomanip>, and <cmath>. They are #include(d) in "nr3.h"
Here is an example program showing the use of "svd.h" This a modified version of the example program given by davekw7x in this post http://www.nr.com/forum/showthread.php?t=1437&highlight=svd+driver
#include "...NR Headers\nr3.h"
#include "...svd.h"
ifstream svtest; // Input file name
string filename; // user entered file name
Int nrows,ncols,n,m;
Doub pause; // dummy variable used to keep the output window visible
int main(void)
{
cout << "Enter the name of the input file " << endl;
cin >> filename;
svtest.open(filename.c_str());
if(svtest.fail()) throw ("Error opening input file");
cout << "Enter the number of rows " << endl;
cin >> m;
cout << "Enter the number of columns " << endl;
cin >> n;
MatDoub a(m, n);
MatDoub uvw(m, n);
// Read in the matrix
for(Int i=0;i<m;i++){
for(Int j=0;j<n;j++) {
svtest >> a[i][j];
}
}
// Print matrix out to output screen
cout << fixed << setprecision(6);
cout << "Loaded Matrix from Data File" << endl << endl;
for(Int i=0;i<m;i++) {
for(Int j=0;j<n;j++) {
cout << setw(12) << a[i][j];
}
cout << endl;
}
// Perform SVD
SVD mySVD(a);
cout << fixed << setprecision(6);
cout << endl << "Matrix U" << endl << endl;
for (Int i = 0; i < m; i++) {
for (Int j = 0; j < n; j++) {
cout << setw(12) << mySVD.u[i][j];
}
cout << endl;
}
cout << endl;
cout << "Diagonal of matrix W" << endl << endl;
for(Int i=0;i<n;i++){
cout << setw(12) << mySVD.w[i];
}
cout << endl;
cout << "Matrix V-Transpose" << endl;
for(Int i=0;i<n;i++){
for(Int j=0;j<n;j++){
cout << setw(12) << mySVD.v[j][i];
}
cout << endl;
}
cout << endl;
cout << "Product [u] x [w] x [V-Transpose]" << endl;
for(Int i=0; i<m; i++){
for(Int j=0; j<n; j++){
uvw[i][j] = 0.0;
for(Int k=0;k<n;k++){
uvw[i][j] +=mySVD.u[i][k] * mySVD.w[k] * mySVD.v[j][k];
}
cout << setw(12) << uvw[i][j];
}
cout << endl;
}
cout << endl;
cout << endl << "Inverse Condition number = "
<< scientific << mySVD.inv_condition() << endl;
cin >> pause;
return 0;
}
Thanks
Matt
davekw7x
12-11-2009, 10:00 AM
Hello everyone
I have a problem with including svdcmp.cpp....
Here's what I do with the Numerical Recipes Version 2 C++ files on my Linux workstation: I make a library that I can link in with whatever source files I have in my project. This way, you never have to worry about what files to include in order to use NR functions from your project files. You still have to include whatever other C++ header files your project needs, but the NR stuff will taken care of by including nr.h. You will never include any NR C++ files.
Note: It is important that you start with source files exactly as they came in the Numerical Recipes distribution. Do not modify them. (After getting things up and running, you can, of course, modify them any which way you want, but for now, let's just get off the ground with original files.)
Here's what works for me on Centos 5.4 with GNU compiler version 4.1.2:
I installed the nr2 c++ stuff under my home directory, so I have the following directories:
Source code is in
/home/dave/nr2cpp/recipes
Include files are in
/home/dave/nr2cpp/other
Example files are in
/home/dave/nr2cpp/examples
Here's the drill:
cd into the recipes directory and execute the following from a command line:
g++ -c -I../other *.cpp 2>& 1 | tee gcc.log
This lets me see the progress of the compiles and also saves compiler messages in a log file so that I can inspect it later if I need to (in case there are so many compiler messages that the "good stuff" might have scrolled off the screen).
It takes a few minutes, and there should be no significant compiler messages. (No errors at all and a few benign warnings.) If there are any problems at this point and you can't resolve them, then post again with specific questions.
Now, some of the files in the recipes directory are not really library function files, but are example programlets with a main() function. We want to delete their object files before creating the library.
You can find the files by executing the following (still in the recipes directory):
grep -l "main.*(" *.cpp
The programs that I see are badluk.cpp, fredex.cpp, sfroid.cpp, sphfpt.cpp, and sphoot.cpp
Remove the object files from them manually (rm badluk.o; rm fredex.o;...) or execute the following from the command line:
rm $(grep -l "main *(" *.cpp | sed -e 's/\.cpp/\.o/')
Anyhow, confirm that those object files are no longer in the recipes directory, then execute the following:
ar cr libnr2cpp.a *.o
Now you have a library file named libnr2cpp.a that contains object code for all of the NR functions.
cd into the examples directory and create the following Makefile (I recommend that you paste it from this post; don't type it in manually.)
#use local header and library to compile examples
#
# invoke this makefile with something like
# make TARGET=xsvdcmp
#
# or use a script like makeit:
### #
### # #!/bin/sh
### # # invoke makefile with target
### # if [ $# == 0 ]
### # then
### # echo "You must supply a target name for the Makefile"
### # exit
### # else
### # target=$1
### # shift 1
### # echo "make TARGET=$target $args"
### # make TARGET=$target $*
### # fi
#
# put the "makeit" script somewhere on your path
#
# then just
# makeit xsvdcmp
#
CXX = g++
CXXFLAGS = -Wall -W
INCLUDEDIR = ../other
LIBDIR = ../recipes
LIBFILE = nr2cpp
INCLUDES = -I$(INCLUDEDIR)
LIBS = -L$(LIBDIR) -l$(LIBFILE) -lm
TARGET = testx
OBJS = $(TARGET).o
$(TARGET): $(OBJS)
$(CXX) $(OBJS) $(LIBS) -o $(TARGET)
%.o:%.cpp
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
clean:
rm -f $(OBJS) $(TARGET)
Then, in the examples directory, enter the following:
make TARGET=xsvcdmp
Now, once you have convinced yourself that you can compile and execute the example files, you can do the following:
Make a project directory at the same level as the examples directory. In my case that would be /home/dave/nr2cpp/projectname
Copy the Makefile from the examples directory to the projectname directory.
Probably change the "TARGET = testx" line in the Makefile to use whatever name you want for your executable.
If you have more than one source code file, change the OBJS assignment in the Makefile to use object files from all of the files in your project.
If you want to include additional header files not in your project directory, add their directory paths to the "INCLUDEDIR =" line.
If you want to link other libraries, then add the appropriate "-l" entries to the "LIBS =" line. (I have already done this for the standard math directory.) If their location is not in the compiler's search path, add their directory paths to the "LIBDIR=" line.
Then just enter "make" on the command line.
Regards,
Dave
MPD78
12-11-2009, 10:16 AM
Florian,
... Numerical Recipes Version 2 C++ files
I thought you were using Numerical Recipes Version 3 C++.
Sorry about that.
Thanks
Matt
davekw7x
12-11-2009, 11:01 AM
I thought you were using Numerical Recipes Version 3 C++.
Well, this is the NR3 part of the forum, and your instructions were correct for this version. The stuff about making a library of all NR functions won't work with unmodified NR3 files for reasons that were spelled out in this thread: http://www.nr.com/forum/showthread.php?t=1260
Regards,
Dave