I would like to know what the most efficient c++ implementation of the following matlab idiom is.
Suppose I have 3 vectors in matlab, x, y and idx.
x = [13,2,5.5,22,107]
y = [-3,100,200]
idx = [1,2,5]
I want to replace positions 1,2 and 5 of x with the contents of y. In matlab I do
x[idx] = y
What is the best way to do this in c++?
The Armadillo library probably comes closest as one of its goals is to make things easy for folks used to Matlab.
Here is a short example (and uvec is a typdef for vector of unsigned ints)
// set four specific elements of X to 1
uvec indices;
indices << 2 << 3 << 6 << 8;
X.elem(indices) = ones<vec>(4);
Obviously, the right-hand side could be any other vector of the same dimension as the index.
But there are few language-imposed constraints you cannot overcome:
zero-based indexing at the C++ level (which you could alter, but few C / C++ programmers will consider it a good idea)
certain operators, including [
A loop seems simple enough, although it can be made simpler with a helper function.
// helper function to get the size of an array
template<typename T, size_t S>
constexpr size_t size(T (&)[S])
{
return S;
}
// loop
for (size_t i = 0; i < size(idx); ++i) x[idx[i]] = y[i];
Of course, here you should check that y is large enough:
If you want it in pretty basic C++ (with no prizes for elegance) try this:
double x[] = { 13.0, 2.0, 5.5, 22.0, 107.0 };
double y[] = { -3.0, 100.0, 200.0 };
size_t idx[] = { 1, 2, 5 };
for ( size_t i = 0; i < sizeof(x)/sizeof(double); ++i )
cout << x[i] << " ";
cout << endl;
// Make a mutable copy of x
double x1[ sizeof(x)/sizeof(double) ];
std::copy( x, x + sizeof(x)/sizeof(double), x1 );
// The transformation
for ( size_t i = 0; i < sizeof(idx)/sizeof(double); ++i )
x1[idx[i]] = y[i];
for ( size_t i = 0; i < sizeof(x)/sizeof(double); ++i )
cout << x1[i] << " ";
cout << endl;
Note exactly pretty, but it does give the following:
13 2 5.5 22 107
-3 100 5.5 22 200
(Note that I've assumed that the indexing starts from 1 rather than 0 in idx)
Related
I've been doing a really really simple finite difference code that solves the 1D convection equation.
It seems to work pretty fine but if I increase the size of the arrays that I'm using I get a segmentation fault error. This happens when I reduce the timestep or if I increase the time interval.
The code is
#include <math.h>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <cmath>
using namespace std;
int main(){
double xi = 0.0;
double xf = 10.0;
double ti = 0.0;
double tf = 1.0;
Time interval, if it is equal to 1 the code works fine.
double x,t;
double dt = 0.1;
double dx = 0.1;
int nstep_x = (xf - xi)/dx;
int nstep_t = (tf - ti)/dt;
double f[nstep_x][nstep_t];
double ex[nstep_x][nstep_t];
// Parameters
const double v = 0.05;
const double D = 0.0001;
const double pi = 3.141592654;
ofstream salida;
salida.open("out");
for (int i = 0 ; i <= nstep_x; i++){
x = xi + dx*i;
f[i][0] = 0.5*sin(pi*x); //Initial conditions
salida << x << " " << 0 << " " << f[i][0] << endl;
}
salida << endl;
for (int n = 0; n <= nstep_t ; n++){
t = ti + n*dt;
for (int i = 1; i <= nstep_x; i++){
x = xi + dx*i;
f[i][n+1] = f[i][n] - ((v*dt)/(2*dx))*(f[i+1][n] - f[i-1][n]); //CONV|SOC
ex[i][n] = 0.5*sin(pi*x - v*t);
salida << x << " " << t << " " << ex[i][n] << " " << f[i][n] << endl;
}
salida << endl;
salida << endl;
}
}
I think that is not a problem of going out of the array bounds in the loops because the code works for "small" arrays.
I guess that I must be doing something wrong with the array handling but I can't find the error.
You have several issues with your code. One is that you're using variable length arrays (VLA's) which are not standard C++.
double f[nstep_x][nstep_t];
double ex[nstep_x][nstep_t];
This is not valid C++, as arrays must have its size known at compile-time, not run time.
The quick solution is to use std::vector<std::vector<double>>:
#include <vector>
//...
std::vector<std::vector<double>> f(nstep_x, std::vector<double>(nstep_t));
std::vector<std::vector<double>> ex = f; // use copy constructor to easily create a copy
The above code basically does what your originally did, but has several advantages:
1) The code is now standard C++, as it uses a standard C++ container class, std::vector.
2) You won't get into stack space issues if nstep_x and/or nstep_t are large values since std::vector gets the memory to store its items from the heap.
3) You can check boundary conditions by using std::vector::at() if it is suspected that you are accessing the vector out-of-bounds. You don't have this test if you're using VLA's (or just arrays in general).
It is item 3) that becomes important in attempting to find the errors.
If we take your code, change it to using std::vector, we see that there is a problem with "small arrays", going against what you thought was not an issue. If we look at this code:
for (int i = 0 ; i <= nstep_x; i++)
{
x = xi + dx*i;
f.at(i).at(0) = 0.5*sin(pi*x); // exception is thrown here
}
We see that there is an out-of-bounds condition. This was detected by using vector::at() instead of [ ] to access the elements in the vector. A std::out_of_range exception is thrown at the line where f[i][0] is being assigned to.
Here is a live example showing this error.
How do you fix this? Simply don't go out of bounds by changing the loop:
for (int i = 0 ; i < nstep_x; i++)
You also have boundary condition issues in your other loops:
for (int n = 0; n <= nstep_t ; n++)
{
t = ti + n*dt;
for (int i = 1; i <= nstep_x; i++)
{
x = xi + dx*i;
f.at(i).at(n+1) = f[i][n] - ((v*dt)/(2*dx))*(f.at(i+1).at(n) - f[i-1][n]);
ex.at(i)(n) = 0.5*sin(pi*x - v*t);
}
}
You will see using at() that you are accessing the f and ex vectors out-of-bounds, and thus can diagnose the issue correctly (as the other answers have done).
gdb would help to see where it actually crashes but:
f[i+1][n] and i grows up to nstep_x, but f is allocated as f[nstep_x][nstep_t],
so it seems like you'd be accessing f[nstep_x+1][n], but the maximum you can is f[nstep_x-1][n].
As noted in the comments, the reason is not the array size, but the for loops
for (int i = 0 ; i <= nstep_x; i++) {
// ...
f[i][0] = 0.5*sin(pi*x);
}
This is a classic one off error, going one beyond the end of the array. The correct way is
for (int i = 0 ; i < nstep_x; i++) {
// ...
}
Note < vs <=.
for (int n = 0; n <= nstep_t ; n++) {
for (int i = 1; i <= nstep_x; i++) {
// ...
f[i][n+1] = f[i][n] - ((v*dt)/(2*dx))*(f[i+1][n] - f[i-1][n]);
}
}
Here too, you have <= instead of <. Additionally you access indexes at i + 1 and n + 1 respectively, which means, you are not one but two steps over the end of the array.
When calculating the second time-step, you're referring to f at x=xi and t=ti+dt which wasn't calculated in the first time-step, since i runs from 1. There is a similar problem at the other boundary.
You need to specify the spatial boundary conditions for x=xi and x=xf for all t as well as fixing the off-by-one errors noted in the other answers.
To clarify, the convection equation requires boundary conditions to be specified for f(x=xi,t) and f(x=xf, t). This is typically either a constant or a prescribed flow rate in the case of an 'insulated' boundary, but other types exist.
I am trying to get the value of an element in an array in order to use it in an if statement but unfortunately the following code is not working for me. The cout of comp is not matching the first element of the array C. I'm new to OpenCV so any help is appreciated.
Mat A = (Mat_<double>(2,1) << u, v);
Mat B = (Mat_<double>(2,6) << -1/Z, 0 , x/Z , x*y , -(x*x+1),y,
0 ,-1/Z, y/Z ,y*y+1, -x*y ,-x);
Mat pinvB = B.inv(DECOMP_SVD);
Mat C=pinvB*A; // 6x1 Array
float comp = C.at<float>(0,0);
cout << "comp " << comp << endl; //This value does not match C[0,0]
cout << "C " << C << endl;
if (comp < 0.0001){
//process
}
Your Mat_<double> instances internally store doubles. When you do this:
float comp = C.at<float>(0,0);
you are trying to use some of the bits that form a double, and interpret them as a float. Floating point representation means that half of the bits of a double don't translate into a meaningful float (assuming a platform where float has half the size of a double, which is quite common). So, call C.at<double> instead.
Actually, if you use the template version of cv::Mat_<_Tp>, you can access pixel value by Mat_<_Tp>::operator ()(int y, int x)
cv::Mat_<double> M(3, 3);
for (int i = 0;i < 3; ++i) {
for (int j = 0;j < 3; ++j) {
std::cout<<M(i, j)<<std::endl;
}
}
so that later if you change the template argument from double to float, you don't need to modify each at().
We are trying to understand accumarray function of MATLAB, wanted to write C/C++ code for the same for our understanding. Can someone help us with a sample/pseudo code?
According to the documentation,
The function processes the input as follows:
Find out how many unique indices there are in subs. Each unique index defines a bin in the output array. The maximum index value in
subs determines the size of the output array.
Find out how many times each index is repeated.
This determines how many elements of vals are going to be accumulated at each bin in the output array.
Create an output array. The output array is of size max(subs) or of size sz.
Accumulate the entries in vals into bins using the values of the indices in subs and apply fun to the entries in each bin.
Fill the values in the output for positions not referred to by subs. Default fill value is zero; use fillval to set a different
value.
So, translating to C++ (this is untested code),
template< typename sub_it, typename val_it, typename out_it,
typename fun = std::plus< typename std::iterator_traits< val_it >::value_type >,
typename T = typename fun::result_type >
out_it accumarray( sub_it first_index, sub_it last_index,
val_it first_value, // val_it last_value, -- 1 value per index
out_it first_out,
fun f = fun(), T fillval = T() ) {
std::size_t sz = std::max_element( first_index, last_index ); // 1. Get size.
std::vector< bool > used_indexes; // 2-3. remember which indexes are used
std::fill_n( first_out, sz, T() ); // 4. initialize output
while ( first_index != last_index ) {
std::size_t index = * first_index;
used_indexes[ index ] = true; // 2-3. remember that this index was used
first_out[ index ] = f( first_out[ index ], * first_value ); // 5. accumulate
++ first_value;
++ first_index;
}
// If fill is different from zero, reinitialize untouched values
if ( fillval != T() ) {
out_it fill_it = first_out;
for ( std::vector< bool >::iterator used_it = used_indexes.begin();
used_it != used_indexes.end(); ++ used_it ) {
if ( * used_it ) * fill_it = fillval;
}
}
return first_out + sz;
}
This has a few shortcomings, for example the accumulation function is called repeatedly instead of once with the entire column vector. The output is placed in pre-allocated storage referenced by first_out. The index vector must be the same size as the value vector. But most of the features should be captured pretty well.
Many thanks for your response. We were able to fully understand and implement the same in C++ (we used armadillo). Here is the code:
colvec TestProcessing::accumarray(icolvec cf, colvec T, double nf, int p)
{
/* ******* Description *******
here cf is the matrix of indices
T is the values whose data is to be
accumulted in the output array S.
if T is not given (or is scaler)then accumarray simply converts
to calculation of histogram of the input data
nf is the the size of output Array
nf >= max(cf)
so pass the argument accordingly
p is not used in the function
********************************/
colvec S; // output Array
S.set_size(int(nf)); // preallocate the output array
for(int i = 0 ; i < (int)nf ; i++)
{
// find the indices in cf corresponding to 1 to nf
// and store in unsigned integer array q1
uvec q1 = find(cf == (i+1));
vec q ;
double sum1 = 0 ;
if(!q1.is_empty())
{
q = T.elem(q1) ; // find the elements in T having indices in q1
// make sure q1 is not empty
sum1 = arma::sum(q); // calculate the sum and store in output array
S(i) = sum1;
}
// if q1 is empty array just put 0 at that particular location
else
{
S(i) = 0 ;
}
}
return S;
}
Hope this will help others too!
Thanks again to everybody who contributed :)
Here's what I came up with. Note: I went for readability (since you wanted to understand best), rather than being optimized. Oh, and I've never used MATLAB, I was just going off of this sample I saw just now:
val = 101:105;
subs = [1; 2; 4; 2; 4]
subs =
1
2
4
2
4
A = accumarray(subs, val)
A =
101 % A(1) = val(1) = 101
206 % A(2) = val(2)+val(4) = 102+104 = 206
0 % A(3) = 0
208 % A(4) = val(3)+val(5) = 103+105 = 208
Anyway, here's the code sample:
#include <iostream>
#include <stdio.h>
#include <vector>
#include <map>
class RangeValues
{
public:
RangeValues(int startValue, int endValue)
{
int range = endValue - startValue;
// Reserve all needed space up front
values.resize(abs(range) + 1);
unsigned int index = 0;
for ( int i = startValue; i != endValue; iterateByDirection(range, i), ++index )
{
values[index] = i;
}
}
std::vector<int> GetValues() const { return values; }
private:
void iterateByDirection(int range, int& value)
{
( range < 0 ) ? --value : ++value;
}
private:
std::vector<int> values;
};
typedef std::map<unsigned int, int> accumMap;
accumMap accumarray( const RangeValues& rangeVals )
{
accumMap aMap;
std::vector<int> values = rangeVals.GetValues();
unsigned int index = 0;
std::vector<int>::const_iterator itr = values.begin();
for ( itr; itr != values.end(); ++itr, ++index )
{
aMap[index] = (*itr);
}
return aMap;
}
int main()
{
// Our value range will be from -10 to 10
RangeValues values(-10, 10);
accumMap aMap = accumarray(values);
// Now iterate through and check out what values map to which indices.
accumMap::const_iterator itr = aMap.begin();
for ( itr; itr != aMap.end(); ++itr )
{
std::cout << "Index: " << itr->first << ", Value: " << itr->second << '\n';
}
//Or much like the MATLAB Example:
cout << aMap[5]; // -5, since out range was from -10 to 10
}
In addition to Vicky Budhiraja "armadillo" example, this one is a 2D version of accumarray using similar semantic than matlab function:
arma::mat accumarray (arma::mat& subs, arma::vec& val, arma::rowvec& sz)
{
arma::u32 ar = sz.col(0)(0);
arma::u32 ac = sz.col(1)(0);
arma::mat A; A.set_size(ar, ac);
for (arma::u32 r = 0; r < ar; ++r)
{
for (arma::u32 c = 0; c < ac; ++c)
{
arma::uvec idx = arma::find(subs.col(0) == r &&
subs.col(1) == c);
if (!idx.is_empty())
A(r, c) = arma::sum(val.elem(idx));
else
A(r, c) = 0;
}
}
return A;
}
The sz input is a two columns vector that contain : num rows / num cols for the output matrix A. The subs matrix is a 2 columns with same num rows of val. Num rows of val is basically sz.rows by sz.cols.
The sz (size) input is not really mandatory and can be deduced easily by searching the max in subs columns.
arma::u32 sz_rows = arma::max(subs.col(0)) + 1;
arma::u32 sz_cols = arma::max(subs.col(1)) + 1;
or
arma::u32 sz_rows = arma::max(subs.col(0)) + 1;
arma::u32 sz_cols = val.n_elem / sz_rows;
the output matrix is now :
arma::mat A (sz_rows, sz_cols);
the accumarray function become :
arma::mat accumarray (arma::mat& subs, arma::vec& val)
{
arma::u32 sz_rows = arma::max(subs.col(0)) + 1;
arma::u32 sz_cols = arma::max(subs.col(1)) + 1;
arma::mat A (sz_rows, sz_cols);
for (arma::u32 r = 0; r < sz_rows; ++r)
{
for (arma::u32 c = 0; c < sz_cols; ++c)
{
arma::uvec idx = arma::find(subs.col(0) == r &&
subs.col(1) == c);
if (!idx.is_empty())
A(r, c) = arma::sum(val.elem(idx));
else
A(r, c) = 0;
}
}
return A;
}
For example :
arma::vec val = arma::regspace(101, 106);
arma::mat subs;
subs << 0 << 0 << arma::endr
<< 1 << 1 << arma::endr
<< 2 << 1 << arma::endr
<< 0 << 0 << arma::endr
<< 1 << 1 << arma::endr
<< 3 << 0 << arma::endr;
arma::mat A = accumarray (subs, val);
A.raw_print("A =");
Produce this result :
A =
205 0
0 207
0 103
106 0
This example is found here : http://fr.mathworks.com/help/matlab/ref/accumarray.html?requestedDomain=www.mathworks.com
except for the indices of subs, armadillo is 0-based indice where matlab is 1-based.
Unfortunaly, the previous code is not suitable for big matrix. Two for-loop with a find in vector in between is really bad thing. The code is good to understand the concept but can be optimized as a single loop like this one :
arma::mat accumarray(arma::mat& subs, arma::vec& val)
{
arma::u32 ar = arma::max(subs.col(0)) + 1;
arma::u32 ac = arma::max(subs.col(1)) + 1;
arma::mat A(ar, ac);
A.zeros();
for (arma::u32 r = 0; r < subs.n_rows; ++r)
A(subs(r, 0), subs(r, 1)) += val(r);
return A;
}
The only change are :
init the output matrix with zero's.
loop over subs rows to get the output indice(s)
accumulate val to output (subs & val are row synchronized)
A 1-D version (vector) of the function can be something like :
arma::vec accumarray (arma::ivec& subs, arma::vec& val)
{
arma::u32 num_elems = arma::max(subs) + 1;
arma::vec A (num_elems);
A.zeros();
for (arma::u32 r = 0; r < subs.n_rows; ++r)
A(subs(r)) += val(r);
return A;
}
For testing 1D version :
arma::vec val = arma::regspace(101, 105);
arma::ivec subs;
subs << 0 << 2 << 3 << 2 << 3;
arma::vec A = accumarray(subs, val);
A.raw_print("A =");
The result is conform with matlab examples (see previous link)
A =
101
0
206
208
This is not a strict copy of matlab accumarray function. For example, the matlab function allow to output vec/mat with size defined by sz that is larger than the intrinsec size of the subs/val duo.
Maybe that can be a idea for addition to the armadillo api. Allowing a single interface for differents dimensions & types.
Edit
I am now using odeint. It is fairly simple to use and less memory hungry than my brute force algorithm implementation.
Check my questions here-->http://stackoverflow.com/questions/12060111/using-odeint-function-definition
and here-->http://stackoverflow.com/questions/12150160/odeint-streaming-observer-and-related-questions
I am trying to implement a numerical method (Explicit Euler) to solve a set of three coupled differential equations. I have worked with C before, but that was a very long time ago (effectively forgotten everything). I have a pretty good idea on what I want my program to do and also have a rough algorithm.
I am interested in using C++ for this task (picked up Stroustroup's Programming: Principles and Practice using C++). My question is, should I go with arrays or vectors? Vectors seem easier to handle, but I was unable to find how you can make a function return a vector? Is it possible for a function to return more than one vector? At this point, I am familiarizing myself with the C++ syntax.
I basically need my function to return many arrays. I realize that it is not possible in C++, so I can also work with some nested structure such as {{arr1},{arr2},{arr3}..}. Please bear with me as I am a noob and come from programming in Mathematica.
Thanks!
If you want to use C++ for integrating ordinary differential equations and you don't want to reinvent the wheel use odeint. This lib is on its way of becoming the de facto standard for solving ODEs in C++. The code is very flexible and highly optimized and can compete with any handcrafted C-code (and Fortran anyway).
Commenting on you question on returning vectors or arrays: Functions can return vectors and arrays if the are wrapped in a class (like std::array). But this is not recommended, since you make many unnecessary copies (incl. calling the constructors and destructors every time).
I assume you want to put your function equation into a c++ function and let it return the resulting vector. For this task it's much better if you pass a reference to a vector to the function and let the function fill this vector. This is also the way how odeint has implemented this.
This link might help you, but for ordinary differential equations :
http://www.codeproject.com/KB/recipes/odeint.aspx
To make the program do what you wan you could take a look at this code, It may be get you started.
I found it very useful, and tested it against mathematica solution, and it is ok.
for more information go here
/*
A simple code for option valuation using the explicit forward Euler method
for the class Derivative Securities, fall 2010
http://www.math.nyu.edu/faculty/goodman/teaching/DerivSec10/index.html
Written for this purpose by Jonathan Goodman, instructor.
Assignment 8
*/
#include <iostream>
#include <fstream>
#include <math.h>
#define NSPOTS 100 /* The number of spot prices computed */
/* A program to compute a simple binomial tree price for a European style put option */
using namespace std;
// The pricer, main is at the bottom of the file
void FE( // Solve a pricing PDE using the forward Euler method
double T, double sigma, double r, double K, // The standard option parameters
double Smin, double Smax, // The min and max prices to return
int nPrices, // The number of prices to compute between Smin and Smax,
// Determines the accuracy and the cost of the computation
double prices[], // An array of option prices to be returned.
double intrinsic[], // The intrinsic value at the same prices
double spots[], // The corresponding spot prices, computed here for convenience.
// Both arrays must be allocated in the calling procedure
double *SEarly ) { // The early exercise boundary
// Setup for the computation, compute computational parameters and allocate the memory
double xMin = log(Smin); // Work in the log variable
double xMax = log(Smax);
double dx = ( xMax - xMin )/ ( (double( nPrices - 1 ) ) ); // The number of gaps is one less than the number of prices
double CFL = .8; // The time step ratio
double dt = CFL*dx*dx/sigma; // The forward Euler time step size, to be adjusted slightly
int nTimeSteps = (int) (T/dt); // The number of time steps, rounded down to the nearest integer
nTimeSteps++; // Now rounded up
dt = T / ( (double) nTimeSteps ); // Adjust the time step to land precisely at T in n steps.
int nx = nPrices + 2*nTimeSteps; // The number of prices at the final time, growing by 2 ...
// ... each time step
xMin = xMin - nTimeSteps*dx; // The x values now start here
double *fOld; // The values of the pricing function at the old time
fOld = new double [nx]; // Allocated using old style C++ for simplicity
double *fNew; // The values of the pricing function at the new time
fNew = new double [nx];
double *V; // The intrinsic value = the final condition
V = new double [nx];
// Get the final conditions and the early exercise values
double x; // The log variable
double S; // A stock price = exp(x)
int j;
for ( j = 0; j < nx; j++ ) {
x = xMin + j*dx;
S = exp(x);
if ( S < K ) V[j] = K-S; // A put struck at K
else V[j] = 0;
fOld[j] = V[j]; // The final condition is the intrinsic value
}
// The time stepping loop
double alpha, beta, gamma; // The coefficients in the finite difference formula
alpha = beta = gamma = .333333333333; // XXXXXXXXXXXXXXXXXXXXXXXXXXX
int jMin = 1; // The smallest and largest j ...
int jMax = nx - 1; // ... for which f is updated. Skip 1 on each end the first time.
int jEarly ; // The last index of early exercise
for ( int k = nTimeSteps; k > 0; k-- ) { // This is, after all, a backward equation
jEarly = 0; // re-initialize the early exercise pointer
for ( j = jMin; j < jMax; j++ ) { // Compute the new values
x = xMin + j*dx; // In case the coefficients depend on S
S = exp(x);
fNew[j] = alpha*fOld[j-1] + beta*fOld[j] + gamma*fOld[j+1]; // Compute the continuation value
if ( fNew[j] < V[j] ) {
fNew[j] = V[j]; // Take the max with the intrinsic value
jEarly = j; // and record the largest early exercise index
}
}
for ( j = jMin; j < jMax; j++ ) // Copy the new values back into the old array
fOld[j] = fNew[j];
jMin++; // Move the boundaries in by one
jMax--;
}
// Copy the computed solution into the desired place
jMin--; // The last decrement and increment were mistakes
jMax++;
int i = 0; // The index into the output array
for ( j = jMin; j < jMax; j++ ) { // Now the range of j should match the output array
x = xMin + j*dx;
S = exp(x);
prices[i] = fOld[j];
intrinsic[i] = V[j];
spots[i++] = S; // Increment i after all copy operations
}
double xEarly = xMin + jEarly*dx;
*SEarly = exp(xEarly); // Pass back the computed early exercise boundary
delete fNew; // Be a good citizen and free the memory when you're done.
delete fOld;
delete V;
return;
}
int main() {
cout << "Hello " << endl;
ofstream csvFile; // The file for output, will be csv format for Excel.
csvFile.open ("PutPrice.csv");
double sigma = .3;
double r = .003;
double T = .5;
double K = 100;
double Smin = 60;
double Smax = 180;
double prices[NSPOTS];
double intrinsic[NSPOTS];
double spots[ NSPOTS];
double SEarly;
FE( T, sigma, r, K, Smin, Smax, NSPOTS, prices, intrinsic, spots, &SEarly );
for ( int j = 0; j < NSPOTS; j++ ) { // Write out the spot prices for plotting
csvFile << spots[j];
if ( j < (NSPOTS - 1) ) csvFile << ", "; // Don't put a comma after the last value
}
csvFile << endl;
for ( int j = 0; j < NSPOTS; j++ ) { // Write out the intrinsic prices for plotting
csvFile << intrinsic[j];
if ( j < (NSPOTS - 1) ) csvFile << ", "; // Don't put a comma after the last value
}
csvFile << endl;
for ( int j = 0; j < NSPOTS; j++ ) { // Write out the computed option prices
csvFile << prices[j];
if ( j < (NSPOTS - 1) ) csvFile << ", ";
}
csvFile << endl;
csvFile << "Critical price," << SEarly << endl;
csvFile << "T ," << T << endl;
csvFile << "r ," << r << endl;
csvFile << "sigma ," << sigma << endl;
csvFile << "strike ," << K << endl;
return 0 ;
}
I have a problem, let's say:
Find all two pairs of numbers (x,y) and (z,t) such that x³ + y³ = z³ + t³, where (x, y) != (z, t) and x³ + y³ < 10,000.
Taking the cube root of 10,000 yeilds 21.544 -> round down to 21, so I got:
#include <iostream>
using namespace std;
int main() {
for( int x = 1; x <= 20; ++x ) {
for( int y = x + 1; y <= 21; ++y ) {
for( int z = x + 1; z <= y - 1; ++z ) {
for( int t = z; t <= y - 1; ++t ) {
if( x*x*x + y*y*y == z*z*z + t*t*t ) {
cout << x << ", " << y << ", " << z << ", " << t << endl;
}
}
}
}
}
return 0;
}
I know this code could be optimized more, and that's what I'm looking for. Plus, one of my friends told me that y could be x + 2 instead of x + 1, and I doubt this since if
x = 1, then we will never have y = 2, which in this case missed one possible solution.
Any thought?
Well there's one obvious algorithmic optimization that can be made given the current loop structure, you optimize quite rightly by limiting your ranges to the cube root of 10,000. However you can go farther and limit your range on y based on the cube root of 10,000 - x. That's one thing you can do.
The other optimization is that there's no reason on earth that this should be 4 loops. Simply do 2 loops and compute the values of x^3 + y^3 and check for duplicates. (This is as good as you're going to get without delving into features of cube roots.)
This isn't actually using the API correctly but you get the idea:
multimap<int, std::pair<int, int> > map;
for (int i = 1; i < 21; i++) {
(for int j = x; j < cube_root(10000 - i^3); j++ {
multimap.insert (i^3 + j^3, std::pair<int, int>(i,j);
Then you just iterate through the multimap and look for repeats.
Typical tradeoff: memory for speed.
First the bound on x is quite large: if we suppose that (x,y) is ordered with x <= y, then
x^3 + y^3 < N and x^3 < y^3 (for positive numbers)
=> x^3 + x^3 < N (by transitivity)
<=> x^3 < N/2
<=> x <= floor((N/2)^(1/3))
Thus x <= 17 here.
Now, let us memoize the result of x^3 + y^3 and build an associative table (sum -> pairs). By the way, is there a reason to discard (x,x) as a pair ?
int main(int argc, char* argv[])
{
typedef std::pair<unsigned short, unsigned short> Pair;
typedef std::vector<Pair> PairsList;
typedef std::unordered_map<unsigned short, PairsList> SumMap;
// Note: arbitrary limitation, N cannot exceed 2^16 on most architectures
// because of the choice of using an `unsigned short`
unsigned short N = 10000;
if (argc > 1) { N = boost::lexical_cast<unsigned short>(argv[1]); }
SumMap sumMap;
for (unsigned short x = 1; x*x*x <= N/2; ++x)
{
for (unsigned short y = x; x*x*x + y*y*y <= N; ++y)
{
sumMap[x*x*x + y*y*y].push_back(Pair(x,y));
}
}
for (SumMap::const_reference ref: sumMap)
{
if (ref.second.size() > 1)
{
std::cout << "Sum: " << ref.first
<< " can be achieved with " << ref.second << "\n";
// I'll let you overload the print operator for a vector of pairs
}
}
return 0;
}
We are O(N^2) here.
Make a list of all numbers and their operational result. Sort the list by the results. Test matching results for having different operands.
Use a table from sums to the set of pairs of numbers generating that sum.
You can generate that table by two nested for loops, and then run through the table collecting the sums with multiple solutions.
I'd suggest calculating the powers in outer loops (EDIT: Moved calculations out of the for loops):
int x3, y3, z3;
for( int x = 1; x <= 20; ++x ) {
x3 = x * x * x;
for( int y = x + 1; y <= 21; ++y ) {
y3 = y * y * y;
for( int z = x + 1; z <= y - 1; ++z ) {
z3 = z * z * z;
for( int t = z; t <= y - 1; ++t ) {
if( x3 + y3 == z3 + t*t*t ) {
cout << x << ", " << y << ", " << z << ", " << t << endl;
}
}
}
}
}
Anyway, why do you want to optimize (at least for this example)? This runs in 20 ms on my PC... So I guess you have similar problems at a larger scale.
As a general summary:
Calculate the cubes as you loop rather than at the end, thus int xcubed = x*x*x; just after the loop of x (similarly with y and z). This saves you calculating the same values multiple times. Put them in a table so you only calculate these once.
Create a table of sums of cubes, using a hash_table of some extent, and let it hold duplicates (not to be confused with a hashed-collision).
Any that has a duplicate is a solution.
1729 should come up as one of your solutions by the way. 1 cubed plus 12 cubed and also 9 cubed + 10 cubed.
To test performance you could of course pick a much higher value of maxsum (as well as run it several times).
The algorithm is strictly O(N^2/3). (2/3 because you go only to the cube-root of N and then it is O(m^2) on that smaller range).