0

Yo,

Im running into a small issue. I have a selection of "Players" I am trying to run some probability predictions on. There is 112 players. Of these players the following is true:

  • 64 can bat.
  • 66 can bowl.
  • 10 can be wicket keepers
  • Any player can be able to do up too any two of bowl/bat/wicket keep but at least one.

A Team is made up of:

  • 7 players that can bat.
  • 7 players that can bowl.
  • 2 players that can wicket keepers.
  • There cannot be duplicate players in a team.
  • A player may only fulfill one role even if they are capable of two.( a batter / bowler must bat or bowl not both)

Now to the problem

I Have the following code.

var allBattingCombos = new Combinations<int>(players.Where(player => player.inRoundCanBat).Select(player => player.fantasyID).ToList(), 7);
var allBowlingCombos = new Combinations<int>(players.Where(player => player.inRoundCanBowl).Select(player => player.fantasyID).ToList(), 7);
var allWKTCombos = new Combinations<int>(players.Where(player => player.inRoundCanWkt).Select(player => player.fantasyID).ToList(), 2);

var allCombos = new List<Combinations<int>>() { allBowlingCombos , allBowlingCombos, allWKTCombos };
var allTeamCombos = allCombos.CartesianProduct().ToList();

Where CartesianProduct(from Finding all combinations from sets of possibilities) =

public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
{
    // Default object
    IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };

    return sequences.Aggregate(
        emptyProduct,
        (accumulator, sequence) =>
        from accseq in accumulator
        from item in sequence
        select accseq.Concat(new[] { item }));
}

I get the following values:

allBattingCombos count = 621216192
allBowlingCombos count = 778789440
allWKTCombos count = 45

All team combos locks my pc and eventually it dies as I run out of memory. While I was waiting for my calculation to run I did some maths. According to Memory size of a list of int 4 bytes min per int in the list so thats:

4 bytes * 
15 member ids in a team * 
621216192 batting combos * 
778789440 bowling combos *
45 wkt combos

= 1.34E+21 bytes

or 13400000000000 gigaBytes

Yikes, ain't nobody got ram like dat.

What makes it more scary is I need to run it 9 times, 1 for each round.

Once I have my team possibilities I need to run something like this on each team.

Team highestScoringTeam = null;

foreach (var team in allTeamCombos)
{
    var teamobj = new Team();
    teamobj.BattersList = team[0].ToList();
    teamobj.BowlersList = team[1].ToList();
    teamobj.WktKeepersList = team[2].ToList();
    if (highestScoringTeam == null)
    {
        highestScoringTeam = teamobj;
    }
    else if (teamobj.TeamIsValid && teamobj.TotalScoreForRound > highestScoringTeam.TotalScoreForRound)
    {
        highestScoringTeam = teamobj;
    }
}

Does anyone know how I can get around my ram issue / see a better way of achieving my goals?

----Update 1----

After some thinking I don't need the whole list object at any point I can just use it during the Cartesian calculation. In place of allTeamCombos I use the following.

foreach (var battingCombo in allBattingCombos)
{
    foreach (var bowlingCombo in allBowlingCombos)
    {
        foreach (var WktCombo in allWKTCombos)
        {
            var team = new Team();

            team.BattersList = battingCombo.Select(id => players.First(p => p.fantasyID == id)).ToList();
            team.BowlersList = bowlingCombo.Select(id => players.First(p => p.fantasyID == id)).ToList();
            team.WktKeepersList = WktCombo.Select(id => players.First(p => p.fantasyID == id)).ToList();
            if (highestScoringTeam == null)
            {
                highestScoringTeam = team;
            }
            else if (team.TeamIsValid && team.TotalScoreForRound > highestScoringTeam.TotalScoreForRound)
            {
                highestScoringTeam = team;
                Console.WriteLine("new highScore = " + team.TotalScoreForRound);
            }

            combinationsParsed++;
            if(combinationsParsed % 10000 == 0)
                Console.WriteLine("combinationsParsed = " + combinationsParsed);
        }
    }

I'm thinking that this solves the question of the ram issue, I'm also thinking I should maybe close the question.

Community
  • 1
  • 1
Spaceman
  • 1,319
  • 13
  • 42
  • Writing that all out has helped a lot. It has got me thinking about if i need to store the list of ids at all. Hmm more thinking is required i think. – Spaceman Dec 16 '15 at 01:53
  • Why the down vote ? :S – Spaceman Dec 16 '15 at 01:55
  • There's no solution to your requirements: `2 can be wicket keepers` and `7 players that can wicket keepers.` - you're 5 wicket keepers short :) – Rob Dec 16 '15 at 02:35
  • Also, this might be a good question for a mathematics based SE site. The *main* problem is that perhaps you don't need to calculate those combinations. If players are identical (they have the same abilities), you can exclude them from the combination set, and simply add a weight to the unique players. I think you'll first need to figure out *logically* how to solve the problem, and then implement code. There are ways to reduce the amount of memory usage, but you'll get stuck on the fact that you'll need to run `621216192` combinations *just for the batters*. – Rob Dec 16 '15 at 02:40
  • @rob Your total correct, my bad i have fixed the question. In relation to the set uniqueness I think the only way programmatically to check for unique players between role combinations is at point of the Cartesian product calculation not before. I think I may have solve my memory issue tho and the point may be moot ill update my question with details. – Spaceman Dec 16 '15 at 02:43
  • At a glance, it appears there are only `6` types of players. `Batter`, `Bowler`, `WK`, `Batter/Bowler`, `Batter/WK` and `Bowler/WK`. So, the fact that there are `112` players doesn't matter in terms of creating combinations. You simply need these `6` combinations and give them a weight of their count (ie, if there are 20 'only batters', you'd add a weight of '20' to the 'Batter' type of player). – Rob Dec 16 '15 at 02:46
  • Identifying 'unique' types of players means you'll only need to check `16,777,216` combinations (assuming 16 players per team), rather than the original ~~`21,770,847,462,897,561,600`. Less, when you take into consideration the requirements of the team (since the `16,777,216` allows a team of `16` only-batters) – Rob Dec 16 '15 at 02:50
  • You may be onto something here doing combinations of 16 out of 112 and then checking if they are legal. Rather then 7 out of 64 + 7 out of 66 + 2 out of 10. – Spaceman Dec 16 '15 at 02:52

0 Answers0