Use parallelism to solve recursive function with Java

I am trying to optimize a process that has to calculate all possible combinations of players to form partitions. To understand my problem, I am using the following example. For example, we have a set of players N = {1,2,3,4,5}

, these players are regrouped as follows {1,2},{3,4},{5}

. This means that palyer 1 will play with player 2 as one player, and thus one. Each group of players has a set of strategies or options. Each player chooses a group to which he wants to belong, for example: the group {1,2}

has such opportunities {{1,2};{1,2,3,4}}

; that is, players {1,2}, or they decided to stay together or join group {3,4}. the same explanation for the rest of the players:

{3,4}=>{{3,4};{3,4,5};{1,2,3,4}}
{5}=>{{5};{3,4,5}}

      

Now a group of players choosing the same strategy will form a new group (coalition). For example, the group has {1,2}

chosen a strategy {1,2,3,4}

, i.e. players {1,2} want to create a new group with players {3,4}. Players {3,4} choose strategy {3,4,5}

, player {5}

chooses strategy{3,4,5}

... The players chose the same strategy, which will be grouped together to form the final players section as follows: {1,2}, {3,4,5}; players 3,4,5 have chosen the same strategy, so they are grouped together, players {1,2} choose a different strategy, so you will be alone. We do the same with all possible combinations of players' strategies to get all possible player partitions that have cardinality = K. In the final I have to choose the optimal player partition. In the previous example: I have to generate only partitions that have cardinality = 2: | {1,2,3,4}, {5} | = 2 | {1,2} {3,4,5} | = 3 these sections are not valid:|{1,2}{3,4}{5}|=3

I have programmed this process as a recursive function to get all the valid player sections. Another problem here: my function generates all possible sections and I only get valid values ​​that take many times!

Now my question is, is it possible to use parallilism in java to calculate all valid player sections, especially when we have many players and so many sections. What should I do to speed up a big problem?

 import static java.util.Arrays.asList;
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 public class Test {
 @SafeVarargs
 static <T> Set<T> set(T ... elems) {
  return new HashSet<T>(asList(elems));
 }
 static <T> List<Set<Set<T>>> calcPartitions(List<T> teams, Map<T,    List<Set<T>>> team2Strategies, int k, boolean doParallel) {
if(k == 0) {
  if(teams.isEmpty()) return asList(new HashSet<>());
  else return new ArrayList<>();
} else if(teams.isEmpty()) {
  return new ArrayList<>();
}

Set<T> teamsSet = new HashSet<>(teams);

T team = teams.get(0);
Stream<Set<T>> strategies = 
  (doParallel ? team2Strategies.get(team).parallelStream() : team2Strategies.get(team).stream())
    .filter(strategy ->
      strategy.stream().allMatch(team2 ->
        teamsSet.contains(team2) && team2Strategies.get(team2).contains(strategy)));
  return strategies.flatMap(strategy -> {
    List<T> newTeams = new ArrayList<>(teams);
    newTeams.removeAll(strategy);
    List<Set<Set<T>>> restPartitions = calcPartitions(newTeams, team2Strategies, k - 1, false);
    for(Set<Set<T>> partition: restPartitions) {
      partition.add(strategy);
    }
    return restPartitions.stream();
  })
  .collect(Collectors.toList());
}

public static void main(String[] args) {
List<Set<Integer>> teams = asList(set(0,1,2), set(3,4), set(5),set(6,7,8),set(9,10,11),set(12,13,14));

Map<Set<Integer>, List<Set<Set<Integer>>>> team2Strategies = new HashMap<>();

team2Strategies.put(set(0,1,2), asList(set(set(0,1, 2)),
                                     set(set(0,1, 2), set(3, 4))));
team2Strategies.put(set(3,4), asList(set(set(3, 4), set(5)),
                                     set(set(0,1, 2), set(3, 4))));
team2Strategies.put(set(5), asList(set(set(5)),
                                   set(set(3, 4), set(5)),set(set(5),set(6,7,8)),set(set(5),set(6,7,8),set(9,10,11),set(12,13,14))));


team2Strategies.put(set(6,7,8), asList(set(set(6,7,8)),
        set(set(6, 7,8), set(5)),set(set(5),set(6,7,8),set(9,10,11),set(12,13,14))));

team2Strategies.put(set(9,10,11), asList(set(set(9,10,11)),
        set(set(9, 10,11), set(12,13,14)),set(set(5),set(6,7,8),set(9,10,11),set(12,13,14))));

team2Strategies.put(set(12,13,14), asList(set(set(12,13,14)),
        set(set(12, 13,14), set(9,10,11)),set(set(5),set(6,7,8),set(9,10,11),set(12,13,14))));
List<Set<Set<Set<Integer>>>> partitions = calcPartitions(teams,   team2Strategies, 3, true);

  Comparator<List<Integer>> intListComparator = (a, b) -> {
  int i = 0;
  while(i < a.size() && i < b.size()) {
    if(a.get(i) > b.get(i)) return 1;
    else if(a.get(i) < b.get(i)) return -1;
    i++;
  }
  return a.size() - b.size();
};

//in "partitions" a strategy was a Set<Set<Integer>>
//in "partitionsList" however a strategy is a List<Integer>
List<List<List<Integer>>> partitionsList =
  partitions.stream().map(partition ->
    partition.stream().map(strategy ->
      strategy.stream().flatMap(Set::stream)
                       .sorted()
                       .collect(Collectors.toList()))
    .sorted(intListComparator).collect(Collectors.toList()))
  .collect(Collectors.toList());

System.out.println(partitionsList);

System.out.println(
  partitionsList.stream().map(partition ->
    partition.stream().map(strategy ->
      strategy.stream().map(i -> i.toString()).collect(Collectors.joining(", ", "{", "}")))
    .collect(Collectors.joining()))
  .collect(Collectors.joining("\n")));
 }
}

      

+3


source to share


1 answer


The Stream class in Java 8 can automatically perform operations in parallel if possible. Of course, for this it is important that within the code that can be executed in parallel, all operations must be thread safe. The easiest way to achieve this is to avoid any changes to variables or collections. Here is a solution that uses streams. It also only goes through every possible section once and should be quite effective. I presented each section as a list of strategies. Each strategy is a list of commands. Each team, in turn, is also a list. This means that the list of teams might look like this: the [[1,2], [3,4], [5]]

strategy might look like this: [[3,4], [5]]

(team [3,4]

and team [5]

pair up). And the section might look like this: [[[1,2]], [[3,4], [5]]]

which is{1,2}{3,4,5}

import static java.util.Arrays.asList;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Test {
  static <T> List<List<List<T>>> calcPartitions(List<T> teams, Map<T, List<List<T>>> team2Strategies, int k, boolean doParallel) {
    if(k == 0) {
      if(teams.isEmpty()) return asList(new ArrayList<>());
      else return new ArrayList<>();
    } else if(teams.isEmpty()) {
      return new ArrayList<>();
    }

    T team = teams.get(0);
    Stream<List<T>> strategies = 
      (doParallel ? team2Strategies.get(team).parallelStream() : team2Strategies.get(team).stream())
        .filter(strategy ->
          strategy.stream().allMatch(team2 ->
            teams.contains(team2) && team2Strategies.get(team2).contains(strategy)));
      return strategies.flatMap(strategy -> {
        List<T> newTeams = new ArrayList<>(teams);
        newTeams.removeAll(strategy);
        List<List<List<T>>> restPartitions = calcPartitions(newTeams, team2Strategies, k - 1, false);
        for(List<List<T>> partition: restPartitions) {
          partition.add(0, strategy);
        }
        return restPartitions.stream();
      })
      .collect(Collectors.toList());
  }

  public static void main(String[] args) {
    List<List<Integer>> teams = asList(asList(1,2), asList(3,4), asList(5));

    Map<List<Integer>, List<List<List<Integer>>>> team2Strategies = new HashMap<>();

    team2Strategies.put(asList(1,2), asList(asList(asList(1, 2)),
                                            asList(asList(1, 2), asList(3, 4))));
    team2Strategies.put(asList(3,4), asList(asList(asList(3, 4)),
                                            asList(asList(3, 4), asList(5)),
                                            asList(asList(1, 2), asList(3, 4))));
    team2Strategies.put(asList(5), asList(asList(asList(5)),
                                          asList(asList(3, 4), asList(5))));

    List<List<List<List<Integer>>>> partitions = calcPartitions(teams, team2Strategies, 2, true);

    System.out.println(
      partitions.stream().map(partition ->
        partition.stream().map(strategy ->
          strategy.stream().map(team ->
            team.stream().map(i -> i.toString()).collect(Collectors.joining(", ")))
          .collect(Collectors.joining(", ", "{", "}")))
        .collect(Collectors.joining()))
      .collect(Collectors.joining("\n")));
  }
}

      

Output of this program

{1, 2}{3, 4, 5}
{1, 2, 3, 4}{5}

      



change

I have to represent each team individually for this strategy to work. But you can improve it by using sets instead of lists. Thus, it [[3,4],[5]]

will be equal [[5],[3,4]]

. The kits should also speed up the execution of the entire program. Once the solutions are found, you can then convert them to a nicer form, i.e. convert [[3,4],[5]]

to [3,4,5]

, and also sort the numbers while you are at it.

import static java.util.Arrays.asList;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Test {
  @SafeVarargs
  static <T> Set<T> set(T ... elems) {
    return new HashSet<T>(asList(elems));
  }

  static <T> List<Set<Set<T>>> calcPartitions(List<T> teams, Map<T, List<Set<T>>> team2Strategies, int k, boolean doParallel) {
    if(k == 0) {
      if(teams.isEmpty()) return asList(new HashSet<>());
      else return new ArrayList<>();
    } else if(teams.isEmpty()) {
      return new ArrayList<>();
    }

    Set<T> teamsSet = new HashSet<>(teams);

    T team = teams.get(0);
    Stream<Set<T>> strategies = 
      (doParallel ? team2Strategies.get(team).parallelStream() : team2Strategies.get(team).stream())
        .filter(strategy ->
          strategy.stream().allMatch(team2 ->
            teamsSet.contains(team2) && team2Strategies.get(team2).contains(strategy)));
      return strategies.flatMap(strategy -> {
        List<T> newTeams = new ArrayList<>(teams);
        newTeams.removeAll(strategy);
        List<Set<Set<T>>> restPartitions = calcPartitions(newTeams, team2Strategies, k - 1, false);
        for(Set<Set<T>> partition: restPartitions) {
          partition.add(strategy);
        }
        return restPartitions.stream();
      })
      .collect(Collectors.toList());
  }

  static List<Set<Integer>> teams = new ArrayList<>();
  static Map<Set<Integer>, List<Set<Set<Integer>>>> team2Strategies = new HashMap<>();

  private static Set<Integer> toSet(String string) {
    return Stream.of(string.split(" ")).map(s -> Integer.valueOf(s.trim())).collect(Collectors.toSet());
  }

  @SafeVarargs
  private static void defineTeams(List<String> ... definitions) {
    for(List<String> def: definitions) {
      teams.add(toSet(def.get(0)));
    }

    for(List<String> def: definitions) {
      Set<Integer> team = toSet(def.get(0));
      Stream<Set<Integer>> strategies = def.stream().skip(1).map(s -> toSet(s));
      List<Set<Set<Integer>>> startegiesList =
        strategies.map(strat -> teams.stream().filter(strat::containsAll).collect(Collectors.toSet()))
                  .collect(Collectors.toList());
      team2Strategies.put(team, startegiesList);
    }
  }

  public static void main(String[] args) {
    defineTeams(asList("0 1 2", "0 1 2", "0 1 2 3 4"),
                asList("3 4", "3 4 5", "0 1 2 3 4"),
                asList("5", "5", "3 4 5", "5 6 7 8", "5 6 7 8 9 10 11 12 13 14"),
                asList("6 7 8", "6 7 8", "5 6 7 8", "5 6 7 8 9 10 11 12 13 14"),             
                asList("9 10 11", "9 10 11", "9 10 11 12 13 14", "5 6 7 8 9 10 11 12 13 14"),
                asList("12 13 14", "12 13 14", "9 10 11 12 13 14", "5 6 7 8 9 10 11 12 13 14"));

    System.out.println("teams = "+ teams);
    System.out.println("team trategies = " + team2Strategies);
    System.out.println();

    List<Set<Set<Set<Integer>>>> partitions = calcPartitions(teams, team2Strategies, 3, true);

    Comparator<List<Integer>> intListComparator = (a, b) -> {
      int i = 0;
      while(i < a.size() && i < b.size()) {
        if(a.get(i) > b.get(i)) return 1;
        else if(a.get(i) < b.get(i)) return -1;
        i++;
      }
      return a.size() - b.size();
    };

    System.out.println(partitions);

    //in "partitions" a strategy was a Set<Set<Integer>>
    //in "partitionsList" however a strategy is a List<Integer>
    List<List<List<Integer>>> partitionsList =
      partitions.stream().map(partition ->
        partition.stream().map(strategy ->
          strategy.stream().flatMap(Set::stream)
                           .sorted()
                           .collect(Collectors.toList()))
        .sorted(intListComparator).collect(Collectors.toList()))
      .collect(Collectors.toList());

    System.out.println(partitionsList);

    System.out.println(
      partitionsList.stream().map(partition ->
        partition.stream().map(strategy ->
          strategy.stream().map(i -> i.toString()).collect(Collectors.joining(", ", "{", "}")))
        .collect(Collectors.joining()))
      .collect(Collectors.joining("\n")));
  }
}

      

0


source







All Articles