0

I have (sort of) learned c++ by myself for physics purposes, so I apologize if this is an easy question. I've tried to find the answer by myself using Google, but I didn't find anything useful (probably because I wasn't sure what kind of search words to use).

For my c++ program, I have to declare 100 (or more) variables like this:

vector< vector<double> > pol1_t1_matrix(SPACE_pol, vector<double>(2));
vector< vector<double> > pol1_t2_matrix(SPACE_pol, vector<double>(2));
vector< vector<double> > pol1_t3_matrix(SPACE_pol, vector<double>(2));
vector< vector<double> > pol1_t4_matrix(SPACE_pol, vector<double>(2));
vector< vector<double> > pol1_t5_matrix(SPACE_pol, vector<double>(2));
vector< vector<double> > pol1_t6_matrix(SPACE_pol, vector<double>(2));
vector< vector<double> > pol1_t7_matrix(SPACE_pol, vector<double>(2));
vector< vector<double> > pol1_t8_matrix(SPACE_pol, vector<double>(2));
vector< vector<double> > pol1_t9_matrix(SPACE_pol, vector<double>(2));
vector< vector<double> > pol1_t10_matrix(SPACE_pol, vector<double>(2));
etc.;

I also use these to write files as follows:

ofstream outputFile_2D_pol1_t1("gnu_2D_pol1_t1_matrix_2sol_num.dat"); 
for(i=0;i<SPACE_pol;i=i+1)
{
    outputFile_2D_pol1_t1 << x_begin + (i * h_pol) << setw(18);
    outputFile_2D_pol1_t1 << pol1_t1_matrix[i][1] << setw(18);
    outputFile_2D_pol1_t1 << endl;
}
outputFile_2D_pol1_t1.close(); 

ofstream outputFile_2D_pol1_t2("gnu_2D_pol1_t2_matrix_2sol_num.dat"); 
for(i=0;i<SPACE_pol;i=i+1)
{
    outputFile_2D_pol1_t2 << x_begin + (i * h_pol) << setw(18);
    outputFile_2D_pol1_t2 << pol1_t2_matrix[i][1] << setw(18);
    outputFile_2D_pol1_t2 << endl;
}
outputFile_2D_pol1_t2.close();

ofstream outputFile_2D_pol1_t3("gnu_2D_pol1_t3_matrix_2sol_num.dat"); 
for(i=0;i<SPACE_pol;i=i+1)
{
    outputFile_2D_pol1_t3 << x_begin + (i * h_pol) << setw(18);
    outputFile_2D_pol1_t3 << pol1_t3_matrix[i][1] << setw(18);
    outputFile_2D_pol1_t3 << endl;
}
outputFile_2D_pol1_t3.close();

etc.;

The above becomes very laborious if I have to do that more than a 100 times (at least up till t100, but sometimes I'll have to do that 1000 times or more). So my question is: is there any way to do all of the above using (separate) loops?

Naively, I would assume it looks something like this (to replace the laborious "declaration of variables" as shown above):

for(i=1;i<101;i=i+1)
{
    double (pol1_t"i"_matrix)[2] = new double[SPACE_pol][2];
}

and (to replace the laborious "writing to files" as shown above):

for(i=1;i<101;i=i+1)
{
        ofstream outputFile_2D_pol1_t"i"("gnu_2D_pol1_t"i"_matrix_2sol_num.dat"); 
        for(j=0;j<SPACE_pol;j=j+1)
        {
            outputFile_2D_pol1_t"i" << x_begin + (j * h_pol) << setw(18);
            outputFile_2D_pol1_t"i" << pol1_tj_matrix[i][1] << setw(18);
            outputFile_2D_pol1_t"i" << endl;
        }
        outputFile_2D_pol1_t"i".close(); 
}
Hunter
  • 357
  • 8
  • 15
  • yes. Look up for vectors – Khalil Khalaf Mar 11 '16 at 01:51
  • 4
    You are already using arrays…so why not make `pol_matrix` an array? Or simpler, `std::vector`? – Jon Purdy Mar 11 '16 at 01:51
  • 1
    `T *p = new T[2];` is archaic and should be avoided. You could write `double bla[100][SPACE_pol][2];` for example – M.M Mar 11 '16 at 01:56
  • btw, keyword to look for might be Dynamic Allocation – Khalil Khalaf Mar 11 '16 at 02:26
  • 1
    @FirstStep using dynamic allocation actually resulted in me declaring arrays using pointers as I have done above. But my task for the next week is to learn vectors, hopefully this will improve my program :) – Hunter Mar 11 '16 at 02:28
  • I don't like Dynamic Memory, although my ideal programmer insisted on its necessity. Cheers for that! vectors are life – Khalil Khalaf Mar 11 '16 at 02:33
  • remove the parentheses in expressions like `t4 = 4 * (0.25/tau)` will make it faster and the result is more correct – phuclv Mar 11 '16 at 03:25
  • 1
    Use arrays (or vectors, or some other container); if you can't do that, consider writing some script (in your favorite scripting language) or a a C++ program which would emit the C++ code you want to have. – Basile Starynkevitch Mar 11 '16 at 05:52
  • @BasileStarynkevitch Thank you, that is actually a good idea (stupid that I didn't think of that). Although it's not very elegant :) – Hunter Mar 11 '16 at 07:16
  • 1
    @Hunter: what makes you think that [metaprogramming](https://en.wikipedia.org/wiki/Metaprogramming) is not elegant (which is a subjective opinion)? Read about [homoiconic](https://en.wikipedia.org/wiki/Homoiconicity) languages (e.g. [Common Lisp](https://en.wikipedia.org/wiki/Common_Lisp)...) and [multi-stage programming](https://en.wikipedia.org/wiki/Multi-stage_programming), etc.. My opinion is on the contrary that meta-programming is a very elegant and powerful concept (and C++ sadly does not use it enough; it has just [templates](https://en.wikipedia.org/wiki/Template_metaprogramming) ). – Basile Starynkevitch Mar 11 '16 at 07:53
  • 1
    @Hunter: See also [this](http://stackoverflow.com/a/28530559/841108) if you consider emitting some C++ code – Basile Starynkevitch Mar 11 '16 at 07:59
  • @BasileStarynkevitch I think there is a big gap in knowledge (you know a lot more than me) so you are probably right. It's just that now I will have to run 2 programs instead of 1 and do some copy-pasting, which doesn't strike me as ideal for such a simple problem. I would have assumed that I'm not the first one with this problem and that there would be a solution along the lines of my the last 2 "for loops" I've written in my question. But still, your solution will save me a lot of time and energy, so thank you again (and thanks for the links, although most of it is going over my head :)). – Hunter Mar 11 '16 at 08:13
  • 1
    @Hunter: you might be right. My PhD thesis (in 1990) was on metaprogramming & metaknowledge approaches. But still, when you are writing any kind of very repetitive code, consider coding something to *generate* that repetitive code. Sometimes, clever [C preprocessor](https://en.wikipedia.org/wiki/C_preprocessor) tricks could be enough... The pragmatically important thing when generating code is to represent in *memory* some [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree) of the code to be generated. – Basile Starynkevitch Mar 11 '16 at 08:20
  • I still think it's simple. Approachable with a small struct and couple vectors – Khalil Khalaf Mar 12 '16 at 15:19

3 Answers3

2

You don't want to be using new, particular with raw pointers. I'm confident your program currently leaks memory because of it. Stick with nested vectors.

You can nest three vectors, but it would probably be easier to just use a class designed for this, such as Boost.MultiArray

Steven Sudit
  • 19,391
  • 1
  • 51
  • 53
  • Ok thank you, I will look into that. Just to add, I do make sure to delete all of them as well at the end of my program. – Hunter Mar 11 '16 at 02:06
  • 1
    I've rewritten my program using vectors (because apparently it is better that way) so +1, but I don't see how it answers my actual question. Maybe that's because I haven't asked the question in an understandable manner. Could you please look at the 2 "for loops" I've naively written at the end of my question; I'm look for something like that to replace my original coding. – Hunter Mar 11 '16 at 04:12
  • 1
    @Hunter The entire code block that you repeated can be broken out into a function that you call with two parameters: a const reference to the matrix (or top-level vector) and a filename. – Steven Sudit Mar 12 '16 at 19:05
1

Take a look at this. std::vector is dynamically allocated, see the modifiers section. So you can declare it at size zero, ten, ... whatever. The key here is that you can resize it and add stuff during the execution, then access its elements using a simple index [i]. The routine is that inside a for loop (if you got the size during execution) or a while loop (if reading from file f.e), you can push_back() elements to it on every iteration. You end up with array(s) of loop-iterations size. Very nice.

Here is a basic demonstration of a two-dimensional vector of double numbers and note that you need to #include <vector>:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<vector<double>> my2dVector; // vector of vectors<double>. initially its size is zero-by-zero and it's possible to assign an initial size.
    vector<double> temp; // this will hold data for everyrow. Notice the clear() in the beginning of the outerloop and the push_back() at the end of it

    for (int Rows = 0; Rows < WhateverDesiredRowSize; Rows++)
    {
        temp.clear();
        for (int Columns = 0; Columns < WhateverDesiredColumnSize; Columns++)
        {
            // here you push_back into temp. Imagine it as the row. So you fill the whole 2d structure row-by-row
            temp.push_back(WhateverDoubleDataYouWant);
        }
        // here you push the whole row into your 2d structure
        my2dVector.push_back(temp);
    }

    return 0;
}
Khalil Khalaf
  • 9,259
  • 11
  • 62
  • 104
  • Thanks for your answer, I will look into vector the coming week. If it works, I'll make sure to come back and upvote your answer. I am curious why someone has downvoted your answer? – Hunter Mar 11 '16 at 02:04
  • Actually me too. I would love to see why and maybe learn. Good luck and you are welcome – Khalil Khalaf Mar 11 '16 at 02:06
  • Not the downvoter, but assume it's because it doesn't explicitly mention `std::vector` and if the link goes down this answer won't really help. A code example probably wouldn't go astray. – Tas Mar 11 '16 at 02:06
  • it's the cplusplus main website, and I do mention vectors and I just highlighted it now. I would appreciate an upvote even if it's not the answer. – Khalil Khalaf Mar 11 '16 at 02:09
  • 1
    Added a basic demonstration. Just because I love vectors :) – Khalil Khalaf Mar 11 '16 at 02:18
  • I've rewritten my program using vectors (because apparently it is better that way) so +1, but I don't see how it answers my actual question. Maybe that's because I haven't asked the question in an understandable manner. Could you please look at the 2 "for loops" I've naively written at the end of my question; I'm look for something like that to replace my original coding. – Hunter Mar 11 '16 at 04:12
  • Help me think about it as objects (100 here and forget about what every actual name of the variable/file should be). what do you want every object to carry? and do you know structs/classes? – Khalil Khalaf Mar 11 '16 at 04:58
  • @FirstStep sorry, I hadn't seen your comment. I don't know how to OOP, which is something I guess I'll need to learn first but I don't have a lot of free time on my hands unfortunately. – Hunter Mar 12 '16 at 05:59
  • It's easy and simple. Answer my questions and I will show you. What do you want every "thing" of those "100 things" to carry (f.e A name + an ID + etc .. )? – Khalil Khalaf Mar 12 '16 at 15:22
  • Using vectors efficiently is tricky and this sample has room for further optimization. – Steven Sudit Mar 12 '16 at 19:05
1

(I gave several comments, they might be interesting enough to make an answer, here is it...)

Use at least C++11 if you can. E.g. if compiling with a recent GCC, use g++ -std=c++11 -Wall (and probably also -g when debugging) ...

First, use if possible arrays (or vectors, or some other C++ standard container); if you can't do that, consider writing some script (in your favorite scripting language) or a C++ program which would emit the C++ code you want to have. You'll need to update your build procedure, e.g. add a few lines in your Makefile

Sometimes (but probably not in your case) using some tricks with C preprocessor is enough (e.g. with X-macro tricks). You could also consider using some more powerful preprocessor, e.g. GPP.

In general, metaprogramming is a useful approach, notably when you begin writing some very repetitive code. Then consider having your particular tool to generate that code. This could be a script (in some scripting language like Python or awk) or your specialized C++ program. Read about homoiconic languages (such as Common Lisp ...), multi-stage programming, partial evaluation.

A useful advice when coding some (e.g. C++) code generator: keep in memory some AST like representations of the emitted code (so build first the AST of the entire generated code, then print it).

If you generate huge C++ routines (e.g. of more than ten thousand lines each), you'll observe that your C++ compiler would take a lot of time to compile such generated C++ code, in particular when you ask it to optimize (empirically, g++ -O2 takes a time quadratic in the size of the longest routine in your source code). If you meet this issue, just modify your C++ generator to generate several smaller routines.

On Linux or POSIX systems, you might even consider having your program which generates at runtime some specialized C++ code (depending on some input data) e.g. in /tmp/generated.cc, then forks a compilation into a /tmp/generated.so plugin (e.g. using system(3) to run some command like g++ -Wall -fPIC -O2 -g -shared /tmp/generated.cc -o /tmp/generated.so ...), and use dlopen(3) (e.g. void*dlh = dlopen("/tmp/generated.so",RTLD_NOW|RTLD_GLOBAL); then test dlh against failure, using dlerror on failure) to dynamically load that plugin, and dlsym(3) to find some (extern "C") symbols there (and fill some function pointers this way). Beware of name mangling so read the C++ dlopen mini-howto. In practice this approach works surprisingly well: my manydl.c C program demonstrates that you can load several millions of such plugins on Linux (of course the practical bottleneck is the time spent in compiling the generated plugins at runtime! you'll need several days to generate a million of plugins and compile them). Notice that a dlopen-ing main program needs to be linked with -rdynamic and -ldl.

BTW, you could perhaps consider embedding some interpreter (like Guile or Lua) in your program... Or use some JIT-compiling library like GCCJIT or LLVM or libjit or asmjit. But that is a different story.

Also, I am not sure that a vector of vectors is an efficient representation of 2D matrixes. I suggest having a class Matrix keeping internally some array of double-s and having inlined member functions (to get the dimensions, get or put a particular element of given two indexes, etc...). You'll probably find some existing library doing that.

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547