0

So I'm working on a homework assignment and I need to create recursive functions for partitions, Stirling numbers(first and second kind), and Chebyshev polynomials of the first. My program should be able to have a user input a positive integer n, and then create files named Partitions.txt, Stirling1.txt, Stirling2.txt, and Chebyshev.txt, that creates a table of all values f(k,m) for 1<=k<=n and 1<=m<=n. I'm struggling just to start off the assignment and feel like I have no understanding of it even though I've been doing research and trying to figure it out. If someone can help me out, I'd really appreciate it! Thank you!

    #include <iostream>
    #include <vector>
    #include "OutputFile.h"

    using namespace std;
    using namespace OutputStream;


    int firstKindStirling();
    vector<vector<int> > getPartitions(int number, int maxElement);

    int main() {

        cout << "Welcome! Please input a number m:";
        int m;
        cin>>m;


        OFile fout("Partitions.txt");

        return 0;
    }

    vector<vector<int> > getPartitions(int number, int maxElement)
    {
        if (number < 1) 
            return vector<vector<int>>();

       vector<vector<int>> partitions;

        if (number <= maxElement) 
            partitions.push_back(number); //for some reason this doesn't want to work. Not sure what I'm missing here. 

        for (int i = number - maxElement; i < number; ++i)
        {
            // (recursively) get the partitions of `i`, with elements no larger than `n - i`
            auto partitionsForI = getPartitions(i, number - i);

            // add `n - i` to the front of all of those partitions
            for(vector<int>& partition : partitionsForI)
            {
                partition.insert(partition.begin(), number - i);
            }

            // add these new partitions to our list.
            partitions.insert(partitions.end(), partitionsForI.begin(), partitionsForI.end());
        }
        return partitions;
    }

    int firstKindStirling(int n, int k) 
    {
        if (n == 0 && k == 0) return 1;
        else if (n == 0 || k == 0) return 0;
        else return -(n-1) * firstKindStirling(n-1, k) + firstKindStirling(n-1, k-1);
    }

And here's my Output .h file

    #ifndef OUTPUT_H
    #define OUTPUT_H

    #include <fstream>
    #include <string>
    #include <vector>
    #include <iostream>
    #include <sys/stat.h>
    #include <sstream>
    #include <memory>

    namespace OutputStream {

        class OFile {
            std::ofstream file;
        public:

            OFile(std::string filename, size_t output_precision = 10) {

                file.open(filename);
                if(file.fail()) throw std::runtime_error("Error: cannot open file");

                file.precision(output_precision);

            };

            /*
            OFile& operator<<(int x) {
                file<<x;
                return *this;
            }
            */

            /*
            OFile& operator<<(const Point2D& p) {
                file<<p;
                return *this;
            }
            */

            OFile& operator<<(const std::vector<int>& v) {

                for(auto x : v) file<<x<<std::endl;
                return *this;
            }


            template<typename T>
            OFile& operator<<(const T& p) {
                file << p;
                return *this;
            }


            ~OFile() { file.close(); };

        };


        // Strongly enumerate type
        enum class FileType { Input, Output, SafeOutput };

        // Partial Template Specialization
        template<FileType> class File;

        template<>
        class File < FileType::Input > {
        public:
            File( const std::string& filename ) : fin(filename) {

                if(fin.fail()) throw std::runtime_error("Error opening file: "+filename);
            };

            /** ...

            IFile& allows for syntax like
            fin>>a>>b>>c;
            */
            File& operator>>(int& a) {
                fin>>a;
                return *this;
            }

            /**...*/
            operator bool() {
                return !(fin.fail());
            }

            operator std::string() {
                return "Active";
            }

            // operator [data type]() {
                // code here
            //  return [object of type data type];
            // }

            friend File& getline( File& fin, std::string& line) {
                getline( fin.fin, line);
                return fin;
            }

            friend File& getrow( File& fin, std::vector<int>& rows);
            friend File& getmatrix( File& fin, std::vector< std::vector<int> >& table);

            ~File() { fin.close(); };
        private:
            std::ifstream fin;
        };  

        template<>
        class File < FileType::Output > {
            std::ofstream file;        
        public:

            File(std::string filename, size_t output_precision = 10) {

                file.open(filename);
                if(file.fail()) throw std::runtime_error("Error: cannot open file");

                file.precision(output_precision);

            };

            /*
            OFile& operator<<(int x) {
                file<<x;
                return *this;
            }
            */

            /*
            OFile& operator<<(const Point2D& p) {
                file<<p;
                return *this;
            }
            */

            File& operator<<(const std::vector<int>& v) {

                for(auto x : v) file<<x<<std::endl;
                return *this;
            }


            template<typename T>
            File& operator<<(const T& p) {
                file << p;
                return *this;
            }


            ~File() { file.close(); };

        };

    }

    #endif
  • Which parts are you having trouble with? Do you understand the concepts of [Stirling numbers](http://en.wikipedia.org/wiki/Stirling_number) and [Chebyshev polynomials](http://en.wikipedia.org/wiki/Chebyshev_polynomials)? What language are you using? What do you mean "recursive functions for partitions"? – ahruss Jul 31 '14 at 01:34
  • So partitions are talking about integer partitions. So for example, if I have an integer n, say, 5. The partition is the set of positive integers that sum up to 5. {5}, {4,1}, {3,2}, {3,1,1}, {2,2,1}, {2,1,1,1}, and {1,1,1,1,1}. And I don't understand the concept of Stirling numbers or Chebyshev polynomials but my professor said we shouldn't need to in order to do the assignment. – Nisha Sharaschandra Jul 31 '14 at 01:51
  • Has he given you instructions on how to generate them, then, because if not, you're going to have to have at least *some* understanding... – ahruss Jul 31 '14 at 01:56

1 Answers1

2

This is really several questions in one, so I will take it in parts.

Partitioning

This is probably the hardest of these tasks, but it's pretty doable if you break it down.

What are all the partitions of a number n? The first number in each partition must be between 1 and n. Since we don't care about order, let's just always keep the numbers in descending order. So the first list of partitions looks something like this:

  • {n}
  • {n-1, 1}
  • {n-2, 2}, {n - 2, 1, 1}
  • {n-3, 3}, {n - 3, 2, 1}, {n - 3, 1, 1, 1}
  • ...
  • {1, 1, ..., 1}

But wait! We can say that more simply. That's just

  • [the set of partitions starting with n]
  • [the set of partitions starting with n - 1]
  • [the set of partitions starting with n - 2]
  • ...
  • [the set of partitions starting with 1]

Which is really just all the partitions starting with n - i for all i between 1 and n. So, if we can find a way to get each group of partitions for each i, we can simplify things.

How might we do that? Well, if we think about it, we can realize that we can get every partition which starts with n - i pretty easily. Each partition is just n - i followed by a way to get numbers which add up to i... which is exactly what a partition is, so we've found our recursive case! We get all of our partitions by getting n - i followed by each of the partitions of i.

Now we just need a base case. That's pretty simple: we can just define the partitions for zero to be the empty set.

Putting It All Together

So what does this look like?

vector<vector<int>> getPartitions(int number, int maxElement)
{
    if (number < 1) return vector<vector<int>>();
    vector<vector<int>> partitions;

    if (number <= maxElement) partitions.push_back({number});

    for (int i = number - maxElement; i < number; ++i)
    {
        // (recursively) get the partitions of `i`, with elements no larger than `n - i`
        auto partitionsForI = getPartitions(i, number - i);

        // add `n - i` to the front of all of those partitions
        for(vector<int>& partition : partitionsForI)
        {
            partition.insert(partition.begin(), number - i);
        }

        // add these new partitions to our list.
        partitions.insert(partitions.end(), partitionsForI.begin(), partitionsForI.end());
    }
    return partitions;
}

Stirling Numbers

These are pretty similar. If you look at their respective Wikipedia pages, you can find recurrence relations for each kind:

First Kind

s1(n, k) = -(n - 1) * s1(n - 1, k) + s1(n - 1, k - 1)

Second Kind

S2(n, k) = k * S2(n - 1, k) + S2(n - 1, k - 1)

And they have the same base cases: S(0, 0) = 1, S(n, 0) = 0 and S(0, n) = 0.

So you could define a function to calculate them something like this:

int firstKindStirling(int n, int k) 
{
    if (n == 0 && k == 0) return 1;
    else if (n == 0 || k == 0) return 0;
    else return -(n-1) * firstKindStirling(n-1, k) + firstKindStirling(n-1, k-1);
}

and the one for the second kind would look very similar to that.

Chebyshev Polynomials

It's not totally clear what the requirement is here. I'm going to assume it's to evaluate one at a point, not to come up with some expanded representation. It goes pretty much the same as the Stirling Numbers.

Again, the wikipedia page has a recurrence relation:

chebyshev(0, x) = 1
chebyshev(1, x) = x
chebyshev(n, x) = 2 * x * chebyshev(n-1, x)  -  chebyshev(n-2, x)

I assume you can figure out how to make that into a function. (Hint: basically all it takes is turning those left-hand sides into if statements, similar to the example above.)

ahruss
  • 2,070
  • 16
  • 21
  • Thank you so much this really helped. Visual Studio is giving me an error with this line though: if (number <= maxElement) partitions.push_back({number});//issue is with the curly bracket before number. I think I need to change that to just (number); correct me if I'm mistaken. – Nisha Sharaschandra Aug 01 '14 at 15:28
  • Your compiler might not support initializer syntax. You'll need to construct the vector manually if that's the case. – ahruss Aug 01 '14 at 15:33
  • From what I'm reading in my book, it should have worked with push_back(number) since that's the value I'm trying to add to the end of the vector and number has already been declared. I'm not quite understanding what's wrong with it... – Nisha Sharaschandra Aug 01 '14 at 16:04
  • It's a vector>. You can't add an int to a vector> directly. The braces around it are a shortcut for a vector which contains the elements inside those braces. – ahruss Aug 01 '14 at 16:06
  • I think my computer hates me. I added the code, for some reason I'm just not able to figure this out. – Nisha Sharaschandra Aug 01 '14 at 17:35