tags:

views:

1175

answers:

5

I am creating a forecasting application that will run simulations for various "modes" that a production plant is able to run. The plant can run in one mode per day, so I am writing a function that will add up the different modes chosen each day that best maximize the plant’s output and best aligns with the sales forecast numbers provided. This data will be loaded into an array of mode objects that will then be used to calculate the forecast output of the plant.

I have created the functions to do this, however, I need to make them recursive so that I am able to handle any number (within reason) of modes and work days (which varies based on production needs). Listed below is my code using for loops to simulate what I want to do. Can someone point me in the right direction in order to create a recursive function to replace the need for multiple for loops?

Where the method GetNumbers4 would be when there were four modes, and GetNumbers5 would be 5 modes. Int start would be the number of work days.

  private static void GetNumber4(int start)
    {
        int count = 0;
        int count1 = 0;          

        for (int i = 0; 0 <= start; i++)
        {
            for (int j = 0; j <= i; j++)
            {

                for (int k = 0; k <= j; k++)
                {
                    count++;

                     for (int l = 0; l <= i; l++)
                     {
                         count1 = l;
                     }

                     Console.WriteLine(start + " " + (count1 - j) + " " + (j - k) + " " + k);
                     count1 = 0;
                }  

            }
            start--;

        }
        Console.WriteLine(count);

    }

    private static void GetNumber5(int start)
    {
        int count = 0;
        int count1 = 0;

        for (int i = 0; 0 <= start; i++)
        {
            for (int j = 0; j <= i; j++)
            {

                for (int k = 0; k <= j; k++)
                {

                    for (int l = 0; l <= k; l++)
                    {
                        count++;
                        for (int m = 0; m <= i; m++)
                        {
                            count1 = m;
                        }
                        Console.WriteLine(start + " " + (count1 - j) + " " + (j - k) + " " + (k - l) + " " + l);
                        count1 = 0;
                    }

                }

            }
            start--;

        }
        Console.WriteLine(count);

    }

EDITED:

I think that it would be more helpful if I gave an example of what I was trying to do. For example, if a plant could run in three modes "A", "B", "C" and there were three work days, then the code will return the following results.

3  0  0
2  1  0
2  0  0
1  2  0
1  1  1
1  0  2
0  3  0
0  2  1
0  1  2
0  0  3

The series of numbers represent the three modes A B C. I will load these results into a Modes object that has the corresponding production rates. Doing it this way allows me to shortcut creating a list of every possible combination; it instead gives me a frequency of occurrence.

Building on one of the solutions already offered, I would like to do something like this.

    //Where Modes is a custom classs
    private static Modes GetNumberRecur(int start, int numberOfModes)
    {
        if (start < 0)
        {
            return Modes;

        }

        //Do work here
        GetNumberRecur(start - 1);
    }

Thanks to everyone who have already provided input.

A: 

I previously offered a simple C# recursive function here. The top-most function ends up having a copy of every permutation, so it should be easily adapted for your needs..

Brian
+3  A: 

A recursive function just needs a terminating condition. In your case, that seems to be when start is less than 0:

private static void GetNumberRec(int start)
{
  if(start < 0)
    return;

  // Do stuff

  // Recurse
  GetNumberRec(start-1);
}
dahlbyk
+1  A: 

I've refactored your example into this:

private static void GetNumber5(int start)
{
    var count = 0;

    for (var i = 0; i <= start; i++)
    {
        for (var j = 0; j <= i; j++)
        {
            for (var k = 0; k <= j; k++)
            {
                for (var l = 0; l <= k; l++)
                {
                    count++;

                    Console.WriteLine(
                       (start - i) + " " +
                       (i - j) + " " +
                       (j - k) + " " +
                       (k - l) + " " +
                       l);
                }
            }
        }
    }

    Console.WriteLine(count);
}

Please verify this is correct.

A recursive version should then look like this:

public static void GetNumber(int start, int depth)
{
    var count = GetNumber(start, depth, new Stack<int>());
    Console.WriteLine(count);
}

private static int GetNumber(int start, int depth, Stack<int> counters)
{
    if (depth == 0)
    {
        Console.WriteLine(FormatCounters(counters));
        return 1;
    }
    else
    {
        var count = 0;
        for (int i = 0; i <= start; i++)
        {
            counters.Push(i);
            count += GetNumber(i, depth - 1, counters);
            counters.Pop();
        }
        return count;
    }
}

FormatCounters is left as an exercise to the reader ;)

dtb
+3  A: 

Calling GetNumber(5, x) should yield the same result as GetNumber5(x):

static void GetNumber(int num, int max) {
    Console.WriteLine(GetNumber(num, max, ""));
}
static int GetNumber(int num, int max, string prefix) {
    if (num < 2) {
        Console.WriteLine(prefix + max);
        return 1;
    }
    else {
        int count = 0;
        for (int i = max; i >= 0; i--)
            count += GetNumber(num - 1, max - i, prefix + i + " ");
        return count;
    }
}
Jimmy
You absolutely nailed it. Thanks a lot.
Irwin M. Fletcher
To be honest, a better solution would might involve GetNumber yielding an an iterator of int[] or something, so your other components could pick up the values directly.
Jimmy
A: 

I realize that everyone's beaten me to the punch at this point, but here's a dumb Java algorithm (pretty close to C# syntactically that you can try out).

import java.util.ArrayList;
import java.util.List;

/**
 * The operational complexity of this is pretty poor and I'm sure you'll be able to optimize
 * it, but here's something to get you started at least.
 */
public class Recurse
{   
    /**
     * Base method to set up your recursion and get it started
     * 
     * @param start The total number that digits from all the days will sum up to
     * @param days The number of days to split the "start" value across (e.g. 5 days equals
     * 5 columns of output)
     */
    private static void getNumber(int start,int days)
    {
     //start recursing
     printOrderings(start,days,new ArrayList<Integer>(start));
    }

    /**
     * So this is a pretty dumb recursion.  I stole code from a string permutation algorithm that I wrote awhile back. So the
     * basic idea to begin with was if you had the string "abc", you wanted to print out all the possible permutations of doing that
     * ("abc","acb","bac","bca","cab","cba"). So you could view your problem in a similar fashion...if "start" is equal to "5" and
     * days is equal to "4" then that means you're looking for all the possible permutations of (0,1,2,3,4,5) that fit into 4 columns. You have
     * the extra restriction that when you find a permutation that works, the digits in the permutation must add up to "start" (so for instance
     * [0,0,3,2] is cool, but [0,1,3,3] is not).  You can begin to see why this is a dumb algorithm because it currently just considers all
     * available permutations and keeps the ones that add up to "start". If you want to optimize it more, you could keep a running "sum" of
     * the current contents of the list and either break your loop when it's greater than "start".
     * 
     * Essentially the way you get all the permutations is to have the recursion choose a new digit at each level until you have a full
     * string (or a value for each "day" in your case).  It's just like nesting for loops, but the for loop actually only gets written
     * once because the nesting is done by each subsequent call to the recursive function.
     * 
     * @param start The total number that digits from all the days will sum up to
     * @param days The number of days to split the "start" value across (e.g. 5 days equals
     * 5 columns of output)
     * @param chosen The current permutation at any point in time, may contain between 0 and "days" numbers.
     */
    private static void printOrderings(int start,int days,List<Integer> chosen)
    {
     if(chosen.size() == days)
     {
      int sum = 0;
      for(Integer i : chosen)
      {
       sum += i.intValue();
      }

      if(sum == start)
      {
       System.out.println(chosen.toString());
      }
      return;
     }
     else if(chosen.size() < days)
     {
      for(int i=0; i < start; i++)
      {
       if(chosen.size() >= days)
       {
        break;
       }

       List<Integer> newChosen = new ArrayList<Integer>(chosen);
       newChosen.add(i);
       printOrderings(start,days,newChosen);
      }
     }
    }

    public static void main(final String[] args)
    {
     //your equivalent of GetNumber4(5)
     getNumber(5,4);

     //your equivalent of GetNumber5(5)
     getNumber(5,5);
    }
}
Brent Nash